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