icu_datetime/provider/pattern/common/
serde.rs

1// This file is part of ICU4X. For terms of use, please see the file
2// called LICENSE at the top level of the ICU4X source tree
3// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5use super::super::{PatternItem, TimeGranularity};
6use ::serde::{de, Deserialize, Deserializer};
7use alloc::{fmt, format, vec::Vec};
8
9#[cfg(feature = "datagen")]
10use ::serde::{ser, Serialize};
11
12mod reference {
13    use super::super::super::reference::Pattern;
14    use super::*;
15
16    /// A helper struct that is shaped exactly like `runtime::Pattern`
17    /// and is used to aid in quick deserialization.
18    #[derive(Debug, Clone, PartialEq, Deserialize)]
19    #[cfg_attr(feature = "datagen", derive(Serialize))]
20    struct PatternForSerde {
21        items: Vec<PatternItem>,
22        time_granularity: TimeGranularity,
23    }
24
25    impl From<PatternForSerde> for Pattern {
26        fn from(pfs: PatternForSerde) -> Self {
27            Self {
28                items: pfs.items,
29                time_granularity: pfs.time_granularity,
30            }
31        }
32    }
33
34    impl From<&Pattern> for PatternForSerde {
35        fn from(pfs: &Pattern) -> Self {
36            Self {
37                items: pfs.items.clone(),
38                time_granularity: pfs.time_granularity,
39            }
40        }
41    }
42
43    #[allow(clippy::upper_case_acronyms)]
44    pub(crate) struct DeserializePatternUTS35String;
45
46    impl de::Visitor<'_> for DeserializePatternUTS35String {
47        type Value = Pattern;
48
49        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
50            write!(formatter, "a valid pattern.")
51        }
52
53        fn visit_str<E>(self, pattern_string: &str) -> Result<Self::Value, E>
54        where
55            E: de::Error,
56        {
57            // Parse a string into a list of fields.
58            pattern_string.parse().map_err(|err| {
59                de::Error::invalid_value(
60                    de::Unexpected::Other(&format!("{err}")),
61                    &"a valid UTS 35 pattern string",
62                )
63            })
64        }
65    }
66
67    impl<'de> Deserialize<'de> for Pattern {
68        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
69        where
70            D: Deserializer<'de>,
71        {
72            if deserializer.is_human_readable() {
73                deserializer.deserialize_str(DeserializePatternUTS35String)
74            } else {
75                let pattern = PatternForSerde::deserialize(deserializer)?;
76                Ok(Pattern::from(pattern))
77            }
78        }
79    }
80
81    #[cfg(feature = "datagen")]
82    impl Serialize for Pattern {
83        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
84        where
85            S: ser::Serializer,
86        {
87            if serializer.is_human_readable() {
88                serializer.serialize_str(&self.to_runtime_pattern().to_string())
89            } else {
90                let pfs = PatternForSerde::from(self);
91                pfs.serialize(serializer)
92            }
93        }
94    }
95
96    #[cfg(all(test, feature = "datagen"))]
97    mod test {
98        use super::*;
99
100        #[test]
101        fn reference_pattern_serde_human_readable_test() {
102            let pattern: Pattern = "y-M-d HH:mm".parse().expect("Failed to parse pattern");
103            let json = serde_json::to_string(&pattern).expect("Failed to serialize pattern");
104            let result: Pattern =
105                serde_json::from_str(&json).expect("Failed to deserialize pattern");
106            assert_eq!(pattern, result);
107        }
108
109        #[test]
110        fn reference_pattern_serde_bincode_test() {
111            let pattern: Pattern = "y-M-d HH:mm".parse().expect("Failed to parse pattern");
112            let bytes = bincode::serialize(&pattern).expect("Failed to serialize pattern");
113            let result: Pattern =
114                bincode::deserialize(&bytes).expect("Failed to deserialize pattern");
115            assert_eq!(pattern, result);
116        }
117    }
118}
119
120mod runtime {
121    use super::super::super::{runtime::Pattern, runtime::PatternMetadata, PatternItem};
122    use super::*;
123    use zerovec::ZeroVec;
124
125    /// A helper struct that is shaped exactly like `runtime::Pattern`
126    /// and is used to aid in quick deserialization.
127    #[derive(Debug, Clone, PartialEq, Deserialize)]
128    #[cfg_attr(feature = "datagen", derive(Serialize))]
129    struct PatternForSerde<'data> {
130        #[serde(borrow)]
131        pub items: ZeroVec<'data, PatternItem>,
132        pub time_granularity: TimeGranularity,
133    }
134
135    impl<'data> From<PatternForSerde<'data>> for Pattern<'data> {
136        fn from(pfs: PatternForSerde<'data>) -> Self {
137            Self {
138                items: pfs.items,
139                metadata: PatternMetadata::from_time_granularity(pfs.time_granularity),
140            }
141        }
142    }
143
144    #[allow(clippy::upper_case_acronyms)]
145    struct DeserializePatternUTS35String;
146
147    impl<'de> de::Visitor<'de> for DeserializePatternUTS35String {
148        type Value = Pattern<'de>;
149
150        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
151            write!(formatter, "a valid pattern.")
152        }
153
154        fn visit_str<E>(self, pattern_string: &str) -> Result<Self::Value, E>
155        where
156            E: de::Error,
157        {
158            // Parse a string into a list of fields.
159            let reference_deserializer = super::reference::DeserializePatternUTS35String;
160            let pattern = reference_deserializer.visit_str(pattern_string)?;
161
162            Ok(Self::Value::from(&pattern))
163        }
164    }
165
166    impl<'de: 'data, 'data> Deserialize<'de> for Pattern<'data> {
167        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
168        where
169            D: Deserializer<'de>,
170        {
171            if deserializer.is_human_readable() {
172                deserializer.deserialize_str(DeserializePatternUTS35String)
173            } else {
174                let pattern = PatternForSerde::deserialize(deserializer)?;
175                Ok(Pattern::from(pattern))
176            }
177        }
178    }
179
180    #[cfg(feature = "datagen")]
181    impl Serialize for Pattern<'_> {
182        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
183        where
184            S: ser::Serializer,
185        {
186            if serializer.is_human_readable() {
187                serializer.serialize_str(&self.to_string())
188            } else {
189                let pfs = PatternForSerde {
190                    items: self.items.clone(),
191                    time_granularity: self.metadata.time_granularity(),
192                };
193                pfs.serialize(serializer)
194            }
195        }
196    }
197
198    #[cfg(all(test, feature = "datagen"))]
199    mod test {
200        use super::*;
201
202        #[test]
203        fn runtime_pattern_serde_human_readable_test() {
204            let pattern: Pattern = "y-M-d HH:mm".parse().expect("Failed to parse pattern");
205            let json = serde_json::to_string(&pattern).expect("Failed to serialize pattern");
206            let result: Pattern =
207                serde_json::from_str(&json).expect("Failed to deserialize pattern");
208            assert_eq!(pattern, result);
209        }
210
211        #[test]
212        fn runtime_pattern_serde_bincode_test() {
213            let pattern: Pattern = "y-M-d HH:mm".parse().expect("Failed to parse pattern");
214            let bytes = bincode::serialize(&pattern).expect("Failed to serialize pattern");
215            let result: Pattern =
216                bincode::deserialize(&bytes).expect("Failed to deserialize pattern");
217            assert_eq!(pattern, result);
218        }
219    }
220
221    mod generic {
222        use super::super::super::super::runtime::GenericPattern;
223        use super::*;
224
225        #[allow(clippy::upper_case_acronyms)]
226        struct DeserializeGenericPatternUTS35String;
227
228        impl<'de> de::Visitor<'de> for DeserializeGenericPatternUTS35String {
229            type Value = GenericPattern<'de>;
230
231            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
232                write!(formatter, "a valid pattern.")
233            }
234
235            fn visit_str<E>(self, pattern_string: &str) -> Result<Self::Value, E>
236            where
237                E: de::Error,
238            {
239                // Parse a string into a list of fields.
240                let pattern = pattern_string
241                    .parse()
242                    .map_err(|_| E::custom("Failed to parse pattern"))?;
243                Ok(GenericPattern::from(&pattern))
244            }
245        }
246
247        impl<'de: 'data, 'data> Deserialize<'de> for GenericPattern<'data> {
248            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
249            where
250                D: Deserializer<'de>,
251            {
252                if deserializer.is_human_readable() {
253                    deserializer.deserialize_str(DeserializeGenericPatternUTS35String)
254                } else {
255                    let items = ZeroVec::deserialize(deserializer)?;
256                    Ok(Self { items })
257                }
258            }
259        }
260
261        #[cfg(feature = "datagen")]
262        impl Serialize for GenericPattern<'_> {
263            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
264            where
265                S: ser::Serializer,
266            {
267                if serializer.is_human_readable() {
268                    // Serialize into the UTS 35 string representation.
269                    let string = self.to_string();
270                    serializer.serialize_str(&string)
271                } else {
272                    self.items.serialize(serializer)
273                }
274            }
275        }
276
277        #[cfg(all(test, feature = "datagen"))]
278        mod test {
279            use super::*;
280
281            #[test]
282            fn runtime_generic_pattern_serde_human_readable_test() {
283                let pattern: GenericPattern =
284                    "{0} 'and' {1}".parse().expect("Failed to parse pattern");
285                let json = serde_json::to_string(&pattern).expect("Failed to serialize pattern");
286                let result: GenericPattern =
287                    serde_json::from_str(&json).expect("Failed to deserialize pattern");
288                assert_eq!(pattern, result);
289            }
290
291            #[test]
292            fn runtime_generic_pattern_serde_bincode_test() {
293                let pattern: GenericPattern =
294                    "{0} 'and' {1}".parse().expect("Failed to parse pattern");
295                let bytes = bincode::serialize(&pattern).expect("Failed to serialize pattern");
296                let result: GenericPattern =
297                    bincode::deserialize(&bytes).expect("Failed to deserialize pattern");
298                assert_eq!(pattern, result);
299            }
300        }
301    }
302}