human_units/
duration_serde.rs

1use core::fmt::Formatter;
2use core::fmt::Write;
3
4use crate::Buffer;
5use crate::Duration;
6
7impl serde::Serialize for Duration {
8    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
9    where
10        S: serde::Serializer,
11    {
12        let mut buf = Buffer::<{ Duration::MAX_STRING_LEN }>::new();
13        let _ = write!(&mut buf, "{self}");
14        s.serialize_str(unsafe { core::str::from_utf8_unchecked(buf.as_slice()) })
15    }
16}
17
18impl<'a> serde::Deserialize<'a> for Duration {
19    fn deserialize<D>(d: D) -> Result<Self, D::Error>
20    where
21        D: serde::Deserializer<'a>,
22    {
23        d.deserialize_str(DurationVisitor)
24    }
25}
26
27struct DurationVisitor;
28
29impl<'a> serde::de::Visitor<'a> for DurationVisitor {
30    type Value = Duration;
31
32    fn expecting(&self, formatter: &mut Formatter) -> core::fmt::Result {
33        write!(formatter, "a string obtained by `Duration::to_string`")
34    }
35
36    fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
37    where
38        E: serde::de::Error,
39    {
40        value.parse().map_err(|_| E::custom("invalid duration"))
41    }
42}
43
44#[cfg(all(test, feature = "std"))]
45mod tests {
46
47    use core::time::Duration as StdDuration;
48
49    use arbtest::arbtest;
50
51    use super::*;
52
53    #[test]
54    fn test_serde_io() {
55        assert_eq!(
56            "\"1m\"",
57            serde_json::to_string(&Duration(StdDuration::from_secs(60))).unwrap()
58        );
59        assert_eq!(
60            Duration(StdDuration::from_secs(60)),
61            serde_json::from_str("\"1m\"").unwrap()
62        );
63        assert_eq!(
64            Duration(StdDuration::from_secs(60)),
65            serde_yaml::from_str("1m").unwrap()
66        );
67        assert_eq!(
68            Duration(StdDuration::from_secs(10)),
69            serde_yaml::from_str("10").unwrap()
70        );
71    }
72
73    #[test]
74    fn test_max_string_len() {
75        let string = format!("{}", Duration(StdDuration::new(u64::MAX, 999_999_999_u32)));
76        assert_eq!(
77            Duration::MAX_STRING_LEN,
78            string.len(),
79            "string = {string:?}"
80        );
81    }
82
83    #[test]
84    fn test_serde_json() {
85        arbtest(|u| {
86            let expected: Duration = u.arbitrary()?;
87            let string = serde_json::to_string(&expected).unwrap();
88            let actual = serde_json::from_str(&string).unwrap();
89            assert_eq!(expected, actual);
90            Ok(())
91        });
92    }
93
94    #[test]
95    fn test_serde_yaml() {
96        arbtest(|u| {
97            let expected: Duration = u.arbitrary()?;
98            let string = serde_yaml::to_string(&expected).unwrap();
99            let actual = serde_yaml::from_str(&string).unwrap();
100            assert_eq!(expected, actual);
101            Ok(())
102        });
103    }
104
105    #[test]
106    fn test_serde_toml() {
107        arbtest(|u| {
108            let expected: DurationWrapper = u.arbitrary()?;
109            let string = toml::to_string(&expected).unwrap();
110            let actual = toml::from_str(&string).unwrap();
111            assert_eq!(expected, actual);
112            Ok(())
113        });
114    }
115
116    #[derive(
117        serde::Serialize, serde::Deserialize, arbitrary::Arbitrary, Debug, PartialEq, Eq, Clone,
118    )]
119    struct DurationWrapper {
120        duration: Duration,
121    }
122}