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