treadmill_rs/
util.rs

1pub mod hex_slice {
2    //! Wrapper type around a slice to print it as a lower-case hex
3    //! string.
4    use std::fmt;
5
6    /// Wrapper type around a slice to print it as a lower-case hex
7    /// string. Implements both [`Display`](fmt::Display) and
8    /// [`Debug`](fmt::Debug).
9    pub struct HexSlice<'a>(pub &'a [u8]);
10
11    impl<'a> fmt::Debug for HexSlice<'a> {
12        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
13            for b in self.0.iter() {
14                write!(f, "{:0>2x}", *b)?;
15            }
16
17            Ok(())
18        }
19    }
20
21    impl<'a> fmt::Display for HexSlice<'a> {
22        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23            write!(f, "{self:?}")
24        }
25    }
26}
27
28/// Based on https://serde.rs/custom-date-format.html.
29pub mod chrono {
30    pub mod optional_duration {
31        use chrono::TimeDelta;
32        use serde::{Deserialize, Deserializer, Serializer};
33
34        pub fn serialize<S>(duration: &Option<TimeDelta>, serializer: S) -> Result<S::Ok, S::Error>
35        where
36            S: Serializer,
37        {
38            match duration.as_ref() {
39                Some(duration) => {
40                    serializer.serialize_some(fundu::Duration::from(*duration).to_string().as_str())
41                }
42                None => serializer.serialize_none(),
43            }
44        }
45        pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<TimeDelta>, D::Error>
46        where
47            D: Deserializer<'de>,
48        {
49            Option::<&str>::deserialize(deserializer)?
50                .map(|s| {
51                    fundu::DurationParser::new()
52                        .parse(s)
53                        .map_err(serde::de::Error::custom)?
54                        .try_into()
55                        .map_err(serde::de::Error::custom)
56                })
57                .transpose()
58        }
59    }
60
61    pub mod duration {
62        use chrono::TimeDelta;
63        use serde::{Deserialize, Deserializer, Serializer};
64
65        pub fn serialize<S>(duration: &TimeDelta, serializer: S) -> Result<S::Ok, S::Error>
66        where
67            S: Serializer,
68        {
69            serializer.serialize_str(fundu::Duration::from(*duration).to_string().as_str())
70        }
71
72        pub fn deserialize<'de, D>(deserializer: D) -> Result<TimeDelta, D::Error>
73        where
74            D: Deserializer<'de>,
75        {
76            String::deserialize(deserializer)
77                .map(|s| {
78                    fundu::DurationParser::new()
79                        .parse(&s)
80                        .map_err(serde::de::Error::custom)?
81                        .try_into()
82                        .map_err(serde::de::Error::custom)
83                })
84                // same as Result::flatten, since that hasn't been stabilized
85                .and_then(|x| x)
86        }
87    }
88}