1#[cfg(all(feature = "chrono", feature = "serde"))]
2use crate::parse_chrono;
3use crate::parse_std;
4#[cfg(all(feature = "time", feature = "serde"))]
5use crate::parse_time;
6use std::time::Duration;
7
8#[cfg(all(feature = "chrono", feature = "serde"))]
9use chrono::Duration as CDuration;
10
11#[cfg(all(feature = "time", feature = "serde"))]
12use time::Duration as TDuration;
13
14#[cfg(feature = "serde")]
15macro_rules! des_duration {
16 ($name:ident,$duration_type:ident,$fn_name:ident,$parse:ident) => {
17 struct $name;
18 impl<'de> serde::de::Visitor<'de> for $name {
19 type Value = $duration_type;
20
21 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
22 formatter.write_str("expect duration string,e.g:'1min+30'")
23 }
24
25 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
26 where
27 E: serde::de::Error,
28 {
29 let duration = $parse(s).map_err(serde::de::Error::custom)?;
30 Ok(duration)
31 }
32 }
33
34 pub fn $fn_name<'de, D>(deserializer: D) -> Result<$duration_type, D::Error>
35 where
36 D: serde::Deserializer<'de>,
37 {
38 deserializer.deserialize_any($name)
39 }
40 };
41}
42
43#[cfg(feature = "serde")]
44macro_rules! des_option_duration {
45 ($name:ident,$duration_type:ident,$fn_name:ident,$parse:ident) => {
46 struct $name;
47 impl<'de> serde::de::Visitor<'de> for $name {
48 type Value = Option<$duration_type>;
49
50 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
51 formatter.write_str("expect duration string,e.g:'1min+30'")
52 }
53
54 fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error>
55 where
56 D: serde::Deserializer<'de>,
57 {
58 use serde::Deserialize;
59 let s: Option<String> = Option::deserialize(d)?;
60 if let Some(s) = s {
61 let duration = $parse(s).map_err(serde::de::Error::custom)?;
62 return Ok(Some(duration));
63 }
64 Ok(None)
65 }
66
67 fn visit_none<E>(self) -> Result<Self::Value, E>
68 where
69 E: serde::de::Error,
70 {
71 Ok(None)
72 }
73 }
74
75 pub fn $fn_name<'de, D>(deserializer: D) -> Result<Option<$duration_type>, D::Error>
76 where
77 D: serde::Deserializer<'de>,
78 {
79 deserializer.deserialize_option($name)
80 }
81 };
82}
83
84#[cfg(feature = "serde")]
85des_duration!(DurationStd, Duration, deserialize_duration, parse_std);
86
87#[cfg(feature = "serde")]
88des_option_duration!(
89 OptionDurationStd,
90 Duration,
91 deserialize_option_duration,
92 parse_std
93);
94
95#[cfg(all(feature = "chrono", feature = "serde"))]
96des_duration!(
97 DurationChrono,
98 CDuration,
99 deserialize_duration_chrono,
100 parse_chrono
101);
102
103#[cfg(all(feature = "chrono", feature = "serde"))]
104des_option_duration!(
105 OptionDurationChrono,
106 CDuration,
107 deserialize_option_duration_chrono,
108 parse_chrono
109);
110
111#[cfg(all(feature = "time", feature = "serde"))]
112des_duration!(
113 DurationTime,
114 TDuration,
115 deserialize_duration_time,
116 parse_time
117);
118
119#[cfg(all(feature = "time", feature = "serde"))]
120des_option_duration!(
121 OptionDurationTime,
122 TDuration,
123 deserialize_option_duration_time,
124 parse_time
125);
126
127#[cfg(all(test, feature = "time"))]
128mod tests {
129 use super::*;
130 use crate::ONE_YEAR_NANOSECOND;
131 use serde::*;
132
133 #[cfg(feature = "serde")]
134 #[test]
135 fn test_deserialize_duration_time() {
136 #[derive(Debug, Deserialize)]
137 struct Config {
138 #[serde(deserialize_with = "deserialize_duration_time")]
139 time_ticker: TDuration,
140 }
141 let json = r#"{"time_ticker":"1y+30"}"#;
142 let config: Config = serde_json::from_str(json).unwrap();
143 assert_eq!(
144 config.time_ticker,
145 TDuration::nanoseconds(ONE_YEAR_NANOSECOND as i64) + TDuration::seconds(30)
146 );
147 }
148
149 #[cfg(feature = "serde")]
150 #[test]
151 fn test_deserialize_option_duration_time() {
152 use TDuration;
153
154 #[derive(Debug, Deserialize)]
155 struct Config {
156 #[serde(deserialize_with = "deserialize_option_duration_time")]
157 time_ticker: Option<TDuration>,
158 }
159 let json = r#"{"time_ticker":"1y+30"}"#;
160 let config: Config = serde_json::from_str(json).unwrap();
161 assert_eq!(
162 config.time_ticker,
163 Some(TDuration::nanoseconds(ONE_YEAR_NANOSECOND as i64) + TDuration::seconds(30))
164 );
165 }
166
167 #[cfg(feature = "serde")]
168 #[test]
169 fn test_deserialize_unit_with_spaces() {
170 #[derive(Debug, Deserialize)]
171 struct Config {
172 #[serde(deserialize_with = "deserialize_duration_time")]
173 time_ticker: TDuration,
174 }
175 let json = r#"{"time_ticker":"1 y + 30"}"#;
176 let config: Config = serde_json::from_str(json).unwrap();
177 assert_eq!(
178 config.time_ticker,
179 TDuration::nanoseconds(ONE_YEAR_NANOSECOND as i64) + TDuration::seconds(30)
180 );
181 }
182
183 #[cfg(all(feature = "serde", feature = "chrono"))]
184 #[test]
185 fn test_deserialize_duration_chrono() {
186 use chrono::Duration;
187 #[derive(Debug, serde::Deserialize)]
188 struct Config {
189 #[serde(deserialize_with = "deserialize_duration_chrono")]
190 time_ticker: Duration,
191 }
192 let json = r#"{"time_ticker":"1y+30"}"#;
193 let config: Config = serde_json::from_str(json).unwrap();
194 assert_eq!(
195 config.time_ticker,
196 Duration::nanoseconds(ONE_YEAR_NANOSECOND as i64) + Duration::seconds(30)
197 );
198 }
199
200 #[cfg(all(feature = "serde", feature = "chrono"))]
201 #[test]
202 fn test_deserialize_option_duration_chrono() {
203 use chrono::Duration;
204 #[derive(Debug, serde::Deserialize)]
205 struct Config {
206 #[serde(deserialize_with = "deserialize_option_duration_chrono")]
207 time_ticker: Option<Duration>,
208 }
209 let json = r#"{"time_ticker":"1y+30"}"#;
210 let config: Config = serde_json::from_str(json).unwrap();
211 assert_eq!(
212 config.time_ticker,
213 Some(Duration::nanoseconds(ONE_YEAR_NANOSECOND as i64) + Duration::seconds(30))
214 );
215 }
216
217 #[cfg(feature = "serde")]
218 #[test]
219 fn test_deserialize_duration() {
220 #[derive(Debug, serde::Deserialize)]
221 struct Config {
222 #[serde(deserialize_with = "deserialize_duration")]
223 time_ticker: std::time::Duration,
224 }
225 let json = r#"{"time_ticker":"1min+30"}"#;
226 let config: Config = serde_json::from_str(json).unwrap();
227 assert_eq!(config.time_ticker, std::time::Duration::from_secs(90));
228 }
229
230 #[cfg(feature = "serde")]
231 #[test]
232 fn test_deserialize_option_duration() {
233 #[derive(Debug, serde::Deserialize)]
234 struct Config {
235 #[serde(deserialize_with = "deserialize_option_duration")]
236 time_ticker: Option<std::time::Duration>,
237 }
238 let json = r#"{"time_ticker":"1min+30"}"#;
239 let config: Config = serde_json::from_str(json).unwrap();
240 assert_eq!(config.time_ticker, Some(std::time::Duration::from_secs(90)));
241 }
242
243 #[cfg(feature = "serde")]
244 #[test]
245 fn test_deserialize_duration2() {
246 #[derive(Debug, serde::Deserialize)]
247 struct Config {
248 #[serde(deserialize_with = "deserialize_duration")]
249 time_ticker: std::time::Duration,
250 }
251 let json = r#"{"time_ticker":"1y+30"}"#;
252 let config: Config = serde_json::from_str(json).unwrap();
253 assert_eq!(
254 config.time_ticker,
255 std::time::Duration::from_nanos(ONE_YEAR_NANOSECOND)
256 + std::time::Duration::from_secs(30)
257 );
258 }
259
260 #[cfg(feature = "serde")]
261 #[test]
262 fn test_deserialize_option_duration2() {
263 #[derive(Debug, serde::Deserialize, PartialEq)]
264 struct Config {
265 #[serde(default, deserialize_with = "deserialize_option_duration")]
266 time_ticker: Option<std::time::Duration>,
267 name: String,
268 }
269 let json = r#"{"time_ticker":null,"name":"foo"}"#;
270 let config: Config = serde_json::from_str(json).unwrap();
271
272 assert_eq!(
273 config,
274 Config {
275 time_ticker: None,
276 name: "foo".into(),
277 }
278 );
279
280 let json = r#"{"name":"foo"}"#;
281 let config: Config = serde_json::from_str(json).unwrap();
282 assert_eq!(
283 config,
284 Config {
285 time_ticker: None,
286 name: "foo".into(),
287 }
288 );
289 }
290}