zerovec/varzerovec/
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::{VarZeroSlice, VarZeroVec, VarZeroVecFormat};
6use crate::ule::*;
7use alloc::boxed::Box;
8use alloc::vec::Vec;
9use core::fmt;
10use core::marker::PhantomData;
11use serde::de::{self, Deserialize, Deserializer, SeqAccess, Visitor};
12#[cfg(feature = "serde")]
13use serde::ser::{Serialize, SerializeSeq, Serializer};
14
15struct VarZeroVecVisitor<T: ?Sized, F: VarZeroVecFormat> {
16    #[allow(clippy::type_complexity)] // this is a private marker type, who cares
17    marker: PhantomData<(fn() -> Box<T>, F)>,
18}
19
20impl<T: ?Sized, F: VarZeroVecFormat> Default for VarZeroVecVisitor<T, F> {
21    fn default() -> Self {
22        Self {
23            marker: PhantomData,
24        }
25    }
26}
27
28impl<'de, T, F> Visitor<'de> for VarZeroVecVisitor<T, F>
29where
30    T: VarULE + ?Sized,
31    Box<T>: Deserialize<'de>,
32    F: VarZeroVecFormat,
33{
34    type Value = VarZeroVec<'de, T, F>;
35
36    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
37        formatter.write_str("a sequence or borrowed buffer of bytes")
38    }
39
40    fn visit_borrowed_bytes<E>(self, bytes: &'de [u8]) -> Result<Self::Value, E>
41    where
42        E: de::Error,
43    {
44        VarZeroVec::parse_bytes(bytes).map_err(de::Error::custom)
45    }
46
47    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
48    where
49        A: SeqAccess<'de>,
50    {
51        let mut vec: Vec<Box<T>> = if let Some(capacity) = seq.size_hint() {
52            Vec::with_capacity(capacity)
53        } else {
54            Vec::new()
55        };
56        while let Some(value) = seq.next_element::<Box<T>>()? {
57            vec.push(value);
58        }
59        Ok(VarZeroVec::from(&vec))
60    }
61}
62
63/// This impl requires enabling the optional `serde` Cargo feature of the `zerovec` crate
64impl<'de, 'a, T, F> Deserialize<'de> for VarZeroVec<'a, T, F>
65where
66    T: VarULE + ?Sized,
67    Box<T>: Deserialize<'de>,
68    F: VarZeroVecFormat,
69    'de: 'a,
70{
71    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
72    where
73        D: Deserializer<'de>,
74    {
75        let visitor = VarZeroVecVisitor::<T, F>::default();
76        if deserializer.is_human_readable() {
77            deserializer.deserialize_seq(visitor)
78        } else {
79            deserializer.deserialize_bytes(visitor)
80        }
81    }
82}
83
84/// This impl requires enabling the optional `serde` Cargo feature of the `zerovec` crate
85impl<'de, 'a, T, F> Deserialize<'de> for &'a VarZeroSlice<T, F>
86where
87    T: VarULE + ?Sized,
88    F: VarZeroVecFormat,
89    'de: 'a,
90{
91    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
92    where
93        D: Deserializer<'de>,
94    {
95        if deserializer.is_human_readable() {
96            Err(de::Error::custom(
97                "&VarZeroSlice cannot be deserialized from human-readable formats",
98            ))
99        } else {
100            let bytes = <&[u8]>::deserialize(deserializer)?;
101            VarZeroSlice::<T, F>::parse_bytes(bytes).map_err(de::Error::custom)
102        }
103    }
104}
105
106/// This impl requires enabling the optional `serde` Cargo feature of the `zerovec` crate
107impl<'de, T, F> Deserialize<'de> for Box<VarZeroSlice<T, F>>
108where
109    T: VarULE + ?Sized,
110    Box<T>: Deserialize<'de>,
111    F: VarZeroVecFormat,
112{
113    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
114    where
115        D: Deserializer<'de>,
116    {
117        let deserialized = VarZeroVec::<T, F>::deserialize(deserializer)?;
118        Ok(deserialized.to_boxed())
119    }
120}
121
122/// This impl requires enabling the optional `serde` Cargo feature of the `zerovec` crate
123#[cfg(feature = "serde")]
124impl<T, F> Serialize for VarZeroVec<'_, T, F>
125where
126    T: Serialize + VarULE + ?Sized,
127    F: VarZeroVecFormat,
128{
129    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
130    where
131        S: Serializer,
132    {
133        if serializer.is_human_readable() {
134            let mut seq = serializer.serialize_seq(Some(self.len()))?;
135            for value in self.iter() {
136                seq.serialize_element(value)?;
137            }
138            seq.end()
139        } else {
140            serializer.serialize_bytes(self.as_bytes())
141        }
142    }
143}
144
145/// This impl requires enabling the optional `serde` Cargo feature of the `zerovec` crate
146#[cfg(feature = "serde")]
147impl<T, F> Serialize for VarZeroSlice<T, F>
148where
149    T: Serialize + VarULE + ?Sized,
150    F: VarZeroVecFormat,
151{
152    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
153    where
154        S: Serializer,
155    {
156        self.as_varzerovec().serialize(serializer)
157    }
158}
159
160#[cfg(test)]
161#[allow(non_camel_case_types)]
162mod test {
163    use crate::{VarZeroSlice, VarZeroVec};
164
165    #[derive(serde::Serialize, serde::Deserialize)]
166    struct DeriveTest_VarZeroVec<'data> {
167        #[serde(borrow)]
168        _data: VarZeroVec<'data, str>,
169    }
170
171    #[derive(serde::Serialize, serde::Deserialize)]
172    struct DeriveTest_VarZeroSlice<'data> {
173        #[serde(borrow)]
174        _data: &'data VarZeroSlice<str>,
175    }
176
177    #[derive(serde::Serialize, serde::Deserialize)]
178    struct DeriveTest_VarZeroVec_of_VarZeroSlice<'data> {
179        #[serde(borrow)]
180        _data: VarZeroVec<'data, VarZeroSlice<str>>,
181    }
182
183    // ["foo", "bar", "baz", "dolor", "quux", "lorem ipsum"];
184    const BYTES: &[u8] = &[
185        6, 0, 3, 0, 6, 0, 9, 0, 14, 0, 18, 0, 102, 111, 111, 98, 97, 114, 98, 97, 122, 100, 111,
186        108, 111, 114, 113, 117, 117, 120, 108, 111, 114, 101, 109, 32, 105, 112, 115, 117, 109,
187    ];
188    const JSON_STR: &str = "[\"foo\",\"bar\",\"baz\",\"dolor\",\"quux\",\"lorem ipsum\"]";
189    const BINCODE_BUF: &[u8] = &[
190        41, 0, 0, 0, 0, 0, 0, 0, 6, 0, 3, 0, 6, 0, 9, 0, 14, 0, 18, 0, 102, 111, 111, 98, 97, 114,
191        98, 97, 122, 100, 111, 108, 111, 114, 113, 117, 117, 120, 108, 111, 114, 101, 109, 32, 105,
192        112, 115, 117, 109,
193    ];
194
195    // ["w", "ω", "文", "𑄃"]
196    const NONASCII_STR: &[&str] = &["w", "ω", "文", "𑄃"];
197    const NONASCII_BYTES: &[u8] = &[
198        4, 0, 1, 0, 3, 0, 6, 0, 119, 207, 137, 230, 150, 135, 240, 145, 132, 131,
199    ];
200    #[test]
201    fn test_serde_json() {
202        let zerovec_orig: VarZeroVec<str> = VarZeroVec::parse_bytes(BYTES).expect("parse");
203        let json_str = serde_json::to_string(&zerovec_orig).expect("serialize");
204        assert_eq!(JSON_STR, json_str);
205        // VarZeroVec should deserialize from JSON to either Vec or VarZeroVec
206        let vec_new: Vec<Box<str>> =
207            serde_json::from_str(&json_str).expect("deserialize from buffer to Vec");
208        assert_eq!(zerovec_orig.to_vec(), vec_new);
209        let zerovec_new: VarZeroVec<str> =
210            serde_json::from_str(&json_str).expect("deserialize from buffer to VarZeroVec");
211        assert_eq!(zerovec_orig.to_vec(), zerovec_new.to_vec());
212        assert!(zerovec_new.is_owned());
213    }
214
215    #[test]
216    fn test_serde_bincode() {
217        let zerovec_orig: VarZeroVec<str> = VarZeroVec::parse_bytes(BYTES).expect("parse");
218        let bincode_buf = bincode::serialize(&zerovec_orig).expect("serialize");
219        assert_eq!(BINCODE_BUF, bincode_buf);
220        let zerovec_new: VarZeroVec<str> =
221            bincode::deserialize(&bincode_buf).expect("deserialize from buffer to VarZeroVec");
222        assert_eq!(zerovec_orig.to_vec(), zerovec_new.to_vec());
223        assert!(!zerovec_new.is_owned());
224    }
225
226    #[test]
227    fn test_vzv_borrowed() {
228        let zerovec_orig: &VarZeroSlice<str> = VarZeroSlice::parse_bytes(BYTES).expect("parse");
229        let bincode_buf = bincode::serialize(&zerovec_orig).expect("serialize");
230        assert_eq!(BINCODE_BUF, bincode_buf);
231        let zerovec_new: &VarZeroSlice<str> =
232            bincode::deserialize(&bincode_buf).expect("deserialize from buffer to VarZeroSlice");
233        assert_eq!(zerovec_orig.to_vec(), zerovec_new.to_vec());
234    }
235
236    #[test]
237    fn test_nonascii_bincode() {
238        let src_vec = NONASCII_STR
239            .iter()
240            .copied()
241            .map(Box::<str>::from)
242            .collect::<Vec<_>>();
243        let mut zerovec: VarZeroVec<str> = VarZeroVec::parse_bytes(NONASCII_BYTES).expect("parse");
244        assert_eq!(zerovec.to_vec(), src_vec);
245        let bincode_buf = bincode::serialize(&zerovec).expect("serialize");
246        let zerovec_result =
247            bincode::deserialize::<VarZeroVec<str>>(&bincode_buf).expect("deserialize");
248        assert_eq!(zerovec_result.to_vec(), src_vec);
249
250        // try again with owned zerovec
251        zerovec.make_mut();
252        let bincode_buf = bincode::serialize(&zerovec).expect("serialize");
253        let zerovec_result =
254            bincode::deserialize::<VarZeroVec<str>>(&bincode_buf).expect("deserialize");
255        assert_eq!(zerovec_result.to_vec(), src_vec);
256    }
257}