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