serde_humantime/
lib.rs

1//! A crate providing Serde deserializers for `Duration`s via the `humantime`
2//! crate.
3//!
4//! # Examples
5//!
6//! You can use the `deserialize` function with the `with` or `deserialize_with`
7//! annotations:
8//!
9//! ```
10//! extern crate serde_humantime;
11//! extern crate serde;
12//! #[macro_use]
13//! extern crate serde_derive;
14//!
15//! use std::time::Duration;
16//!
17//! #[derive(Deserialize)]
18//! struct Foo {
19//!     #[serde(with = "serde_humantime")]
20//!     timeout: Duration,
21//! }
22//!
23//! # fn main() {}
24//! ```
25//!
26//! Or use the `De` wrapper type:
27//!
28//! ```
29//! extern crate serde_humantime;
30//! extern crate serde;
31//! #[macro_use]
32//! extern crate serde_derive;
33//!
34//! use serde_humantime::De;
35//! use std::time::Duration;
36//!
37//! #[derive(Deserialize)]
38//! struct Foo {
39//!     timeout: De<Option<Duration>>,
40//! }
41//!
42//! # fn main() {}
43//! ```
44#![warn(missing_docs)]
45#![doc(html_root_url="https://docs.rs/serde-humantime/0.1.1")]
46
47extern crate humantime;
48extern crate serde;
49
50#[cfg(test)]
51#[macro_use]
52extern crate serde_derive;
53#[cfg(test)]
54extern crate serde_json;
55
56use serde::de::{Deserialize, Deserializer, Visitor, Error, Unexpected};
57use std::fmt;
58use std::time::Duration;
59
60/// A wrapper type which implements `Deserialize` for types involving
61/// `Duration`.
62///
63/// It can only be constructed through its `Deserialize` implementations.
64pub struct De<T>(T);
65
66impl<T> De<T> {
67    /// Consumes the `De`, returning the inner value.
68    pub fn into_inner(self) -> T {
69        self.0
70    }
71}
72
73impl<'de> Deserialize<'de> for De<Duration> {
74    fn deserialize<D>(d: D) -> Result<De<Duration>, D::Error>
75        where D: Deserializer<'de>
76    {
77        deserialize(d).map(De)
78    }
79}
80
81impl<'de> Deserialize<'de> for De<Option<Duration>> {
82    fn deserialize<D>(d: D) -> Result<De<Option<Duration>>, D::Error>
83        where D: Deserializer<'de>
84    {
85        match Option::<De<Duration>>::deserialize(d)? {
86            Some(De(dur)) => Ok(De(Some(dur))),
87            None => Ok(De(None)),
88        }
89    }
90}
91
92/// Deserializes a `Duration` via the humantime crate.
93///
94/// This function can be used with `serde_derive`'s `with` and
95/// `deserialize_with` annotations.
96pub fn deserialize<'de, D>(d: D) -> Result<Duration, D::Error>
97    where D: Deserializer<'de>
98{
99    struct V;
100
101    impl<'de2> Visitor<'de2> for V {
102        type Value = Duration;
103
104        fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
105            fmt.write_str("a duration")
106        }
107
108        fn visit_str<E>(self, v: &str) -> Result<Duration, E>
109            where E: Error
110        {
111            humantime::parse_duration(v).map_err(|_| E::invalid_value(Unexpected::Str(v), &self))
112        }
113    }
114
115    d.deserialize_str(V)
116}
117
118#[cfg(test)]
119mod test {
120    use super::*;
121
122    #[test]
123    fn with() {
124        #[derive(Deserialize)]
125        struct Foo {
126            #[serde(with = "super")]
127            time: Duration,
128        }
129
130        let json = r#"{"time": "15 seconds"}"#;
131        let foo = serde_json::from_str::<Foo>(json).unwrap();
132        assert_eq!(foo.time, Duration::from_secs(15));
133    }
134
135    #[test]
136    fn de_option() {
137        #[derive(Deserialize)]
138        struct Foo {
139            time: De<Option<Duration>>,
140        }
141
142        let json = r#"{"time": "15 seconds"}"#;
143        let foo = serde_json::from_str::<Foo>(json).unwrap();
144        assert_eq!(foo.time.into_inner(), Some(Duration::from_secs(15)));
145
146        let json = r#"{"time": null}"#;
147        let foo = serde_json::from_str::<Foo>(json).unwrap();
148        assert_eq!(foo.time.into_inner(), None);
149
150        let json = r#"{}"#;
151        let foo = serde_json::from_str::<Foo>(json).unwrap();
152        assert_eq!(foo.time.into_inner(), None);
153    }
154}