human_units/
duration_serde.rs1use 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}