Source code
Revision control
Copy as Markdown
Other Tools
//! Serde visitor for various types.
use core::fmt;
use core::marker::PhantomData;
use serde::de;
#[cfg(feature = "parsing")]
use serde::Deserializer;
#[cfg(feature = "parsing")]
use super::{
DATE_FORMAT, OFFSET_DATE_TIME_FORMAT, PRIMITIVE_DATE_TIME_FORMAT, TIME_FORMAT,
UTC_OFFSET_FORMAT,
};
use crate::error::ComponentRange;
#[cfg(feature = "parsing")]
use crate::format_description::well_known::*;
use crate::{Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday};
/// A serde visitor for various types.
pub(super) struct Visitor<T: ?Sized>(pub(super) PhantomData<T>);
impl<'a> de::Visitor<'a> for Visitor<Date> {
type Value = Date;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a `Date`")
}
#[cfg(feature = "parsing")]
fn visit_str<E: de::Error>(self, value: &str) -> Result<Date, E> {
Date::parse(value, &DATE_FORMAT).map_err(E::custom)
}
fn visit_seq<A: de::SeqAccess<'a>>(self, mut seq: A) -> Result<Date, A::Error> {
let year = item!(seq, "year")?;
let ordinal = item!(seq, "day of year")?;
Date::from_ordinal_date(year, ordinal).map_err(ComponentRange::into_de_error)
}
}
impl<'a> de::Visitor<'a> for Visitor<Duration> {
type Value = Duration;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a `Duration`")
}
fn visit_str<E: de::Error>(self, value: &str) -> Result<Duration, E> {
let (seconds, nanoseconds) = value.split_once('.').ok_or_else(|| {
de::Error::invalid_value(de::Unexpected::Str(value), &"a decimal point")
})?;
let seconds = seconds
.parse()
.map_err(|_| de::Error::invalid_value(de::Unexpected::Str(seconds), &"seconds"))?;
let mut nanoseconds = nanoseconds.parse().map_err(|_| {
de::Error::invalid_value(de::Unexpected::Str(nanoseconds), &"nanoseconds")
})?;
if seconds < 0 {
nanoseconds *= -1;
}
Ok(Duration::new(seconds, nanoseconds))
}
fn visit_seq<A: de::SeqAccess<'a>>(self, mut seq: A) -> Result<Duration, A::Error> {
let seconds = item!(seq, "seconds")?;
let nanoseconds = item!(seq, "nanoseconds")?;
Ok(Duration::new(seconds, nanoseconds))
}
}
impl<'a> de::Visitor<'a> for Visitor<OffsetDateTime> {
type Value = OffsetDateTime;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("an `OffsetDateTime`")
}
#[cfg(feature = "parsing")]
fn visit_str<E: de::Error>(self, value: &str) -> Result<OffsetDateTime, E> {
OffsetDateTime::parse(value, &OFFSET_DATE_TIME_FORMAT).map_err(E::custom)
}
fn visit_seq<A: de::SeqAccess<'a>>(self, mut seq: A) -> Result<OffsetDateTime, A::Error> {
let year = item!(seq, "year")?;
let ordinal = item!(seq, "day of year")?;
let hour = item!(seq, "hour")?;
let minute = item!(seq, "minute")?;
let second = item!(seq, "second")?;
let nanosecond = item!(seq, "nanosecond")?;
let offset_hours = item!(seq, "offset hours")?;
let offset_minutes = item!(seq, "offset minutes")?;
let offset_seconds = item!(seq, "offset seconds")?;
Date::from_ordinal_date(year, ordinal)
.and_then(|date| date.with_hms_nano(hour, minute, second, nanosecond))
.and_then(|datetime| {
UtcOffset::from_hms(offset_hours, offset_minutes, offset_seconds)
.map(|offset| datetime.assume_offset(offset))
})
.map_err(ComponentRange::into_de_error)
}
}
impl<'a> de::Visitor<'a> for Visitor<PrimitiveDateTime> {
type Value = PrimitiveDateTime;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a `PrimitiveDateTime`")
}
#[cfg(feature = "parsing")]
fn visit_str<E: de::Error>(self, value: &str) -> Result<PrimitiveDateTime, E> {
PrimitiveDateTime::parse(value, &PRIMITIVE_DATE_TIME_FORMAT).map_err(E::custom)
}
fn visit_seq<A: de::SeqAccess<'a>>(self, mut seq: A) -> Result<PrimitiveDateTime, A::Error> {
let year = item!(seq, "year")?;
let ordinal = item!(seq, "day of year")?;
let hour = item!(seq, "hour")?;
let minute = item!(seq, "minute")?;
let second = item!(seq, "second")?;
let nanosecond = item!(seq, "nanosecond")?;
Date::from_ordinal_date(year, ordinal)
.and_then(|date| date.with_hms_nano(hour, minute, second, nanosecond))
.map_err(ComponentRange::into_de_error)
}
}
impl<'a> de::Visitor<'a> for Visitor<Time> {
type Value = Time;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a `Time`")
}
#[cfg(feature = "parsing")]
fn visit_str<E: de::Error>(self, value: &str) -> Result<Time, E> {
Time::parse(value, &TIME_FORMAT).map_err(E::custom)
}
fn visit_seq<A: de::SeqAccess<'a>>(self, mut seq: A) -> Result<Time, A::Error> {
let hour = item!(seq, "hour")?;
let minute = item!(seq, "minute")?;
let second = item!(seq, "second")?;
let nanosecond = item!(seq, "nanosecond")?;
Time::from_hms_nano(hour, minute, second, nanosecond).map_err(ComponentRange::into_de_error)
}
}
impl<'a> de::Visitor<'a> for Visitor<UtcOffset> {
type Value = UtcOffset;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a `UtcOffset`")
}
#[cfg(feature = "parsing")]
fn visit_str<E: de::Error>(self, value: &str) -> Result<UtcOffset, E> {
UtcOffset::parse(value, &UTC_OFFSET_FORMAT).map_err(E::custom)
}
fn visit_seq<A: de::SeqAccess<'a>>(self, mut seq: A) -> Result<UtcOffset, A::Error> {
let hours = item!(seq, "offset hours")?;
let mut minutes = 0;
let mut seconds = 0;
if let Ok(Some(min)) = seq.next_element() {
minutes = min;
if let Ok(Some(sec)) = seq.next_element() {
seconds = sec;
}
};
UtcOffset::from_hms(hours, minutes, seconds).map_err(ComponentRange::into_de_error)
}
}
impl de::Visitor<'_> for Visitor<Weekday> {
type Value = Weekday;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a `Weekday`")
}
fn visit_str<E: de::Error>(self, value: &str) -> Result<Weekday, E> {
match value {
"Monday" => Ok(Weekday::Monday),
"Tuesday" => Ok(Weekday::Tuesday),
"Wednesday" => Ok(Weekday::Wednesday),
"Thursday" => Ok(Weekday::Thursday),
"Friday" => Ok(Weekday::Friday),
"Saturday" => Ok(Weekday::Saturday),
"Sunday" => Ok(Weekday::Sunday),
_ => Err(E::invalid_value(de::Unexpected::Str(value), &"a `Weekday`")),
}
}
fn visit_u64<E: de::Error>(self, value: u64) -> Result<Weekday, E> {
match value {
1 => Ok(Weekday::Monday),
2 => Ok(Weekday::Tuesday),
3 => Ok(Weekday::Wednesday),
4 => Ok(Weekday::Thursday),
5 => Ok(Weekday::Friday),
6 => Ok(Weekday::Saturday),
7 => Ok(Weekday::Sunday),
_ => Err(E::invalid_value(
de::Unexpected::Unsigned(value),
&"a value in the range 1..=7",
)),
}
}
}
impl de::Visitor<'_> for Visitor<Month> {
type Value = Month;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a `Month`")
}
fn visit_str<E: de::Error>(self, value: &str) -> Result<Month, E> {
match value {
"January" => Ok(Month::January),
"February" => Ok(Month::February),
"March" => Ok(Month::March),
"April" => Ok(Month::April),
"May" => Ok(Month::May),
"June" => Ok(Month::June),
"July" => Ok(Month::July),
"August" => Ok(Month::August),
"September" => Ok(Month::September),
"October" => Ok(Month::October),
"November" => Ok(Month::November),
"December" => Ok(Month::December),
_ => Err(E::invalid_value(de::Unexpected::Str(value), &"a `Month`")),
}
}
fn visit_u64<E: de::Error>(self, value: u64) -> Result<Month, E> {
match value {
1 => Ok(Month::January),
2 => Ok(Month::February),
3 => Ok(Month::March),
4 => Ok(Month::April),
5 => Ok(Month::May),
6 => Ok(Month::June),
7 => Ok(Month::July),
8 => Ok(Month::August),
9 => Ok(Month::September),
10 => Ok(Month::October),
11 => Ok(Month::November),
12 => Ok(Month::December),
_ => Err(E::invalid_value(
de::Unexpected::Unsigned(value),
&"a value in the range 1..=12",
)),
}
}
}
/// Implement a visitor for a well-known format.
macro_rules! well_known {
($article:literal, $name:literal, $($ty:tt)+) => {
#[cfg(feature = "parsing")]
impl de::Visitor<'_> for Visitor<$($ty)+> {
type Value = OffsetDateTime;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(concat!($article, " ", $name, "-formatted `OffsetDateTime`"))
}
fn visit_str<E: de::Error>(self, value: &str) -> Result<OffsetDateTime, E> {
OffsetDateTime::parse(value, &$($ty)+).map_err(E::custom)
}
}
#[cfg(feature = "parsing")]
impl<'a> de::Visitor<'a> for Visitor<Option<$($ty)+>> {
type Value = Option<OffsetDateTime>;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(concat!(
$article,
" ",
$name,
"-formatted `Option<OffsetDateTime>`"
))
}
fn visit_some<D: Deserializer<'a>>(
self,
deserializer: D,
) -> Result<Option<OffsetDateTime>, D::Error> {
deserializer
.deserialize_any(Visitor::<$($ty)+>(PhantomData))
.map(Some)
}
fn visit_none<E: de::Error>(self) -> Result<Option<OffsetDateTime>, E> {
Ok(None)
}
fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
Ok(None)
}
}
};
}
well_known!("an", "RFC2822", Rfc2822);
well_known!("an", "RFC3339", Rfc3339);
well_known!(
"an",
"ISO 8601",
Iso8601::<{ super::iso8601::SERDE_CONFIG }>
);