1use serde::{Deserialize, Serialize};
4use std::fmt;
5
6#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
13#[serde(transparent)]
14#[non_exhaustive]
15pub struct Id(String);
16
17#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
24#[serde(transparent)]
25#[non_exhaustive]
26pub struct UTCDate(String);
27
28#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
40#[serde(transparent)]
41#[non_exhaustive]
42pub struct Date(String);
43
44#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
51#[serde(transparent)]
52#[non_exhaustive]
53pub struct State(String);
54
55macro_rules! impl_string_newtype {
59 ($T:ident) => {
60 impl fmt::Display for $T {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 f.write_str(&self.0)
63 }
64 }
65 impl From<String> for $T {
66 fn from(s: String) -> Self {
67 Self(s)
68 }
69 }
70 impl From<&str> for $T {
71 fn from(s: &str) -> Self {
72 Self(s.to_owned())
73 }
74 }
75 impl AsRef<str> for $T {
76 fn as_ref(&self) -> &str {
77 &self.0
78 }
79 }
80 impl PartialEq<str> for $T {
81 fn eq(&self, other: &str) -> bool {
82 self.0 == other
83 }
84 }
85 impl PartialEq<&str> for $T {
86 fn eq(&self, other: &&str) -> bool {
87 self.0 == *other
88 }
89 }
90 impl std::borrow::Borrow<str> for $T {
91 fn borrow(&self) -> &str {
92 &self.0
93 }
94 }
95 impl $T {
96 pub fn into_inner(self) -> String {
98 self.0
99 }
100 }
101 };
102}
103
104impl_string_newtype!(Id);
105impl_string_newtype!(UTCDate);
106impl_string_newtype!(Date);
107impl_string_newtype!(State);
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 #[test]
115 fn id_serializes_as_plain_string() {
116 let id = Id("abc123".to_owned());
117 let json = serde_json::to_string(&id).expect("serialize Id");
118 assert_eq!(json, "\"abc123\"");
119 }
120
121 #[test]
123 fn id_deserializes_from_plain_string() {
124 let id: Id = serde_json::from_str("\"abc123\"").expect("deserialize Id");
125 assert_eq!(id.as_ref(), "abc123");
126 }
127
128 #[test]
130 fn utcdate_serializes_as_plain_string() {
131 let d = UTCDate("2014-10-30T06:12:00Z".to_owned());
132 let json = serde_json::to_string(&d).expect("serialize UTCDate");
133 assert_eq!(json, "\"2014-10-30T06:12:00Z\"");
134 }
135
136 #[test]
138 fn state_serializes_as_plain_string() {
139 let s = State("75128aab4b1b".to_owned());
140 let json = serde_json::to_string(&s).expect("serialize State");
141 assert_eq!(json, "\"75128aab4b1b\"");
142 }
143
144 #[test]
146 fn id_from_str() {
147 let id = Id::from("hello");
148 assert_eq!(id.as_ref(), "hello");
149 }
150
151 #[test]
153 fn id_display() {
154 let id = Id("display-test".to_owned());
155 assert_eq!(id.to_string(), "display-test");
156 }
157
158 #[test]
160 fn id_as_ref_str() {
161 let id = Id("ref-test".to_owned());
162 assert_eq!(id.as_ref(), "ref-test");
163 }
164
165 #[test]
167 fn state_round_trip() {
168 let s = State("75128aab4b1b".to_owned());
169 let json = serde_json::to_string(&s).expect("serialize");
170 let s2: State = serde_json::from_str(&json).expect("deserialize");
171 assert_eq!(s, s2);
172 }
173
174 #[test]
176 fn date_accepts_non_utc_offset() {
177 let d = Date("2014-10-30T14:12:00+08:00".to_owned());
178 let json = serde_json::to_string(&d).expect("serialize Date");
179 assert_eq!(json, "\"2014-10-30T14:12:00+08:00\"");
180 let d2: Date = serde_json::from_str(&json).expect("deserialize Date");
181 assert_eq!(d, d2);
182 }
183}