zerotrie/
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 crate::builder::bytestr::ByteStr;
6use crate::options::ZeroTrieWithOptions;
7use crate::zerotrie::ZeroTrieFlavor;
8use crate::ZeroAsciiIgnoreCaseTrie;
9use crate::ZeroTrie;
10use crate::ZeroTrieExtendedCapacity;
11use crate::ZeroTriePerfectHash;
12use crate::ZeroTrieSimpleAscii;
13use alloc::boxed::Box;
14use alloc::vec::Vec;
15use core::fmt;
16use litemap::LiteMap;
17use serde::de::Error;
18use serde::de::Visitor;
19use serde::Deserialize;
20use serde::Deserializer;
21use serde::Serialize;
22use serde::Serializer;
23
24struct ByteStrVisitor;
25impl<'de> Visitor<'de> for ByteStrVisitor {
26    type Value = Box<[u8]>;
27    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
28        write!(formatter, "a slice of borrowed bytes or a string")
29    }
30    fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E> {
31        Ok(Box::from(v))
32    }
33    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> {
34        Ok(Box::from(v.as_bytes()))
35    }
36    fn visit_seq<A>(self, mut v: A) -> Result<Self::Value, A::Error>
37    where
38        A: serde::de::SeqAccess<'de>,
39    {
40        let mut result = Vec::with_capacity(v.size_hint().unwrap_or(0));
41        while let Some(x) = v.next_element::<u8>()? {
42            result.push(x);
43        }
44        Ok(Box::from(result))
45    }
46}
47
48impl<'data, 'de: 'data> Deserialize<'de> for &'data ByteStr {
49    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
50    where
51        D: Deserializer<'de>,
52    {
53        let s = <&'data [u8]>::deserialize(deserializer)?;
54        Ok(ByteStr::from_bytes(s))
55    }
56}
57
58impl<'de> Deserialize<'de> for Box<ByteStr> {
59    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
60    where
61        D: Deserializer<'de>,
62    {
63        if deserializer.is_human_readable() {
64            let s = deserializer.deserialize_any(ByteStrVisitor)?;
65            Ok(ByteStr::from_boxed_bytes(s))
66        } else {
67            let s = Vec::<u8>::deserialize(deserializer)?;
68            Ok(ByteStr::from_boxed_bytes(s.into_boxed_slice()))
69        }
70    }
71}
72
73impl Serialize for &ByteStr {
74    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
75    where
76        S: Serializer,
77    {
78        let bytes = self.as_bytes();
79        if serializer.is_human_readable() {
80            match core::str::from_utf8(bytes) {
81                Ok(s) => serializer.serialize_str(s),
82                Err(_) => serializer.serialize_bytes(bytes),
83            }
84        } else {
85            serializer.serialize_bytes(bytes)
86        }
87    }
88}
89
90impl<'data, 'de: 'data, Store> Deserialize<'de> for ZeroTrieSimpleAscii<Store>
91where
92    // DISCUSS: There are several possibilities for the bounds here that would
93    // get the job done. I could look for Deserialize, but this would require
94    // creating a custom Deserializer for the map case. I also considered
95    // introducing a new trait instead of relying on From.
96    Store: From<&'data [u8]> + From<Vec<u8>> + 'data,
97{
98    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
99    where
100        D: Deserializer<'de>,
101    {
102        if deserializer.is_human_readable() {
103            let lm = LiteMap::<Box<ByteStr>, usize>::deserialize(deserializer)?;
104            ZeroTrieSimpleAscii::try_from_serde_litemap(&lm)
105                .map_err(D::Error::custom)
106                .map(|trie| trie.convert_store())
107        } else {
108            // Note: `impl Deserialize for &[u8]` uses visit_borrowed_bytes
109            let (flags, trie_bytes) = <(u8, &[u8])>::deserialize(deserializer)?;
110            if Self::OPTIONS.to_u8_flags() != flags {
111                return Err(D::Error::custom("invalid ZeroTrie tag"));
112            };
113            Ok(ZeroTrieSimpleAscii::from_store(Store::from(trie_bytes)))
114        }
115    }
116}
117
118impl<Store> Serialize for ZeroTrieSimpleAscii<Store>
119where
120    Store: AsRef<[u8]>,
121{
122    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
123    where
124        S: Serializer,
125    {
126        if serializer.is_human_readable() {
127            let lm = self.to_litemap();
128            lm.serialize(serializer)
129        } else {
130            // Note: `impl Serialize for ByteStr` uses `serialize_bytes`
131            (Self::FLAGS, ByteStr::from_bytes(self.as_bytes())).serialize(serializer)
132        }
133    }
134}
135
136impl<'de, 'data, Store> Deserialize<'de> for ZeroAsciiIgnoreCaseTrie<Store>
137where
138    'de: 'data,
139    // DISCUSS: There are several possibilities for the bounds here that would
140    // get the job done. I could look for Deserialize, but this would require
141    // creating a custom Deserializer for the map case. I also considered
142    // introducing a new trait instead of relying on From.
143    Store: From<&'data [u8]> + From<Vec<u8>> + 'data,
144{
145    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
146    where
147        D: Deserializer<'de>,
148    {
149        if deserializer.is_human_readable() {
150            let lm = LiteMap::<Box<ByteStr>, usize>::deserialize(deserializer)?;
151            ZeroAsciiIgnoreCaseTrie::try_from_serde_litemap(&lm)
152                .map_err(D::Error::custom)
153                .map(|trie| trie.convert_store())
154        } else {
155            // Note: `impl Deserialize for &[u8]` uses visit_borrowed_bytes
156            let (flags, trie_bytes) = <(u8, &[u8])>::deserialize(deserializer)?;
157            if Self::OPTIONS.to_u8_flags() != flags {
158                return Err(D::Error::custom("invalid ZeroTrie tag"));
159            }
160            Ok(ZeroAsciiIgnoreCaseTrie::from_store(Store::from(trie_bytes)))
161        }
162    }
163}
164
165impl<Store> Serialize for ZeroAsciiIgnoreCaseTrie<Store>
166where
167    Store: AsRef<[u8]>,
168{
169    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
170    where
171        S: Serializer,
172    {
173        if serializer.is_human_readable() {
174            let lm = self.to_litemap();
175            lm.serialize(serializer)
176        } else {
177            // Note: `impl Serialize for ByteStr` uses `serialize_bytes`
178            (
179                Self::OPTIONS.to_u8_flags(),
180                ByteStr::from_bytes(self.as_bytes()),
181            )
182                .serialize(serializer)
183        }
184    }
185}
186
187impl<'de, 'data, Store> Deserialize<'de> for ZeroTriePerfectHash<Store>
188where
189    'de: 'data,
190    Store: From<&'data [u8]> + From<Vec<u8>> + 'data,
191{
192    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
193    where
194        D: Deserializer<'de>,
195    {
196        if deserializer.is_human_readable() {
197            let lm = LiteMap::<Box<ByteStr>, usize>::deserialize(deserializer)?;
198            ZeroTriePerfectHash::try_from_serde_litemap(&lm)
199                .map_err(D::Error::custom)
200                .map(|trie| trie.convert_store())
201        } else {
202            // Note: `impl Deserialize for &[u8]` uses visit_borrowed_bytes
203            let (flags, trie_bytes) = <(u8, &[u8])>::deserialize(deserializer)?;
204            if Self::OPTIONS.to_u8_flags() != flags {
205                return Err(D::Error::custom("invalid ZeroTrie tag"));
206            }
207            Ok(ZeroTriePerfectHash::from_store(Store::from(trie_bytes)))
208        }
209    }
210}
211
212impl<Store> Serialize for ZeroTriePerfectHash<Store>
213where
214    Store: AsRef<[u8]>,
215{
216    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
217    where
218        S: Serializer,
219    {
220        if serializer.is_human_readable() {
221            let lm = self.to_litemap();
222            let lm = lm
223                .iter()
224                .map(|(k, v)| (ByteStr::from_bytes(k), v))
225                .collect::<LiteMap<_, _>>();
226            lm.serialize(serializer)
227        } else {
228            // Note: `impl Serialize for ByteStr` uses `serialize_bytes`
229            (
230                Self::OPTIONS.to_u8_flags(),
231                ByteStr::from_bytes(self.as_bytes()),
232            )
233                .serialize(serializer)
234        }
235    }
236}
237
238impl<'de, 'data, Store> Deserialize<'de> for ZeroTrieExtendedCapacity<Store>
239where
240    'de: 'data,
241    Store: From<&'data [u8]> + From<Vec<u8>> + 'data,
242{
243    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
244    where
245        D: Deserializer<'de>,
246    {
247        if deserializer.is_human_readable() {
248            let lm = LiteMap::<Box<ByteStr>, usize>::deserialize(deserializer)?;
249            ZeroTrieExtendedCapacity::try_from_serde_litemap(&lm)
250                .map_err(D::Error::custom)
251                .map(|trie| trie.convert_store())
252        } else {
253            // Note: `impl Deserialize for &[u8]` uses visit_borrowed_bytes
254            let (flags, trie_bytes) = <(u8, &[u8])>::deserialize(deserializer)?;
255            if Self::OPTIONS.to_u8_flags() != flags {
256                return Err(D::Error::custom("invalid ZeroTrie tag"));
257            }
258            Ok(ZeroTrieExtendedCapacity::from_store(Store::from(
259                trie_bytes,
260            )))
261        }
262    }
263}
264
265impl<Store> Serialize for ZeroTrieExtendedCapacity<Store>
266where
267    Store: AsRef<[u8]>,
268{
269    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
270    where
271        S: Serializer,
272    {
273        if serializer.is_human_readable() {
274            let lm = self.to_litemap();
275            let lm = lm
276                .iter()
277                .map(|(k, v)| (ByteStr::from_bytes(k), v))
278                .collect::<LiteMap<_, _>>();
279            lm.serialize(serializer)
280        } else {
281            // Note: `impl Serialize for ByteStr` uses `serialize_bytes`
282            (
283                Self::OPTIONS.to_u8_flags(),
284                ByteStr::from_bytes(self.as_bytes()),
285            )
286                .serialize(serializer)
287        }
288    }
289}
290
291impl<'de, 'data, Store> Deserialize<'de> for ZeroTrie<Store>
292where
293    'de: 'data,
294    Store: From<&'data [u8]> + From<Vec<u8>> + 'data,
295{
296    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
297    where
298        D: Deserializer<'de>,
299    {
300        if deserializer.is_human_readable() {
301            let lm = LiteMap::<Box<ByteStr>, usize>::deserialize(deserializer)?;
302            ZeroTrie::<Vec<u8>>::try_from(&lm)
303                .map_err(D::Error::custom)
304                .map(|trie| trie.convert_store())
305        } else {
306            // Note: `impl Deserialize for &[u8]` uses visit_borrowed_bytes
307            let bytes = <&[u8]>::deserialize(deserializer)?;
308            let (tag, trie_bytes) = bytes
309                .split_first()
310                .ok_or(D::Error::custom("expected at least 1 byte for ZeroTrie"))?;
311            let store = Store::from(trie_bytes);
312            let zerotrie = if *tag == ZeroTrieSimpleAscii::<u8>::OPTIONS.to_u8_flags() {
313                ZeroTrieSimpleAscii::from_store(store).into_zerotrie()
314            } else if *tag == ZeroTriePerfectHash::<u8>::OPTIONS.to_u8_flags() {
315                ZeroTriePerfectHash::from_store(store).into_zerotrie()
316            } else if *tag == ZeroTrieExtendedCapacity::<u8>::OPTIONS.to_u8_flags() {
317                ZeroTrieExtendedCapacity::from_store(store).into_zerotrie()
318            } else {
319                return Err(D::Error::custom("invalid ZeroTrie tag"));
320            };
321            Ok(zerotrie)
322        }
323    }
324}
325
326impl<Store> Serialize for ZeroTrie<Store>
327where
328    Store: AsRef<[u8]>,
329{
330    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
331    where
332        S: Serializer,
333    {
334        if serializer.is_human_readable() {
335            let lm = self.to_litemap();
336            let lm = lm
337                .iter()
338                .map(|(k, v)| (ByteStr::from_bytes(k), v))
339                .collect::<LiteMap<_, _>>();
340            lm.serialize(serializer)
341        } else {
342            let (tag, bytes) = match &self.0 {
343                ZeroTrieFlavor::SimpleAscii(t) => (
344                    ZeroTrieSimpleAscii::<u8>::OPTIONS.to_u8_flags(),
345                    t.as_bytes(),
346                ),
347                ZeroTrieFlavor::PerfectHash(t) => (
348                    ZeroTriePerfectHash::<u8>::OPTIONS.to_u8_flags(),
349                    t.as_bytes(),
350                ),
351                ZeroTrieFlavor::ExtendedCapacity(t) => (
352                    ZeroTrieExtendedCapacity::<u8>::OPTIONS.to_u8_flags(),
353                    t.as_bytes(),
354                ),
355            };
356            let mut all_in_one_vec = Vec::with_capacity(bytes.len() + 1);
357            all_in_one_vec.push(tag);
358            all_in_one_vec.extend(bytes);
359            serializer.serialize_bytes(&all_in_one_vec)
360        }
361    }
362}
363
364#[cfg(test)]
365mod testdata {
366    include!("../tests/data/data.rs");
367}
368
369#[cfg(test)]
370mod tests {
371    use super::*;
372    use alloc::borrow::Cow;
373
374    #[derive(Serialize, Deserialize)]
375    pub struct ZeroTrieSimpleAsciiCow<'a> {
376        #[serde(borrow)]
377        trie: ZeroTrieSimpleAscii<Cow<'a, [u8]>>,
378    }
379
380    #[test]
381    pub fn test_serde_simpleascii_cow() {
382        let trie = ZeroTrieSimpleAscii::from_store(Cow::from(testdata::basic::TRIE_ASCII));
383        let original = ZeroTrieSimpleAsciiCow { trie };
384        let json_str = serde_json::to_string(&original).unwrap();
385        let bincode_bytes = bincode::serialize(&original).unwrap();
386        let rmp_bytes = rmp_serde::to_vec(&original).unwrap();
387
388        assert_eq!(json_str, testdata::basic::JSON_STR_ASCII);
389        assert_eq!(&bincode_bytes[0..9], &[0, 26, 0, 0, 0, 0, 0, 0, 0]);
390        assert_eq!(&bincode_bytes[9..], testdata::basic::BINCODE_BYTES_ASCII);
391        assert_eq!(&rmp_bytes[0..5], &[145, 146, 0, 196, 26]);
392        assert_eq!(&rmp_bytes[5..], testdata::basic::BINCODE_BYTES_ASCII);
393
394        let json_recovered: ZeroTrieSimpleAsciiCow = serde_json::from_str(&json_str).unwrap();
395        let bincode_recovered: ZeroTrieSimpleAsciiCow =
396            bincode::deserialize(&bincode_bytes).unwrap();
397        let rmp_recovered: ZeroTrieSimpleAsciiCow = rmp_serde::from_slice(&rmp_bytes).unwrap();
398
399        assert_eq!(original.trie, json_recovered.trie);
400        assert_eq!(original.trie, bincode_recovered.trie);
401        assert_eq!(original.trie, rmp_recovered.trie);
402
403        assert!(matches!(json_recovered.trie.into_store(), Cow::Owned(_)));
404        assert!(matches!(
405            bincode_recovered.trie.into_store(),
406            Cow::Borrowed(_)
407        ));
408    }
409
410    #[derive(Serialize, Deserialize)]
411    pub struct ZeroAsciiIgnoreCaseTrieCow<'a> {
412        #[serde(borrow)]
413        trie: ZeroAsciiIgnoreCaseTrie<Cow<'a, [u8]>>,
414    }
415
416    #[test]
417    pub fn test_serde_asciiignorecase_cow() {
418        let trie = ZeroAsciiIgnoreCaseTrie::from_store(Cow::from(testdata::basic::TRIE_ASCII));
419        let original = ZeroAsciiIgnoreCaseTrieCow { trie };
420        let json_str = serde_json::to_string(&original).unwrap();
421        let bincode_bytes = bincode::serialize(&original).unwrap();
422
423        assert_eq!(json_str, testdata::basic::JSON_STR_ASCII);
424        assert_eq!(&bincode_bytes[0..9], &[8, 26, 0, 0, 0, 0, 0, 0, 0]);
425        assert_eq!(&bincode_bytes[9..], testdata::basic::BINCODE_BYTES_ASCII);
426
427        let json_recovered: ZeroAsciiIgnoreCaseTrieCow = serde_json::from_str(&json_str).unwrap();
428        let bincode_recovered: ZeroAsciiIgnoreCaseTrieCow =
429            bincode::deserialize(&bincode_bytes).unwrap();
430
431        assert_eq!(original.trie, json_recovered.trie);
432        assert_eq!(original.trie, bincode_recovered.trie);
433
434        assert!(matches!(json_recovered.trie.into_store(), Cow::Owned(_)));
435        assert!(matches!(
436            bincode_recovered.trie.into_store(),
437            Cow::Borrowed(_)
438        ));
439    }
440
441    #[derive(Serialize, Deserialize)]
442    pub struct ZeroTriePerfectHashCow<'a> {
443        #[serde(borrow)]
444        trie: ZeroTriePerfectHash<Cow<'a, [u8]>>,
445    }
446
447    #[test]
448    pub fn test_serde_perfecthash_cow() {
449        let trie = ZeroTriePerfectHash::from_store(Cow::from(testdata::basic::TRIE_ASCII));
450        let original = ZeroTriePerfectHashCow { trie };
451        let json_str = serde_json::to_string(&original).unwrap();
452        let bincode_bytes = bincode::serialize(&original).unwrap();
453
454        assert_eq!(json_str, testdata::basic::JSON_STR_ASCII);
455        assert_eq!(&bincode_bytes[0..9], &[3, 26, 0, 0, 0, 0, 0, 0, 0]);
456        assert_eq!(&bincode_bytes[9..], testdata::basic::BINCODE_BYTES_ASCII);
457
458        let json_recovered: ZeroTriePerfectHashCow = serde_json::from_str(&json_str).unwrap();
459        let bincode_recovered: ZeroTriePerfectHashCow =
460            bincode::deserialize(&bincode_bytes).unwrap();
461
462        assert_eq!(original.trie, json_recovered.trie);
463        assert_eq!(original.trie, bincode_recovered.trie);
464
465        assert!(matches!(json_recovered.trie.into_store(), Cow::Owned(_)));
466        assert!(matches!(
467            bincode_recovered.trie.into_store(),
468            Cow::Borrowed(_)
469        ));
470    }
471
472    #[test]
473    pub fn test_serde_perfecthash_cow_u() {
474        let trie = ZeroTriePerfectHash::from_store(Cow::from(testdata::basic::TRIE_UNICODE));
475        let original = ZeroTriePerfectHashCow { trie };
476        let json_str = serde_json::to_string(&original).unwrap();
477        let bincode_bytes = bincode::serialize(&original).unwrap();
478
479        assert_eq!(json_str, testdata::basic::JSON_STR_UNICODE);
480        assert_eq!(&bincode_bytes[0..9], &[3, 39, 0, 0, 0, 0, 0, 0, 0]);
481        assert_eq!(&bincode_bytes[9..], testdata::basic::BINCODE_BYTES_UNICODE);
482
483        let json_recovered: ZeroTriePerfectHashCow = serde_json::from_str(&json_str).unwrap();
484        let bincode_recovered: ZeroTriePerfectHashCow =
485            bincode::deserialize(&bincode_bytes).unwrap();
486
487        assert_eq!(original.trie, json_recovered.trie);
488        assert_eq!(original.trie, bincode_recovered.trie);
489
490        assert!(matches!(json_recovered.trie.into_store(), Cow::Owned(_)));
491        assert!(matches!(
492            bincode_recovered.trie.into_store(),
493            Cow::Borrowed(_)
494        ));
495    }
496
497    #[test]
498    pub fn test_serde_perfecthash_cow_bin() {
499        let trie = ZeroTriePerfectHash::from_store(Cow::from(testdata::basic::TRIE_BINARY));
500        let original = ZeroTriePerfectHashCow { trie };
501        let json_str = serde_json::to_string(&original).unwrap();
502        let bincode_bytes = bincode::serialize(&original).unwrap();
503
504        assert_eq!(json_str, testdata::basic::JSON_STR_BINARY);
505        assert_eq!(&bincode_bytes[0..9], &[3, 26, 0, 0, 0, 0, 0, 0, 0]);
506        assert_eq!(&bincode_bytes[9..], testdata::basic::BINCODE_BYTES_BINARY);
507
508        let json_recovered: ZeroTriePerfectHashCow = serde_json::from_str(&json_str).unwrap();
509        let bincode_recovered: ZeroTriePerfectHashCow =
510            bincode::deserialize(&bincode_bytes).unwrap();
511
512        assert_eq!(original.trie, json_recovered.trie);
513        assert_eq!(original.trie, bincode_recovered.trie);
514
515        assert!(matches!(json_recovered.trie.into_store(), Cow::Owned(_)));
516        assert!(matches!(
517            bincode_recovered.trie.into_store(),
518            Cow::Borrowed(_)
519        ));
520    }
521
522    #[derive(Serialize, Deserialize)]
523    pub struct ZeroTrieAnyCow<'a> {
524        #[serde(borrow)]
525        trie: ZeroTrie<Cow<'a, [u8]>>,
526    }
527
528    #[test]
529    pub fn test_serde_any_cow() {
530        let trie =
531            ZeroTrieSimpleAscii::from_store(Cow::from(testdata::basic::TRIE_ASCII)).into_zerotrie();
532        let original = ZeroTrieAnyCow { trie };
533        let json_str = serde_json::to_string(&original).unwrap();
534        let bincode_bytes = bincode::serialize(&original).unwrap();
535
536        assert_eq!(json_str, testdata::basic::JSON_STR_ASCII);
537        assert_eq!(&bincode_bytes[0..9], &[27, 0, 0, 0, 0, 0, 0, 0, 0]);
538        assert_eq!(&bincode_bytes[9..], testdata::basic::BINCODE_BYTES_ASCII);
539
540        let json_recovered: ZeroTrieAnyCow = serde_json::from_str(&json_str).unwrap();
541        let bincode_recovered: ZeroTrieAnyCow = bincode::deserialize(&bincode_bytes).unwrap();
542
543        assert_eq!(original.trie, json_recovered.trie);
544        assert_eq!(original.trie, bincode_recovered.trie);
545
546        assert!(matches!(json_recovered.trie.into_store(), Cow::Owned(_)));
547        assert!(matches!(
548            bincode_recovered.trie.into_store(),
549            Cow::Borrowed(_)
550        ));
551    }
552
553    #[test]
554    pub fn test_serde_any_cow_u() {
555        let trie = ZeroTriePerfectHash::from_store(Cow::from(testdata::basic::TRIE_UNICODE))
556            .into_zerotrie();
557        let original = ZeroTrieAnyCow { trie };
558        let json_str = serde_json::to_string(&original).unwrap();
559        let bincode_bytes = bincode::serialize(&original).unwrap();
560
561        assert_eq!(json_str, testdata::basic::JSON_STR_UNICODE);
562        assert_eq!(&bincode_bytes[0..9], &[40, 0, 0, 0, 0, 0, 0, 0, 3]);
563        assert_eq!(&bincode_bytes[9..], testdata::basic::BINCODE_BYTES_UNICODE);
564
565        let json_recovered: ZeroTrieAnyCow = serde_json::from_str(&json_str).unwrap();
566        let bincode_recovered: ZeroTrieAnyCow = bincode::deserialize(&bincode_bytes).unwrap();
567
568        assert_eq!(original.trie, json_recovered.trie);
569        assert_eq!(original.trie, bincode_recovered.trie);
570
571        assert!(matches!(json_recovered.trie.into_store(), Cow::Owned(_)));
572        assert!(matches!(
573            bincode_recovered.trie.into_store(),
574            Cow::Borrowed(_)
575        ));
576    }
577}
578
579#[cfg(test)]
580#[cfg(feature = "zerovec")]
581mod tests_zerovec {
582    use super::*;
583    use zerovec::ZeroVec;
584
585    #[derive(Serialize, Deserialize)]
586    pub struct ZeroTrieSimpleAsciiZeroVec<'a> {
587        #[serde(borrow)]
588        trie: ZeroTrieSimpleAscii<ZeroVec<'a, u8>>,
589    }
590
591    #[test]
592    pub fn test_serde_simpleascii_zerovec() {
593        let trie =
594            ZeroTrieSimpleAscii::from_store(ZeroVec::new_borrowed(testdata::basic::TRIE_ASCII));
595        let original = ZeroTrieSimpleAsciiZeroVec { trie };
596        let json_str = serde_json::to_string(&original).unwrap();
597        let bincode_bytes = bincode::serialize(&original).unwrap();
598
599        assert_eq!(json_str, testdata::basic::JSON_STR_ASCII);
600        assert_eq!(&bincode_bytes[0..9], &[0, 26, 0, 0, 0, 0, 0, 0, 0]);
601        assert_eq!(&bincode_bytes[9..], testdata::basic::BINCODE_BYTES_ASCII);
602
603        let json_recovered: ZeroTrieSimpleAsciiZeroVec = serde_json::from_str(&json_str).unwrap();
604        let bincode_recovered: ZeroTrieSimpleAsciiZeroVec =
605            bincode::deserialize(&bincode_bytes).unwrap();
606
607        assert_eq!(original.trie, json_recovered.trie);
608        assert_eq!(original.trie, bincode_recovered.trie);
609
610        assert!(json_recovered.trie.into_store().is_owned());
611        assert!(!bincode_recovered.trie.into_store().is_owned());
612    }
613
614    #[derive(Serialize, Deserialize)]
615    pub struct ZeroTriePerfectHashZeroVec<'a> {
616        #[serde(borrow)]
617        trie: ZeroTriePerfectHash<ZeroVec<'a, u8>>,
618    }
619
620    #[test]
621    pub fn test_serde_perfecthash_zerovec() {
622        let trie =
623            ZeroTriePerfectHash::from_store(ZeroVec::new_borrowed(testdata::basic::TRIE_ASCII));
624        let original = ZeroTriePerfectHashZeroVec { trie };
625        let json_str = serde_json::to_string(&original).unwrap();
626        let bincode_bytes = bincode::serialize(&original).unwrap();
627
628        assert_eq!(json_str, testdata::basic::JSON_STR_ASCII);
629        assert_eq!(&bincode_bytes[0..9], &[3, 26, 0, 0, 0, 0, 0, 0, 0]);
630        assert_eq!(&bincode_bytes[9..], testdata::basic::BINCODE_BYTES_ASCII);
631
632        let json_recovered: ZeroTriePerfectHashZeroVec = serde_json::from_str(&json_str).unwrap();
633        let bincode_recovered: ZeroTriePerfectHashZeroVec =
634            bincode::deserialize(&bincode_bytes).unwrap();
635
636        assert_eq!(original.trie, json_recovered.trie);
637        assert_eq!(original.trie, bincode_recovered.trie);
638
639        assert!(json_recovered.trie.into_store().is_owned());
640        assert!(!bincode_recovered.trie.into_store().is_owned());
641    }
642}