time_macros/
serde_format_description.rs

1use proc_macro::{Ident, TokenStream, TokenTree};
2
3pub(crate) fn build(
4    mod_name: Ident,
5    ty: TokenTree,
6    format: TokenStream,
7    format_description_display: String,
8) -> TokenStream {
9    let ty_s = &*ty.to_string();
10
11    let visitor = if cfg!(feature = "parsing") {
12        quote! {
13            struct Visitor;
14            struct OptionVisitor;
15
16            impl<'a> ::serde::de::Visitor<'a> for Visitor {
17                type Value = __TimeSerdeType;
18
19                fn expecting(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
20                    write!(
21                        f,
22                        concat!(
23                            "a(n) `",
24                            #(ty_s),
25                            "` in the format \"{}\"",
26                        ),
27                        #(format_description_display.as_str())
28                    )
29                }
30
31                fn visit_str<E: ::serde::de::Error>(
32                    self,
33                    value: &str
34                ) -> Result<__TimeSerdeType, E> {
35                    __TimeSerdeType::parse(value, &description()).map_err(E::custom)
36                }
37            }
38
39            impl<'a> ::serde::de::Visitor<'a> for OptionVisitor {
40                type Value = Option<__TimeSerdeType>;
41
42                fn expecting(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
43                    write!(
44                        f,
45                        concat!(
46                            "an `Option<",
47                            #(ty_s),
48                            ">` in the format \"{}\"",
49                        ),
50                        #(format_description_display.as_str())
51                    )
52                }
53
54                fn visit_some<D: ::serde::de::Deserializer<'a>>(
55                    self,
56                    deserializer: D
57                ) -> Result<Option<__TimeSerdeType>, D::Error> {
58                    deserializer
59                        .deserialize_str(Visitor)
60                        .map(Some)
61                }
62
63                fn visit_none<E: ::serde::de::Error>(
64                    self
65                ) -> Result<Option<__TimeSerdeType>, E> {
66                    Ok(None)
67                }
68            }
69        }
70    } else {
71        quote!()
72    };
73
74    let serialize_primary = if cfg!(feature = "formatting") {
75        quote! {
76            pub fn serialize<S: ::serde::Serializer>(
77                datetime: &__TimeSerdeType,
78                serializer: S,
79            ) -> Result<S::Ok, S::Error> {
80                use ::serde::Serialize;
81                datetime
82                    .format(&description())
83                    .map_err(::time::error::Format::into_invalid_serde_value::<S>)?
84                    .serialize(serializer)
85            }
86        }
87    } else {
88        quote!()
89    };
90
91    let deserialize_primary = if cfg!(feature = "parsing") {
92        quote! {
93            pub fn deserialize<'a, D: ::serde::Deserializer<'a>>(
94                deserializer: D
95            ) -> Result<__TimeSerdeType, D::Error> {
96                use ::serde::Deserialize;
97                deserializer.deserialize_str(Visitor)
98            }
99        }
100    } else {
101        quote!()
102    };
103
104    let serialize_option = if cfg!(feature = "formatting") {
105        quote! {
106            pub fn serialize<S: ::serde::Serializer>(
107                option: &Option<__TimeSerdeType>,
108                serializer: S,
109            ) -> Result<S::Ok, S::Error> {
110                use ::serde::Serialize;
111                option.map(|datetime| datetime.format(&description()))
112                    .transpose()
113                    .map_err(::time::error::Format::into_invalid_serde_value::<S>)?
114                    .serialize(serializer)
115            }
116        }
117    } else {
118        quote!()
119    };
120
121    let deserialize_option = if cfg!(feature = "parsing") {
122        quote! {
123            pub fn deserialize<'a, D: ::serde::Deserializer<'a>>(
124                deserializer: D
125            ) -> Result<Option<__TimeSerdeType>, D::Error> {
126                use ::serde::Deserialize;
127                deserializer.deserialize_option(OptionVisitor)
128            }
129        }
130    } else {
131        quote!()
132    };
133
134    let deserialize_option_imports = if cfg!(feature = "parsing") {
135        quote! {
136            use super::{OptionVisitor, Visitor};
137        }
138    } else {
139        quote!()
140    };
141
142    let fd_traits = match (cfg!(feature = "formatting"), cfg!(feature = "parsing")) {
143        (false, false) => {
144            bug!("serde_format_description::build called without formatting or parsing enabled")
145        }
146        (false, true) => quote! { ::time::parsing::Parsable },
147        (true, false) => quote! { ::time::formatting::Formattable },
148        (true, true) => quote! { ::time::formatting::Formattable + ::time::parsing::Parsable },
149    };
150
151    quote! {
152        mod #(mod_name) {
153            use super::*;
154            // TODO Remove the prefix, forcing the user to import the type themself.
155            use ::time::#(ty) as __TimeSerdeType;
156
157            const fn description() -> impl #S(fd_traits) {
158                #S(format)
159            }
160
161            #S(visitor)
162            #S(serialize_primary)
163            #S(deserialize_primary)
164
165            pub(super) mod option {
166                use super::{description, __TimeSerdeType};
167                #S(deserialize_option_imports)
168
169                #S(serialize_option)
170                #S(deserialize_option)
171            }
172        }
173    }
174}