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