Skip to main content

utc2k/
serde.rs

1/*!
2# (De/)Serialization
3*/
4
5use crate::{
6	FmtUtc2k,
7	Month,
8	Utc2k,
9	Weekday,
10};
11use serde_core::{
12	de,
13	Deserialize,
14	ser,
15	Serialize,
16};
17use std::fmt;
18
19
20
21impl<'de> Deserialize<'de> for FmtUtc2k {
22	/// # Deserialize.
23	///
24	/// Use the optional `serde` crate feature to enable serialization support.
25	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
26	where D: de::Deserializer<'de> {
27		Utc2k::deserialize(deserializer).map(Self::from)
28	}
29}
30
31impl Serialize for FmtUtc2k {
32	#[inline]
33	/// # Serialize.
34	///
35	/// Use the optional `serde` crate feature to enable serialization support.
36	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
37	where S: ser::Serializer { serializer.serialize_str(self.as_str()) }
38}
39
40
41
42impl<'de> Deserialize<'de> for Utc2k {
43	/// # Deserialize.
44	///
45	/// Use the optional `serde` crate feature to enable serialization support.
46	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
47	where D: de::Deserializer<'de> {
48		/// # Visitor Instance.
49		struct Visitor;
50
51		/// # Helper: Errors for Unsupported Formats.
52		macro_rules! invalid {
53			($fn:ident, $ty:ty) => (
54				fn $fn<S>(self, _src: $ty) -> Result<Self::Value, S>
55				where S: de::Error {
56					Err(de::Error::custom(concat!(stringify!($ty), " is unsupported")))
57				}
58			);
59		}
60
61		impl de::Visitor<'_> for Visitor {
62			type Value = Utc2k;
63
64			fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
65				f.write_str("a timestamp or datetime string")
66			}
67
68			fn visit_str<S>(self, src: &str) -> Result<Self::Value, S>
69			where S: de::Error {
70				Utc2k::try_from(src).map_err(|_| de::Error::custom("invalid datetime string"))
71			}
72
73			fn visit_bytes<S>(self, src: &[u8]) -> Result<Self::Value, S>
74			where S: de::Error {
75				Utc2k::try_from(src).map_err(|_| de::Error::custom("invalid datetime string"))
76			}
77
78			fn visit_i32<S>(self, src: i32) -> Result<Self::Value, S>
79			where S: de::Error {
80				// Fail on negative, otherwise parse as usual.
81				u32::try_from(src)
82					.map(Utc2k::from)
83					.map_err(|_| de::Error::custom("invalid unix timestamp"))
84			}
85
86			fn visit_i64<S>(self, src: i64) -> Result<Self::Value, S>
87			where S: de::Error {
88				// Fail on negative, otherwise parse as usual.
89				u32::try_from(src)
90					.map(Utc2k::from)
91					.map_err(|_| de::Error::custom("invalid unix timestamp"))
92			}
93
94			fn visit_u32<S>(self, src: u32) -> Result<Self::Value, S>
95			where S: de::Error { Ok(Utc2k::from(src)) }
96
97			fn visit_u64<S>(self, src: u64) -> Result<Self::Value, S>
98			where S: de::Error {
99				// Return the max value on failure because it's too big,
100				// otherwise parse as normal.
101				Ok(u32::try_from(src).map_or_else(|_| Utc2k::MAX, Utc2k::from))
102			}
103
104			// Too small to hold an in-range value.
105			invalid!(visit_char, char);
106			invalid!(visit_i8, i8);
107			invalid!(visit_i16, i16);
108			invalid!(visit_u8, u8);
109			invalid!(visit_u16, u16);
110		}
111
112		deserializer.deserialize_any(Visitor)
113	}
114}
115
116impl Serialize for Utc2k {
117	#[inline]
118	/// # Serialize.
119	///
120	/// Use the optional `serde` crate feature to enable serialization support.
121	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
122	where S: ser::Serializer { serializer.serialize_u32(self.unixtime()) }
123}
124
125
126
127impl<'de> Deserialize<'de> for Month {
128	#[inline]
129	/// # Deserialize.
130	///
131	/// Use the optional `serde` crate feature to enable serialization support.
132	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
133	where D: de::Deserializer<'de> {
134		/// # Visitor Instance.
135		struct Visitor;
136
137		impl de::Visitor<'_> for Visitor {
138			type Value = Month;
139
140			fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
141				f.write_str("a string representation like 'jan' or 'January'")
142			}
143
144			#[inline]
145			fn visit_str<S>(self, src: &str) -> Result<Self::Value, S>
146			where S: de::Error {
147				Month::try_from(src).map_err(|_| de::Error::custom("invalid month string"))
148			}
149
150			#[inline]
151			fn visit_bytes<S>(self, src: &[u8]) -> Result<Self::Value, S>
152			where S: serde_core::de::Error {
153				Month::try_from(src).map_err(|_| de::Error::custom("invalid month string"))
154			}
155		}
156
157		deserializer.deserialize_str(Visitor)
158	}
159}
160
161impl Serialize for Month {
162	#[inline]
163	/// # Serialize.
164	///
165	/// Use the optional `serde` crate feature to enable serialization support.
166	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
167	where S: ser::Serializer { serializer.serialize_str(self.as_str()) }
168}
169
170
171
172impl<'de> Deserialize<'de> for Weekday {
173	#[inline]
174	/// # Deserialize.
175	///
176	/// Use the optional `serde` crate feature to enable serialization support.
177	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
178	where D: de::Deserializer<'de> {
179		/// # Visitor Instance.
180		struct Visitor;
181
182		impl de::Visitor<'_> for Visitor {
183			type Value = Weekday;
184
185			fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
186				f.write_str("a string representation like 'mon' or 'Monday'")
187			}
188
189			#[inline]
190			fn visit_str<S>(self, src: &str) -> Result<Self::Value, S>
191			where S: de::Error {
192				Weekday::try_from(src).map_err(|_| de::Error::custom("invalid weekday string"))
193			}
194
195			#[inline]
196			fn visit_bytes<S>(self, src: &[u8]) -> Result<Self::Value, S>
197			where S: serde_core::de::Error {
198				Weekday::try_from(src).map_err(|_| de::Error::custom("invalid weekday string"))
199			}
200		}
201
202		deserializer.deserialize_str(Visitor)
203	}
204}
205
206impl Serialize for Weekday {
207	#[inline]
208	/// # Serialize.
209	///
210	/// Use the optional `serde` crate feature to enable serialization support.
211	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
212	where S: ser::Serializer { serializer.serialize_str(self.as_str()) }
213}
214
215
216
217#[cfg(test)]
218mod tests {
219	use super::*;
220
221	#[cfg(not(miri))]
222	const SAMPLE_SIZE: usize = 1_000_000;
223
224	#[cfg(miri)]
225	const SAMPLE_SIZE: usize = 1000; // Miri runs way too slow for a million tests.
226
227	#[test]
228	/// # Test Serialization.
229	fn t_serde() {
230		const DATESTR: &str = "2021-07-08 11:33:16";
231		const DATENUM: &str = "1625743996";
232		const DATESTR_Q: &str = "\"2021-07-08 11:33:16\"";
233
234		{
235			// Formatted Version.
236			let date = FmtUtc2k::try_from(DATESTR).unwrap();
237			let serial = serde_json::to_string(&date)
238				.expect("FmtUtc2k serialization failed.");
239			assert_eq!(serial, DATESTR_Q);
240
241			let mut date2: FmtUtc2k = serde_json::from_str(&serial)
242				.expect("FmtUtc2k deserialization (str) failed.");
243			assert_eq!(date, date2);
244
245			// We should also be able to deserialize from a timestamp.
246			date2 = serde_json::from_str(DATENUM)
247				.expect("FmtUtc2k deserialization (u32) failed.");
248			assert_eq!(date, date2);
249		}
250
251		{
252			// Utc2k Version.
253			let date = Utc2k::try_from(DATESTR).unwrap();
254			let serial = serde_json::to_string(&date)
255				.expect("Utc2k serialization failed.");
256			assert_eq!(serial, DATENUM);
257
258			let mut date2: Utc2k = serde_json::from_str(&serial)
259				.expect("Utc2k deserialization (u32) failed.");
260			assert_eq!(date, date2);
261
262			// We should also be able to deserialize from a datetime string.
263			date2 = serde_json::from_str(DATESTR_Q)
264				.expect("Utc2k deserialization (str) failed.");
265			assert_eq!(date, date2);
266		}
267	}
268
269	#[test]
270	fn t_serde_fmtutc2k_rng() {
271		let mut rng = fastrand::Rng::new();
272		for i in std::iter::repeat_with(|| rng.u32(Utc2k::MIN_UNIXTIME..=Utc2k::MAX_UNIXTIME)).take(SAMPLE_SIZE) {
273			let date = FmtUtc2k::from(i);
274
275			// Serialization should give us the date string with an extra pair
276			// of quotes.
277			let s = serde_json::to_string(&date).expect("Serialization failed.");
278			assert_eq!(format!("{:?}", date.as_str()), s);
279
280			// Deserialization should give us a copy of the original.
281			let d = serde_json::from_str::<FmtUtc2k>(&s).expect("Deserialization failed.");
282			assert_eq!(date, d);
283		}
284	}
285
286	#[test]
287	fn t_serde_utc2k_rng() {
288		let mut rng = fastrand::Rng::new();
289		for i in std::iter::repeat_with(|| rng.u32(Utc2k::MIN_UNIXTIME..=Utc2k::MAX_UNIXTIME)).take(SAMPLE_SIZE) {
290			let date = Utc2k::from(i);
291
292			// Serialization should give us the unixtime as a string.
293			let s = serde_json::to_string(&date).expect("Serialization failed.");
294			assert_eq!(s, i.to_string());
295
296			// Deserialization should give us a copy of the original.
297			let d = serde_json::from_str::<Utc2k>(&s).expect("Deserialization failed.");
298			assert_eq!(date, d);
299		}
300	}
301
302	#[test]
303	fn t_serde_month() {
304		for month in Month::ALL {
305			let s = serde_json::to_string(&month).expect("Serialization failed.");
306			assert_eq!(s, format!("\"{}\"", month.as_str()));
307
308			let d = serde_json::from_str::<Month>(&s).expect("Deserialization failed.");
309			assert_eq!(d, month);
310
311			// From abbreviation.
312			let d = serde_json::from_str::<Month>(&format!("\"{}\"", month.abbreviation()))
313				.expect("Deserialization (abbr) failed.");
314			assert_eq!(d, month);
315		}
316	}
317
318	#[test]
319	fn t_serde_weekday() {
320		for day in Weekday::ALL {
321			let s = serde_json::to_string(&day).expect("Serialization failed.");
322			assert_eq!(s, format!("\"{}\"", day.as_str()));
323
324			let d = serde_json::from_str::<Weekday>(&s).expect("Deserialization failed.");
325			assert_eq!(d, day);
326
327			// From abbreviation.
328			let d = serde_json::from_str::<Weekday>(&format!("\"{}\"", day.abbreviation()))
329				.expect("Deserialization (abbr) failed.");
330			assert_eq!(d, day);
331		}
332	}
333}