diff options
Diffstat (limited to 'vendor/time-macros/src/serde_format_description.rs')
-rw-r--r-- | vendor/time-macros/src/serde_format_description.rs | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/vendor/time-macros/src/serde_format_description.rs b/vendor/time-macros/src/serde_format_description.rs new file mode 100644 index 000000000..c09a4e9e2 --- /dev/null +++ b/vendor/time-macros/src/serde_format_description.rs @@ -0,0 +1,163 @@ +use proc_macro::{Ident, TokenStream, TokenTree}; + +pub(crate) fn build( + mod_name: Ident, + ty: TokenTree, + format: TokenStream, + raw_format_string: Option<String>, +) -> TokenStream { + let ty_s = &*ty.to_string(); + + let format_description_display = raw_format_string.unwrap_or_else(|| format.to_string()); + + let visitor = if cfg!(feature = "parsing") { + quote! { + struct Visitor; + struct OptionVisitor; + + impl<'a> ::serde::de::Visitor<'a> for Visitor { + type Value = __TimeSerdeType; + + fn expecting(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!( + f, + concat!( + "a(n) `", + #(ty_s), + "` in the format \"{}\"", + ), + #(format_description_display.as_str()) + ) + } + + fn visit_str<E: ::serde::de::Error>( + self, + value: &str + ) -> Result<__TimeSerdeType, E> { + __TimeSerdeType::parse(value, &DESCRIPTION).map_err(E::custom) + } + } + + impl<'a> ::serde::de::Visitor<'a> for OptionVisitor { + type Value = Option<__TimeSerdeType>; + + fn expecting(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!( + f, + concat!( + "an `Option<", + #(ty_s), + ">` in the format \"{}\"", + ), + #(format_description_display.as_str()) + ) + } + + fn visit_some<D: ::serde::de::Deserializer<'a>>( + self, + deserializer: D + ) -> Result<Option<__TimeSerdeType>, D::Error> { + deserializer + .deserialize_any(Visitor) + .map(Some) + } + + fn visit_none<E: ::serde::de::Error>( + self + ) -> Result<Option<__TimeSerdeType>, E> { + Ok(None) + } + } + } + } else { + quote!() + }; + + let serialize_primary = if cfg!(feature = "formatting") { + quote! { + pub fn serialize<S: ::serde::Serializer>( + datetime: &__TimeSerdeType, + serializer: S, + ) -> Result<S::Ok, S::Error> { + use ::serde::Serialize; + datetime + .format(&DESCRIPTION) + .map_err(::time::error::Format::into_invalid_serde_value::<S>)? + .serialize(serializer) + } + } + } else { + quote!() + }; + + let deserialize_primary = if cfg!(feature = "parsing") { + quote! { + pub fn deserialize<'a, D: ::serde::Deserializer<'a>>( + deserializer: D + ) -> Result<__TimeSerdeType, D::Error> { + use ::serde::Deserialize; + deserializer.deserialize_any(Visitor) + } + } + } else { + quote!() + }; + + let serialize_option = if cfg!(feature = "formatting") { + quote! { + pub fn serialize<S: ::serde::Serializer>( + option: &Option<__TimeSerdeType>, + serializer: S, + ) -> Result<S::Ok, S::Error> { + use ::serde::Serialize; + option.map(|datetime| datetime.format(&DESCRIPTION)) + .transpose() + .map_err(::time::error::Format::into_invalid_serde_value::<S>)? + .serialize(serializer) + } + } + } else { + quote!() + }; + + let deserialize_option = if cfg!(feature = "parsing") { + quote! { + pub fn deserialize<'a, D: ::serde::Deserializer<'a>>( + deserializer: D + ) -> Result<Option<__TimeSerdeType>, D::Error> { + use ::serde::Deserialize; + deserializer.deserialize_option(OptionVisitor) + } + } + } else { + quote!() + }; + + let deserialize_option_imports = if cfg!(feature = "parsing") { + quote! { + use super::{OptionVisitor, Visitor}; + } + } else { + quote!() + }; + + quote! { + mod #(mod_name) { + use ::time::#(ty) as __TimeSerdeType; + + const DESCRIPTION: &[::time::format_description::FormatItem<'_>] = #S(format); + + #S(visitor) + #S(serialize_primary) + #S(deserialize_primary) + + pub(super) mod option { + use super::{DESCRIPTION, __TimeSerdeType}; + #S(deserialize_option_imports) + + #S(serialize_option) + #S(deserialize_option) + } + } + } +} |