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