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