Skip to main content

time/serde/
visitor.rs

1//! Serde visitor for various types.
2
3use core::fmt;
4use core::marker::PhantomData;
5
6#[cfg(feature = "parsing")]
7use serde_core::Deserializer;
8use serde_core::de;
9
10#[cfg(feature = "parsing")]
11use super::{
12    DATE_FORMAT, OFFSET_DATE_TIME_FORMAT, PRIMITIVE_DATE_TIME_FORMAT, TIME_FORMAT,
13    UTC_DATE_TIME_FORMAT, UTC_OFFSET_FORMAT,
14};
15use crate::error::ComponentRange;
16#[cfg(feature = "parsing")]
17use crate::format_description::well_known::*;
18use crate::{
19    Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, Timestamp, UtcDateTime,
20    UtcOffset, Weekday,
21};
22
23/// A serde visitor for various types.
24pub(super) struct Visitor<T>(pub(super) PhantomData<T>)
25where
26    T: ?Sized;
27
28impl<'a> de::Visitor<'a> for Visitor<Date> {
29    type Value = Date;
30
31    #[inline]
32    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
33        formatter.write_str("a `Date`")
34    }
35
36    #[cfg(feature = "parsing")]
37    #[inline]
38    fn visit_str<E>(self, value: &str) -> Result<Date, E>
39    where
40        E: de::Error,
41    {
42        Date::parse(value, &DATE_FORMAT).map_err(E::custom)
43    }
44
45    #[inline]
46    fn visit_seq<A>(self, mut seq: A) -> Result<Date, A::Error>
47    where
48        A: de::SeqAccess<'a>,
49    {
50        let year = item!(seq, "year")?;
51        let ordinal = item!(seq, "day of year")?;
52        Date::from_ordinal_date(year, ordinal).map_err(ComponentRange::into_de_error)
53    }
54}
55
56impl<'a> de::Visitor<'a> for Visitor<Duration> {
57    type Value = Duration;
58
59    #[inline]
60    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
61        formatter.write_str("a `Duration`")
62    }
63
64    #[inline]
65    fn visit_str<E>(self, value: &str) -> Result<Duration, E>
66    where
67        E: de::Error,
68    {
69        let (seconds, nanoseconds) = value.split_once('.').ok_or_else(|| {
70            de::Error::invalid_value(de::Unexpected::Str(value), &"a decimal point")
71        })?;
72
73        let seconds = seconds
74            .parse()
75            .map_err(|_| de::Error::invalid_value(de::Unexpected::Str(seconds), &"seconds"))?;
76        let mut nanoseconds = nanoseconds.parse().map_err(|_| {
77            de::Error::invalid_value(de::Unexpected::Str(nanoseconds), &"nanoseconds")
78        })?;
79
80        if seconds < 0
81            // make sure sign does not disappear when seconds == 0
82            || (seconds == 0 && value.starts_with("-"))
83        {
84            nanoseconds *= -1;
85        }
86
87        Ok(Duration::new(seconds, nanoseconds))
88    }
89
90    #[inline]
91    fn visit_seq<A>(self, mut seq: A) -> Result<Duration, A::Error>
92    where
93        A: de::SeqAccess<'a>,
94    {
95        let seconds = item!(seq, "seconds")?;
96        let nanoseconds = item!(seq, "nanoseconds")?;
97        Ok(Duration::new(seconds, nanoseconds))
98    }
99}
100
101impl<'a> de::Visitor<'a> for Visitor<OffsetDateTime> {
102    type Value = OffsetDateTime;
103
104    #[inline]
105    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
106        formatter.write_str("an `OffsetDateTime`")
107    }
108
109    #[cfg(feature = "parsing")]
110    #[inline]
111    fn visit_str<E>(self, value: &str) -> Result<OffsetDateTime, E>
112    where
113        E: de::Error,
114    {
115        OffsetDateTime::parse(value, &OFFSET_DATE_TIME_FORMAT).map_err(E::custom)
116    }
117
118    #[inline]
119    fn visit_seq<A>(self, mut seq: A) -> Result<OffsetDateTime, A::Error>
120    where
121        A: de::SeqAccess<'a>,
122    {
123        let year = item!(seq, "year")?;
124        let ordinal = item!(seq, "day of year")?;
125        let hour = item!(seq, "hour")?;
126        let minute = item!(seq, "minute")?;
127        let second = item!(seq, "second")?;
128        let nanosecond = item!(seq, "nanosecond")?;
129        let offset_hours = item!(seq, "offset hours")?;
130        let offset_minutes = item!(seq, "offset minutes")?;
131        let offset_seconds = item!(seq, "offset seconds")?;
132
133        Date::from_ordinal_date(year, ordinal)
134            .and_then(|date| date.with_hms_nano(hour, minute, second, nanosecond))
135            .and_then(|datetime| {
136                UtcOffset::from_hms(offset_hours, offset_minutes, offset_seconds)
137                    .map(|offset| datetime.assume_offset(offset))
138            })
139            .map_err(ComponentRange::into_de_error)
140    }
141}
142
143impl<'a> de::Visitor<'a> for Visitor<PrimitiveDateTime> {
144    type Value = PrimitiveDateTime;
145
146    #[inline]
147    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
148        formatter.write_str("a `PrimitiveDateTime`")
149    }
150
151    #[cfg(feature = "parsing")]
152    #[inline]
153    fn visit_str<E>(self, value: &str) -> Result<PrimitiveDateTime, E>
154    where
155        E: de::Error,
156    {
157        PrimitiveDateTime::parse(value, &PRIMITIVE_DATE_TIME_FORMAT).map_err(E::custom)
158    }
159
160    #[inline]
161    fn visit_seq<A>(self, mut seq: A) -> Result<PrimitiveDateTime, A::Error>
162    where
163        A: de::SeqAccess<'a>,
164    {
165        let year = item!(seq, "year")?;
166        let ordinal = item!(seq, "day of year")?;
167        let hour = item!(seq, "hour")?;
168        let minute = item!(seq, "minute")?;
169        let second = item!(seq, "second")?;
170        let nanosecond = item!(seq, "nanosecond")?;
171
172        Date::from_ordinal_date(year, ordinal)
173            .and_then(|date| date.with_hms_nano(hour, minute, second, nanosecond))
174            .map_err(ComponentRange::into_de_error)
175    }
176}
177
178impl<'a> de::Visitor<'a> for Visitor<UtcDateTime> {
179    type Value = UtcDateTime;
180
181    #[inline]
182    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
183        formatter.write_str("a `PrimitiveDateTime`")
184    }
185
186    #[cfg(feature = "parsing")]
187    #[inline]
188    fn visit_str<E>(self, value: &str) -> Result<UtcDateTime, E>
189    where
190        E: de::Error,
191    {
192        UtcDateTime::parse(value, &UTC_DATE_TIME_FORMAT).map_err(E::custom)
193    }
194
195    #[inline]
196    fn visit_seq<A>(self, mut seq: A) -> Result<UtcDateTime, A::Error>
197    where
198        A: de::SeqAccess<'a>,
199    {
200        let year = item!(seq, "year")?;
201        let ordinal = item!(seq, "day of year")?;
202        let hour = item!(seq, "hour")?;
203        let minute = item!(seq, "minute")?;
204        let second = item!(seq, "second")?;
205        let nanosecond = item!(seq, "nanosecond")?;
206
207        Date::from_ordinal_date(year, ordinal)
208            .and_then(|date| date.with_hms_nano(hour, minute, second, nanosecond))
209            .map(UtcDateTime::from_primitive)
210            .map_err(ComponentRange::into_de_error)
211    }
212}
213
214impl<'a> de::Visitor<'a> for Visitor<Time> {
215    type Value = Time;
216
217    #[inline]
218    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
219        formatter.write_str("a `Time`")
220    }
221
222    #[cfg(feature = "parsing")]
223    #[inline]
224    fn visit_str<E>(self, value: &str) -> Result<Time, E>
225    where
226        E: de::Error,
227    {
228        Time::parse(value, &TIME_FORMAT).map_err(E::custom)
229    }
230
231    #[inline]
232    fn visit_seq<A>(self, mut seq: A) -> Result<Time, A::Error>
233    where
234        A: de::SeqAccess<'a>,
235    {
236        let hour = item!(seq, "hour")?;
237        let minute = item!(seq, "minute")?;
238        let second = item!(seq, "second")?;
239        let nanosecond = item!(seq, "nanosecond")?;
240
241        Time::from_hms_nano(hour, minute, second, nanosecond).map_err(ComponentRange::into_de_error)
242    }
243}
244
245impl<'a> de::Visitor<'a> for Visitor<UtcOffset> {
246    type Value = UtcOffset;
247
248    #[inline]
249    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
250        formatter.write_str("a `UtcOffset`")
251    }
252
253    #[cfg(feature = "parsing")]
254    #[inline]
255    fn visit_str<E>(self, value: &str) -> Result<UtcOffset, E>
256    where
257        E: de::Error,
258    {
259        UtcOffset::parse(value, &UTC_OFFSET_FORMAT).map_err(E::custom)
260    }
261
262    #[inline]
263    fn visit_seq<A>(self, mut seq: A) -> Result<UtcOffset, A::Error>
264    where
265        A: de::SeqAccess<'a>,
266    {
267        let hours = item!(seq, "offset hours")?;
268        let mut minutes = 0;
269        let mut seconds = 0;
270
271        if let Ok(Some(min)) = seq.next_element() {
272            minutes = min;
273            if let Ok(Some(sec)) = seq.next_element() {
274                seconds = sec;
275            }
276        };
277
278        UtcOffset::from_hms(hours, minutes, seconds).map_err(ComponentRange::into_de_error)
279    }
280}
281
282impl de::Visitor<'_> for Visitor<Timestamp> {
283    type Value = Timestamp;
284
285    #[inline]
286    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
287        formatter.write_str("a `Timestamp`")
288    }
289
290    #[inline]
291    fn visit_i128<E>(self, value: i128) -> Result<Timestamp, E>
292    where
293        E: de::Error,
294    {
295        Timestamp::from_nanoseconds(value).map_err(ComponentRange::into_de_error)
296    }
297}
298
299impl de::Visitor<'_> for Visitor<Weekday> {
300    type Value = Weekday;
301
302    #[inline]
303    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
304        formatter.write_str("a `Weekday`")
305    }
306
307    #[inline]
308    fn visit_str<E>(self, value: &str) -> Result<Weekday, E>
309    where
310        E: de::Error,
311    {
312        match value {
313            "Monday" => Ok(Weekday::Monday),
314            "Tuesday" => Ok(Weekday::Tuesday),
315            "Wednesday" => Ok(Weekday::Wednesday),
316            "Thursday" => Ok(Weekday::Thursday),
317            "Friday" => Ok(Weekday::Friday),
318            "Saturday" => Ok(Weekday::Saturday),
319            "Sunday" => Ok(Weekday::Sunday),
320            _ => Err(E::invalid_value(de::Unexpected::Str(value), &"a `Weekday`")),
321        }
322    }
323
324    #[inline]
325    fn visit_u64<E>(self, value: u64) -> Result<Weekday, E>
326    where
327        E: de::Error,
328    {
329        match value {
330            1 => Ok(Weekday::Monday),
331            2 => Ok(Weekday::Tuesday),
332            3 => Ok(Weekday::Wednesday),
333            4 => Ok(Weekday::Thursday),
334            5 => Ok(Weekday::Friday),
335            6 => Ok(Weekday::Saturday),
336            7 => Ok(Weekday::Sunday),
337            _ => Err(E::invalid_value(
338                de::Unexpected::Unsigned(value),
339                &"a value in the range 1..=7",
340            )),
341        }
342    }
343}
344
345impl de::Visitor<'_> for Visitor<Month> {
346    type Value = Month;
347
348    #[inline]
349    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
350        formatter.write_str("a `Month`")
351    }
352
353    #[inline]
354    fn visit_str<E>(self, value: &str) -> Result<Month, E>
355    where
356        E: de::Error,
357    {
358        match value {
359            "January" => Ok(Month::January),
360            "February" => Ok(Month::February),
361            "March" => Ok(Month::March),
362            "April" => Ok(Month::April),
363            "May" => Ok(Month::May),
364            "June" => Ok(Month::June),
365            "July" => Ok(Month::July),
366            "August" => Ok(Month::August),
367            "September" => Ok(Month::September),
368            "October" => Ok(Month::October),
369            "November" => Ok(Month::November),
370            "December" => Ok(Month::December),
371            _ => Err(E::invalid_value(de::Unexpected::Str(value), &"a `Month`")),
372        }
373    }
374
375    #[inline]
376    fn visit_u64<E>(self, value: u64) -> Result<Month, E>
377    where
378        E: de::Error,
379    {
380        match value {
381            1 => Ok(Month::January),
382            2 => Ok(Month::February),
383            3 => Ok(Month::March),
384            4 => Ok(Month::April),
385            5 => Ok(Month::May),
386            6 => Ok(Month::June),
387            7 => Ok(Month::July),
388            8 => Ok(Month::August),
389            9 => Ok(Month::September),
390            10 => Ok(Month::October),
391            11 => Ok(Month::November),
392            12 => Ok(Month::December),
393            _ => Err(E::invalid_value(
394                de::Unexpected::Unsigned(value),
395                &"a value in the range 1..=12",
396            )),
397        }
398    }
399}
400
401/// Implement a visitor for a well-known format.
402macro_rules! well_known {
403    ($article:literal, $name:literal, $($ty:tt)+) => {
404        #[cfg(feature = "parsing")]
405        impl de::Visitor<'_> for Visitor<$($ty)+> {
406            type Value = OffsetDateTime;
407
408            #[inline]
409            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
410                formatter.write_str(concat!($article, " ", $name, "-formatted `OffsetDateTime`"))
411            }
412
413            #[inline]
414            fn visit_str<E>(self, value: &str) -> Result<OffsetDateTime, E>
415            where
416                E: de::Error,
417            {
418                OffsetDateTime::parse(value, &$($ty)+).map_err(E::custom)
419            }
420        }
421
422        #[cfg(feature = "parsing")]
423        impl<'a> de::Visitor<'a> for Visitor<Option<$($ty)+>> {
424            type Value = Option<OffsetDateTime>;
425
426            #[inline]
427            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
428                formatter.write_str(concat!(
429                    $article,
430                    " ",
431                    $name,
432                    "-formatted `Option<OffsetDateTime>`"
433                ))
434            }
435
436            #[inline]
437            fn visit_some<D>(self, deserializer: D) -> Result<Option<OffsetDateTime>, D::Error>
438            where
439                D: Deserializer<'a>,
440            {
441                deserializer
442                    .deserialize_any(Visitor::<$($ty)+>(PhantomData))
443                    .map(Some)
444            }
445
446            #[inline]
447            fn visit_none<E>(self) -> Result<Option<OffsetDateTime>, E>
448            where
449                E: de::Error,
450            {
451                Ok(None)
452            }
453
454            #[inline]
455            fn visit_unit<E>(self) -> Result<Self::Value, E>
456            where
457                E: de::Error,
458            {
459                Ok(None)
460            }
461        }
462    };
463}
464
465well_known!("an", "RFC2822", Rfc2822);
466well_known!("an", "RFC3339", Rfc3339);
467well_known!(
468    "an",
469    "ISO 8601",
470    Iso8601::<{ super::iso8601::SERDE_CONFIG }>
471);