time/serde/
visitor.rs

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