hocon_linked/serde/
wrappers.rs

1//! Wrapper for custom deserialization from Hocon
2
3use std::{
4    fmt,
5    ops::{Deref, DerefMut},
6    time::Duration,
7};
8
9use serde::{
10    de::{self, Deserialize, Visitor},
11    Deserializer,
12};
13
14use crate::Hocon;
15
16/// Wrapper for custom deserialization from Hocon.
17///
18/// Implemented for [`Duration`]
19///
20/// ## As a newtype wrapper
21///
22/// ```rust
23/// # use std::time::Duration;
24/// # use hocon::de::wrappers::Serde;
25/// # use serde::Deserialize;
26/// #[derive(Deserialize, Debug)]
27/// struct StructWithDuration {
28///     timeout: Serde<Duration>,
29/// }
30/// # fn usage() {
31/// # let doc = r#"{"a":"1 second"}"#;
32///
33/// let my_struct: StructWithDuration = hocon::de::from_str(doc).unwrap();
34/// assert_eq!(*my_struct.timeout, Duration::from_secs(1));
35/// # }
36/// ```
37///
38/// ## As a serde attribute
39///
40/// ```rust
41/// # use std::time::Duration;
42/// # use hocon::de::wrappers::Serde;
43/// # use serde::Deserialize;
44/// #[derive(Deserialize, Debug)]
45/// struct StructWithDuration {
46///     #[serde(deserialize_with = "Serde::<Duration>::with")]
47///     timeout: Duration,
48/// }
49/// # fn usage() {
50/// # let doc = r#"{"a":"1 second"}"#;
51///
52/// let my_struct: StructWithDuration = hocon::de::from_str(doc).unwrap();
53/// assert_eq!(my_struct.timeout, Duration::from_secs(1));
54/// # }
55/// ```
56#[doc(alias = "Duration")]
57#[derive(Debug)]
58pub struct Serde<T>(T);
59
60impl<T> Deref for Serde<T> {
61    type Target = T;
62
63    fn deref(&self) -> &Self::Target {
64        &self.0
65    }
66}
67
68impl<T> DerefMut for Serde<T> {
69    fn deref_mut(&mut self) -> &mut Self::Target {
70        &mut self.0
71    }
72}
73
74struct StringDurationVisitor;
75
76impl<'de> Visitor<'de> for StringDurationVisitor {
77    type Value = Duration;
78
79    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
80        formatter.write_str("a duration")
81    }
82
83    fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
84    where
85        E: de::Error,
86    {
87        let duration = Hocon::str_as_milliseconds(&v)
88            .ok_or_else(|| E::custom(format!("expected duration, found \"{}\"", v)))?;
89
90        Ok(Duration::from_secs_f64(duration / 1000.0))
91    }
92
93    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
94    where
95        E: de::Error,
96    {
97        let duration = Hocon::str_as_milliseconds(v)
98            .ok_or_else(|| E::custom(format!("expected duration, found \"{}\"", v)))?;
99
100        Ok(Duration::from_secs_f64(duration / 1000.0))
101    }
102}
103
104impl<'de> Deserialize<'de> for Serde<Duration> {
105    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
106    where
107        D: Deserializer<'de>,
108    {
109        Ok(Serde(deserializer.deserialize_str(StringDurationVisitor)?))
110    }
111}
112
113impl Serde<Duration> {
114    /// Custom deserializer for a duration, to use with Serde `deserialize_with` attribute
115    pub fn with<'de, D>(deserializer: D) -> Result<Duration, D::Error>
116    where
117        D: Deserializer<'de>,
118    {
119        deserializer.deserialize_str(StringDurationVisitor)
120    }
121}