serde_encoded_bytes/
containers.rs

1use core::fmt;
2
3use core::marker::PhantomData;
4
5use serde::{Deserializer, Serializer};
6
7use crate::encoding::Encoding;
8use crate::low_level;
9
10/// A container for array-like data, e.g. Rust stack arrays.
11///
12/// For a `GenericArray` from `generic-array=0.14` with the size parametrized
13/// by a generic parameter, use [`GenericArray014`].
14///
15/// For use in the `#[serde(with)]` field attribute.
16///
17/// Note that the length of the array will be serialized as well;
18/// this is caused by `serde` not being able to communicate to format implementations
19/// that the array has a constant size.
20/// See <https://github.com/serde-rs/serde/issues/2120> for details.
21///
22/// Requirements:
23/// - serializer requires the field to implement `AsRef<[u8]>`;
24/// - deserializer requires the field to implement `TryFrom<[u8; N]>`.
25pub struct ArrayLike<Enc: Encoding>(PhantomData<Enc>);
26
27impl<Enc: Encoding> ArrayLike<Enc> {
28    /// Serializes array-like data.
29    pub fn serialize<T, S>(obj: &T, serializer: S) -> Result<S::Ok, S::Error>
30    where
31        T: AsRef<[u8]>,
32        S: Serializer,
33    {
34        low_level::serialize_slice::<Enc, _>(obj.as_ref(), serializer)
35    }
36
37    /// Deserializes into array-like data.
38    pub fn deserialize<'de, T, E, D, const N: usize>(deserializer: D) -> Result<T, D::Error>
39    where
40        D: Deserializer<'de>,
41        T: TryFrom<[u8; N], Error = E>,
42        E: fmt::Display,
43    {
44        low_level::deserialize_array::<Enc, N, _, _, _>(deserializer)
45    }
46}
47
48/// A container for slice-like data, e.g. `Vec<u8>` or `Box<u8>`.
49///
50/// For use in the `#[serde(with)]` field attribute.
51///
52/// Requirements:
53/// - serializer requires the field to implement `AsRef<[u8]>`;
54/// - deserializer requires the field to implement `TryFrom<&[u8]>`.
55pub struct SliceLike<Enc: Encoding>(PhantomData<Enc>);
56
57impl<Enc: Encoding> SliceLike<Enc> {
58    /// Serializes slice-like data.
59    pub fn serialize<T, S>(obj: &T, serializer: S) -> Result<S::Ok, S::Error>
60    where
61        T: AsRef<[u8]>,
62        S: Serializer,
63    {
64        low_level::serialize_slice::<Enc, _>(obj.as_ref(), serializer)
65    }
66
67    /// Deserializes into slice-like data.
68    pub fn deserialize<'de, T, E, D>(deserializer: D) -> Result<T, D::Error>
69    where
70        D: Deserializer<'de>,
71        T: for<'a> TryFrom<&'a [u8], Error = E>,
72        E: fmt::Display,
73    {
74        low_level::deserialize_slice::<Enc, _, _, _>(deserializer)
75    }
76}
77
78/// A container for slice-like data with borrow constructor,
79/// e.g. `GenericArray` from `generic-array=1`.
80///
81/// Note that the object will still be cloned, hence the `Clone` requirement.
82///
83/// For use in the `#[serde(with)]` field attribute.
84///
85/// Requirements:
86/// - serializer requires the field to implement `AsRef<[u8]>`;
87/// - deserializer requires the field to implement `Clone` and `&Self: TryFrom<&[u8]>`.
88pub struct BorrowedSliceLike<Enc: Encoding>(PhantomData<Enc>);
89
90impl<Enc: Encoding> BorrowedSliceLike<Enc> {
91    /// Serializes slice-like data.
92    pub fn serialize<T, S>(obj: &T, serializer: S) -> Result<S::Ok, S::Error>
93    where
94        T: AsRef<[u8]>,
95        S: Serializer,
96    {
97        low_level::serialize_slice::<Enc, _>(obj.as_ref(), serializer)
98    }
99
100    /// Deserializes into slice-like data.
101    pub fn deserialize<'de, T, E, D>(deserializer: D) -> Result<T, D::Error>
102    where
103        D: Deserializer<'de>,
104        T: Clone,
105        for<'a> &'a T: TryFrom<&'a [u8], Error = E>,
106        E: fmt::Display,
107    {
108        low_level::deserialize_borrowed_slice::<Enc, _, _, _>(deserializer)
109    }
110}
111
112/// A container for boxed array-like data, e.g. `Box<[u8; 4]>`
113/// or `Box<generic_array::GenericArray<...>>`.
114///
115/// For use in the `#[serde(with)]` field attribute.
116///
117/// Requirements:
118/// - serializer requires the field to implement `AsRef<[u8; N]>`;
119/// - deserializer requires the field to implement [`TryFromArray`] or `TryFrom<[u8; N]>`.
120pub struct BoxedArrayLike<Enc: Encoding>(PhantomData<Enc>);
121
122impl<Enc: Encoding> BoxedArrayLike<Enc> {
123    /// Serializes boxed-array-like data.
124    pub fn serialize<T, S, const N: usize>(obj: &T, serializer: S) -> Result<S::Ok, S::Error>
125    where
126        T: AsRef<[u8; N]>,
127        S: Serializer,
128    {
129        low_level::serialize_slice::<Enc, _>(obj.as_ref(), serializer)
130    }
131
132    /// Deserializes into boxed-array-like data.
133    pub fn deserialize<'de, T, E, D, const N: usize>(deserializer: D) -> Result<T, D::Error>
134    where
135        D: Deserializer<'de>,
136        T: TryFrom<[u8; N], Error = E>,
137        E: fmt::Display,
138    {
139        low_level::deserialize_array::<Enc, N, _, _, _>(deserializer)
140    }
141}
142
143/// A container for `generic_array::GenericArray<...>` from `generic-array=0.14`
144/// (either with a fixed size or generic).
145///
146/// For use in the `#[serde(with)]` field attribute.
147///
148/// Note that the length of the array will be serialized as well;
149/// this is caused by `serde` not being able to communicate to format implementations
150/// that the array has a constant size.
151/// See <https://github.com/serde-rs/serde/issues/2120> for details.
152#[cfg(feature = "generic-array-014")]
153pub struct GenericArray014<Enc: Encoding>(PhantomData<Enc>);
154
155#[cfg(feature = "generic-array-014")]
156impl<Enc: Encoding> GenericArray014<Enc> {
157    /// Serializes array-like data.
158    pub fn serialize<L, S>(
159        obj: &generic_array_014::GenericArray<u8, L>,
160        serializer: S,
161    ) -> Result<S::Ok, S::Error>
162    where
163        L: generic_array_014::ArrayLength<u8>,
164        S: Serializer,
165    {
166        low_level::serialize_slice::<Enc, _>(obj.as_ref(), serializer)
167    }
168
169    /// Deserializes into array-like data.
170    pub fn deserialize<'de, L, D>(
171        deserializer: D,
172    ) -> Result<generic_array_014::GenericArray<u8, L>, D::Error>
173    where
174        D: Deserializer<'de>,
175        L: generic_array_014::ArrayLength<u8>,
176    {
177        low_level::deserialize_generic_array_014::<Enc, L, _>(deserializer)
178    }
179}
180
181#[cfg(test)]
182mod tests {
183    use alloc::{boxed::Box, vec::Vec};
184
185    use serde::{Deserialize, Serialize};
186
187    use crate::{encoding::Hex, ArrayLike, BoxedArrayLike, SliceLike};
188
189    #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
190    struct FixedArrayStruct(#[serde(with = "ArrayLike::<Hex>")] [u8; 4]);
191
192    #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
193    struct VectorStruct(#[serde(with = "SliceLike::<Hex>")] Vec<u8>);
194
195    #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
196    struct BoxedArrayStruct(#[serde(with = "BoxedArrayLike::<Hex>")] Box<[u8; 4]>);
197
198    #[test]
199    fn roundtrip_array() {
200        let val = FixedArrayStruct([1, 2, 3, 4]);
201        let val_bytes = rmp_serde::to_vec(&val).unwrap();
202        let val_back = rmp_serde::from_slice::<FixedArrayStruct>(&val_bytes).unwrap();
203        assert_eq!(val, val_back);
204    }
205
206    #[test]
207    fn roundtrip_slice() {
208        let val = VectorStruct([1, 2, 3, 4].into());
209        let val_bytes = rmp_serde::to_vec(&val).unwrap();
210        let val_back = rmp_serde::from_slice::<VectorStruct>(&val_bytes).unwrap();
211        assert_eq!(val, val_back);
212    }
213
214    #[test]
215    fn roundtrip_boxed_array() {
216        let val = BoxedArrayStruct([1, 2, 3, 4].into());
217        let val_bytes = rmp_serde::to_vec(&val).unwrap();
218        let val_back = rmp_serde::from_slice::<BoxedArrayStruct>(&val_bytes).unwrap();
219        assert_eq!(val, val_back);
220    }
221}