1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
//! Extensions for serde.

/// A module for serializing/deserializing a `Duration` as milliseconds.
pub mod duration_millis {
    use serde::{Deserialize, Deserializer, Serialize, Serializer};
    use std::time::Duration;

    pub fn serialize<S>(value: &Duration, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        to_millis(value).serialize(serializer)
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<Duration, D::Error>
    where
        D: Deserializer<'de>,
    {
        u64::deserialize(deserializer).map(from_millis)
    }

    pub(crate) fn to_millis(duration: &Duration) -> u64 {
        duration.as_secs() * 1000 + u64::from(duration.subsec_millis())
    }

    pub(crate) fn from_millis(millis: u64) -> Duration {
        Duration::from_millis(millis)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::time::Duration;

    #[test]
    fn to_millis_works() {
        assert_eq!(0, duration_millis::to_millis(&Duration::from_millis(0)));
        assert_eq!(10, duration_millis::to_millis(&Duration::from_millis(10)));
        assert_eq!(999, duration_millis::to_millis(&Duration::from_millis(999)));
        assert_eq!(0, duration_millis::to_millis(&Duration::from_nanos(3000)));
        assert_eq!(
            0,
            duration_millis::to_millis(&Duration::from_nanos(999_999))
        );
        assert_eq!(
            1,
            duration_millis::to_millis(&Duration::from_nanos(1_000_000))
        );
        assert_eq!(
            1,
            duration_millis::to_millis(&Duration::from_nanos(1_000_001))
        );
        assert_eq!(1000, duration_millis::to_millis(&Duration::from_secs(1)));
    }

    #[derive(PartialEq, Debug, Serialize, Deserialize)]
    struct TestStruct {
        #[serde(with = "duration_millis")]
        pub duration: Duration,

        #[serde(default = "default_duration", with = "duration_millis")]
        pub default_duration: Duration,
    }
    fn default_duration() -> Duration {
        Duration::from_secs(42)
    }

    #[test]
    fn serialize_and_deserialize_work() -> Result<(), Box<dyn std::error::Error>> {
        let test: TestStruct = TestStruct {
            duration: Duration::from_millis(42),
            default_duration: default_duration(),
        };
        let yaml = serde_yaml::to_string(&test)?;
        let deserialized = serde_yaml::from_str(&yaml)?;

        assert_eq!(test, deserialized);

        Ok(())
    }

    #[test]
    fn default_and_deserialize_work() -> Result<(), Box<dyn std::error::Error>> {
        let yaml = r#"---
duration: 24
"#;
        let deserialized: TestStruct = serde_yaml::from_str(&yaml)?;
        assert_eq!(deserialized.duration, Duration::from_millis(24));
        assert_eq!(deserialized.default_duration, default_duration());

        Ok(())
    }
}