humantime_serde/
lib.rs

1#![doc(html_root_url = "https://docs.rs/humantime-serde/1.0")]
2#![forbid(unsafe_code)]
3
4//! Serde support for the `humantime` crate.
5//!
6//! Based on [this fork](https://github.com/tailhook/serde-humantime/tree/serde_wrapper).
7//!
8//! Currently `std::time::{Duration, SystemTime}` are supported.
9//!
10//! # Example
11//! ```
12//! use serde::{Serialize, Deserialize};
13//! use std::time::{Duration, SystemTime};
14//!
15//! #[derive(Serialize, Deserialize)]
16//! struct Foo {
17//!     #[serde(with = "humantime_serde")]
18//!     timeout: Duration,
19//!     #[serde(default)]
20//!     #[serde(with = "humantime_serde")]
21//!     time: Option<SystemTime>,
22//! }
23//! ```
24//!
25//! Or use the `Serde` wrapper type:
26//!
27//! ```
28//! use serde::{Serialize, Deserialize};
29//! use humantime_serde::Serde;
30//! use std::time::SystemTime;
31//!
32//! #[derive(Serialize, Deserialize)]
33//! struct Foo {
34//!     timeout: Vec<Serde<SystemTime>>,
35//! }
36//! ```
37
38/// Reexport module.
39pub mod re {
40    pub use humantime;
41}
42
43pub mod option;
44
45use std::fmt;
46use std::ops::{Deref, DerefMut};
47use std::time::{Duration, SystemTime};
48
49use humantime;
50use serde::{de, ser, Deserialize, Deserializer, Serialize, Serializer};
51
52/// Deserializes a `Duration` or `SystemTime` via the humantime crate.
53///
54/// This function can be used with `serde_derive`'s `with` and
55/// `deserialize_with` annotations.
56pub fn deserialize<'a, T, D>(d: D) -> Result<T, D::Error>
57where
58    Serde<T>: Deserialize<'a>,
59    D: Deserializer<'a>,
60{
61    Serde::deserialize(d).map(Serde::into_inner)
62}
63
64/// Serializes a `Duration` or `SystemTime` via the humantime crate.
65///
66/// This function can be used with `serde_derive`'s `with` and
67/// `serialize_with` annotations.
68pub fn serialize<T, S>(d: &T, s: S) -> Result<S::Ok, S::Error>
69where
70    for<'a> Serde<&'a T>: Serialize,
71    S: Serializer,
72{
73    Serde::from(d).serialize(s)
74}
75
76/// A wrapper type which implements `Serialize` and `Deserialize` for
77/// types involving `SystemTime` and `Duration`.
78#[derive(Copy, Clone, Eq, Hash, PartialEq)]
79pub struct Serde<T>(T);
80
81impl<T> fmt::Debug for Serde<T>
82where
83    T: fmt::Debug,
84{
85    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
86        self.0.fmt(formatter)
87    }
88}
89
90impl<T> Deref for Serde<T> {
91    type Target = T;
92
93    fn deref(&self) -> &T {
94        &self.0
95    }
96}
97
98impl<T> DerefMut for Serde<T> {
99    fn deref_mut(&mut self) -> &mut T {
100        &mut self.0
101    }
102}
103
104impl<T> Serde<T> {
105    /// Consumes the `De`, returning the inner value.
106    pub fn into_inner(self) -> T {
107        self.0
108    }
109}
110
111impl<T> From<T> for Serde<T> {
112    fn from(val: T) -> Serde<T> {
113        Serde(val)
114    }
115}
116
117impl<'de> Deserialize<'de> for Serde<Duration> {
118    fn deserialize<D>(d: D) -> Result<Serde<Duration>, D::Error>
119    where
120        D: Deserializer<'de>,
121    {
122        struct V;
123
124        impl<'de2> de::Visitor<'de2> for V {
125            type Value = Duration;
126
127            fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
128                fmt.write_str("a duration")
129            }
130
131            fn visit_str<E>(self, v: &str) -> Result<Duration, E>
132            where
133                E: de::Error,
134            {
135                humantime::parse_duration(v).map_err(|_| {
136                    E::invalid_value(de::Unexpected::Str(v), &self)
137                })
138            }
139        }
140
141        d.deserialize_str(V).map(Serde)
142    }
143}
144
145impl<'de> Deserialize<'de> for Serde<SystemTime> {
146    fn deserialize<D>(d: D) -> Result<Serde<SystemTime>, D::Error>
147    where
148        D: Deserializer<'de>,
149    {
150        struct V;
151
152        impl<'de2> de::Visitor<'de2> for V {
153            type Value = SystemTime;
154
155            fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
156                fmt.write_str("a timestamp")
157            }
158
159            fn visit_str<E>(self, v: &str) -> Result<SystemTime, E>
160            where
161                E: de::Error,
162            {
163                humantime::parse_rfc3339_weak(v).map_err(|_| {
164                    E::invalid_value(de::Unexpected::Str(v), &self)
165                })
166            }
167        }
168
169        d.deserialize_str(V).map(Serde)
170    }
171}
172
173impl<'de> Deserialize<'de> for Serde<Option<Duration>> {
174    fn deserialize<D>(d: D) -> Result<Serde<Option<Duration>>, D::Error>
175    where
176        D: Deserializer<'de>,
177    {
178        match Option::<Serde<Duration>>::deserialize(d)? {
179            Some(Serde(dur)) => Ok(Serde(Some(dur))),
180            None => Ok(Serde(None)),
181        }
182    }
183}
184
185impl<'de> Deserialize<'de> for Serde<Option<SystemTime>> {
186    fn deserialize<D>(d: D) -> Result<Serde<Option<SystemTime>>, D::Error>
187    where
188        D: Deserializer<'de>,
189    {
190        match Option::<Serde<SystemTime>>::deserialize(d)? {
191            Some(Serde(dur)) => Ok(Serde(Some(dur))),
192            None => Ok(Serde(None)),
193        }
194    }
195}
196
197impl<'a> ser::Serialize for Serde<&'a Duration> {
198    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
199    where
200        S: ser::Serializer,
201    {
202        humantime::format_duration(*self.0)
203            .to_string()
204            .serialize(serializer)
205    }
206}
207
208impl ser::Serialize for Serde<Duration> {
209    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
210    where
211        S: ser::Serializer,
212    {
213        humantime::format_duration(self.0)
214            .to_string()
215            .serialize(serializer)
216    }
217}
218
219impl<'a> ser::Serialize for Serde<&'a SystemTime> {
220    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
221    where
222        S: ser::Serializer,
223    {
224        humantime::format_rfc3339(*self.0)
225            .to_string()
226            .serialize(serializer)
227    }
228}
229
230impl ser::Serialize for Serde<SystemTime> {
231    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
232    where
233        S: ser::Serializer,
234    {
235        humantime::format_rfc3339(self.0)
236            .to_string()
237            .serialize(serializer)
238    }
239}
240
241impl<'a> ser::Serialize for Serde<&'a Option<Duration>> {
242    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
243    where
244        S: ser::Serializer,
245    {
246        match *self.0 {
247            Some(dur) => serializer.serialize_some(&Serde(dur)),
248            None => serializer.serialize_none(),
249        }
250    }
251}
252
253impl ser::Serialize for Serde<Option<Duration>> {
254    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
255    where
256        S: ser::Serializer,
257    {
258        Serde(&self.0).serialize(serializer)
259    }
260}
261
262impl<'a> ser::Serialize for Serde<&'a Option<SystemTime>> {
263    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
264    where
265        S: ser::Serializer,
266    {
267        match *self.0 {
268            Some(tm) => serializer.serialize_some(&Serde(tm)),
269            None => serializer.serialize_none(),
270        }
271    }
272}
273
274impl ser::Serialize for Serde<Option<SystemTime>> {
275    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
276    where
277        S: ser::Serializer,
278    {
279        Serde(&self.0).serialize(serializer)
280    }
281}
282
283#[cfg(test)]
284mod test {
285    use super::*;
286    use std::time::{SystemTime, UNIX_EPOCH};
287
288    #[test]
289    fn with() {
290        #[derive(Serialize, Deserialize)]
291        struct Foo {
292            #[serde(with = "super")]
293            time: Duration,
294        }
295
296        let json = r#"{"time": "15 seconds"}"#;
297        let foo = serde_json::from_str::<Foo>(json).unwrap();
298        assert_eq!(foo.time, Duration::from_secs(15));
299        let reverse = serde_json::to_string(&foo).unwrap();
300        assert_eq!(reverse, r#"{"time":"15s"}"#);
301    }
302
303    #[test]
304    fn with_option() {
305        #[derive(Serialize, Deserialize)]
306        struct Foo {
307            #[serde(with = "super", default)]
308            time: Option<Duration>,
309        }
310
311        let json = r#"{"time": "15 seconds"}"#;
312        let foo = serde_json::from_str::<Foo>(json).unwrap();
313        assert_eq!(foo.time, Some(Duration::from_secs(15)));
314        let reverse = serde_json::to_string(&foo).unwrap();
315        assert_eq!(reverse, r#"{"time":"15s"}"#);
316
317        let json = r#"{"time": null}"#;
318        let foo = serde_json::from_str::<Foo>(json).unwrap();
319        assert_eq!(foo.time, None);
320        let reverse = serde_json::to_string(&foo).unwrap();
321        assert_eq!(reverse, r#"{"time":null}"#);
322
323        let json = r#"{}"#;
324        let foo = serde_json::from_str::<Foo>(json).unwrap();
325        assert_eq!(foo.time, None);
326    }
327
328    #[test]
329    fn time() {
330        #[derive(Serialize, Deserialize)]
331        struct Foo {
332            #[serde(with = "super")]
333            time: SystemTime,
334        }
335
336        let json = r#"{"time": "2018-05-11 18:28:30"}"#;
337        let foo = serde_json::from_str::<Foo>(json).unwrap();
338        assert_eq!(foo.time, UNIX_EPOCH + Duration::new(1526063310, 0));
339        let reverse = serde_json::to_string(&foo).unwrap();
340        assert_eq!(reverse, r#"{"time":"2018-05-11T18:28:30Z"}"#);
341    }
342
343    #[test]
344    fn time_with_option() {
345        #[derive(Serialize, Deserialize)]
346        struct Foo {
347            #[serde(with = "super", default)]
348            time: Option<SystemTime>,
349        }
350
351        let json = r#"{"time": "2018-05-11 18:28:30"}"#;
352        let foo = serde_json::from_str::<Foo>(json).unwrap();
353        assert_eq!(foo.time, Some(UNIX_EPOCH + Duration::new(1526063310, 0)));
354        let reverse = serde_json::to_string(&foo).unwrap();
355        assert_eq!(reverse, r#"{"time":"2018-05-11T18:28:30Z"}"#);
356
357        let json = r#"{"time": null}"#;
358        let foo = serde_json::from_str::<Foo>(json).unwrap();
359        assert_eq!(foo.time, None);
360        let reverse = serde_json::to_string(&foo).unwrap();
361        assert_eq!(reverse, r#"{"time":null}"#);
362
363        let json = r#"{}"#;
364        let foo = serde_json::from_str::<Foo>(json).unwrap();
365        assert_eq!(foo.time, None);
366    }
367
368    #[test]
369    fn test_readme_deps() {
370        version_sync::assert_markdown_deps_updated!("README.md");
371    }
372
373    #[test]
374    fn test_html_root_url() {
375        version_sync::assert_html_root_url_updated!("src/lib.rs");
376    }
377}