Skip to main content

deser_core/adapters/bytes/
impls.rs

1//! The adapters for bytes.
2use alloc::borrow::Cow;
3use alloc::format;
4use alloc::vec::Vec;
5use core::marker::PhantomData;
6
7use crate::BytesFormat;
8use crate::State;
9use crate::adapters::bytes::BytesEncoding;
10use crate::adapters::{DeserializeAs, SerializeAs};
11use crate::de::{Deserialize, Sink, SinkHandle};
12use crate::error::{Error, ErrorKind};
13use crate::event::{Atom, Bytes, ContainerShape};
14use crate::ser::{Begin, Chunk};
15
16mod sealed {
17    use super::*;
18
19    pub trait BytesBufImpl: Sized + Send + Sync {
20        fn bytes(&self) -> &[u8];
21        fn from_vec(bytes: Vec<u8>) -> Result<Self, Error>;
22        fn deserialize_into<'a, 'de>(
23            out: &'a mut Option<Self>,
24            state: &mut State,
25        ) -> SinkHandle<'a, 'de>;
26    }
27
28    pub trait BytesFallbackFormatImpl: 'static {
29        const FORMAT: BytesFormat;
30        fn deserialize_into<'a, 'de, T: BytesBufImpl>(
31            out: &'a mut Option<T>,
32            state: &mut State,
33        ) -> SinkHandle<'a, 'de>;
34    }
35}
36
37pub(crate) use self::sealed::BytesBufImpl;
38use self::sealed::BytesFallbackFormatImpl;
39
40/// The types that the bytes adapters support.
41///
42/// These are `Vec<u8>`, `[u8; N]` and `Cow<[u8]>`.  With the features of
43/// the same name also `bytes::Bytes`, `bytes::BytesMut`,
44/// `bstr::BString`, `smallvec::SmallVec<[u8; N]>` and
45/// `arrayvec::ArrayVec<u8, N>`.  The trait is sealed, it cannot be
46/// implemented outside of deser.
47pub trait BytesBuf: BytesBufImpl {}
48
49impl<T: BytesBufImpl> BytesBuf for T {}
50
51impl BytesBufImpl for Vec<u8> {
52    #[inline]
53    fn bytes(&self) -> &[u8] {
54        self
55    }
56
57    #[inline]
58    fn from_vec(bytes: Vec<u8>) -> Result<Self, Error> {
59        Ok(bytes)
60    }
61
62    #[inline]
63    fn deserialize_into<'a, 'de>(
64        out: &'a mut Option<Self>,
65        state: &mut State,
66    ) -> SinkHandle<'a, 'de> {
67        Deserialize::deserialize_into(out, state)
68    }
69}
70
71impl<const N: usize> BytesBufImpl for [u8; N] {
72    #[inline]
73    fn bytes(&self) -> &[u8] {
74        self
75    }
76
77    fn from_vec(bytes: Vec<u8>) -> Result<Self, Error> {
78        bytes
79            .try_into()
80            .map_err(|_| Error::new(ErrorKind::WrongLength, "byte array of wrong length"))
81    }
82
83    #[inline]
84    fn deserialize_into<'a, 'de>(
85        out: &'a mut Option<Self>,
86        state: &mut State,
87    ) -> SinkHandle<'a, 'de> {
88        Deserialize::deserialize_into(out, state)
89    }
90}
91
92impl<'c> BytesBufImpl for Cow<'c, [u8]> {
93    #[inline]
94    fn bytes(&self) -> &[u8] {
95        self
96    }
97
98    #[inline]
99    fn from_vec(bytes: Vec<u8>) -> Result<Self, Error> {
100        Ok(Cow::Owned(bytes))
101    }
102
103    #[inline]
104    fn deserialize_into<'a, 'de>(
105        out: &'a mut Option<Self>,
106        state: &mut State,
107    ) -> SinkHandle<'a, 'de> {
108        Deserialize::deserialize_into(out, state)
109    }
110}
111
112/// The representations that [`BytesFallback`] supports.
113///
114/// These are all [encodings](BytesEncoding) and [`IntSeq`].  The trait is
115/// sealed, it cannot be implemented outside of deser.  New encodings are
116/// added by implementing [`BytesEncoding`].
117pub trait BytesFallbackFormat: BytesFallbackFormatImpl {}
118
119impl<F: BytesFallbackFormatImpl> BytesFallbackFormat for F {}
120
121impl<E: BytesEncoding> BytesFallbackFormatImpl for E {
122    const FORMAT: BytesFormat = BytesFormat::encoded::<E>();
123
124    #[inline]
125    fn deserialize_into<'a, 'de, T: BytesBufImpl>(
126        out: &'a mut Option<T>,
127        state: &mut State,
128    ) -> SinkHandle<'a, 'de> {
129        encoded_handle::<T, E>(out, state)
130    }
131}
132
133/// Represents bytes as sequences of integers.
134///
135/// This is only used with [`BytesFallback`], `BytesFallback<IntSeq>` writes
136/// bytes as sequences of integers in formats without native bytes (like
137/// `serde_json`).  It corresponds to [`BytesFormat::SEQ`].
138pub struct IntSeq;
139
140impl BytesFallbackFormatImpl for IntSeq {
141    const FORMAT: BytesFormat = BytesFormat::SEQ;
142
143    #[inline]
144    fn deserialize_into<'a, 'de, T: BytesBufImpl>(
145        out: &'a mut Option<T>,
146        state: &mut State,
147    ) -> SinkHandle<'a, 'de> {
148        // bytes accept sequences of integers anyways
149        T::deserialize_into(out, state)
150    }
151}
152
153/// Deserializes bytes which are either native bytes or encoded strings.
154struct EncodedSink<'a, T, E> {
155    out: &'a mut Option<T>,
156    _marker: PhantomData<fn() -> E>,
157}
158
159impl<'a, 'de, T: BytesBufImpl, E: BytesEncoding> Sink<'de> for EncodedSink<'a, T, E> {
160    fn expecting(&self) -> Cow<'_, str> {
161        Cow::Owned(format!("bytes or {} string", E::NAME))
162    }
163
164    fn atom(&mut self, atom: Atom, state: &mut State) -> Result<(), Error> {
165        let bytes = match atom {
166            Atom::Bytes(value) => value.into_data().into_owned(),
167            Atom::Str(value) => E::decode(&value)?,
168            other => return self.unexpected_atom(other, state),
169        };
170        *self.out = Some(T::from_vec(bytes)?);
171        Ok(())
172    }
173}
174
175#[inline]
176pub(crate) fn encoded_handle<'a, 'de, T: BytesBufImpl, E: BytesEncoding>(
177    out: &'a mut Option<T>,
178    state: &mut State,
179) -> SinkHandle<'a, 'de> {
180    SinkHandle::arena(
181        EncodedSink::<T, E> {
182            out,
183            _marker: PhantomData,
184        },
185        state,
186    )
187}
188
189/// Makes the encodings adapters which represent bytes as strings in all
190/// formats and accept strings in the encoding and native bytes.
191///
192/// The impls are for the concrete types rather than all [`BytesBuf`]s as
193/// otherwise they would conflict with the impls for `Box<U>`.
194macro_rules! encoding_adapter {
195    ($([$($gen:tt)*] $ty:ty),* $(,)?) => {
196        $(
197            impl<$($gen)* E: $crate::adapters::BytesEncoding> $crate::adapters::SerializeAs<$ty> for E {
198                fn serialize_as<'a>(
199                    value: &'a $ty,
200                    _state: &mut $crate::State,
201                ) -> Result<$crate::ser::Chunk<'a>, $crate::Error> {
202                    let mut rv = alloc::string::String::new();
203                    E::encode(
204                        $crate::adapters::bytes::BytesBufImpl::bytes(value),
205                        &mut rv,
206                    );
207                    Ok($crate::ser::Chunk::Atom($crate::Atom::Str($crate::Text::owned(rv))))
208                }
209
210                #[inline]
211                fn __private_begin_as<'a>(
212                    value: &'a $ty,
213                    state: &mut $crate::State,
214                ) -> Result<$crate::ser::Begin<'a>, $crate::Error> {
215                    Ok($crate::ser::Begin::chunk(
216                        Self::serialize_as(value, state)?,
217                        $crate::ContainerShape::new(),
218                        false,
219                    ))
220                }
221            }
222
223            impl<'de, $($gen)* E: $crate::adapters::BytesEncoding>
224                $crate::adapters::DeserializeAs<'de, $ty> for E
225            {
226                #[inline]
227                fn deserialize_into_as<'a>(
228                    out: &'a mut Option<$ty>, state: &mut $crate::State) -> $crate::de::SinkHandle<'a, 'de> {
229                    $crate::adapters::bytes::encoded_handle::<$ty, E>(out, state)
230                }
231            }
232        )*
233    };
234}
235
236// also used for the byte buffers of other crates
237#[allow(unused_imports)]
238pub(crate) use encoding_adapter;
239
240encoding_adapter!(
241    [] Vec<u8>,
242    [const N: usize,] [u8; N],
243    ['c,] Cow<'c, [u8]>,
244);
245
246/// Represents bytes as bytes, with a fallback for formats without native bytes.
247///
248/// The bytes are serialized as bytes which carry the format `F` as
249/// fallback (see [`Bytes::fallback`](crate::Bytes::fallback)).  Formats with native bytes (like CBOR)
250/// write them as bytes, formats without native bytes (like JSON and TOML)
251/// write them in `F`: strings in an [encoding](BytesEncoding) or sequences
252/// of integers for [`IntSeq`].  When deserializing native bytes and the
253/// representation of `F` are accepted.  It supports the types of
254/// [`BytesBuf`].
255///
256/// ```
257/// use deser::adapters::{Base64Url, BytesFallback, IntSeq};
258/// use deser::{Deserialize, Serialize};
259///
260/// #[derive(Serialize, Deserialize)]
261/// pub struct Blob {
262///     // URL-safe base64 in JSON and TOML, bytes in CBOR
263///     #[deser(as = BytesFallback<Base64Url>)]
264///     sha1: [u8; 20],
265///     #[deser(as = Option<BytesFallback<Base64Url>>)]
266///     signature: Option<Vec<u8>>,
267///     // `[1, 2]` in JSON and TOML, bytes in CBOR
268///     #[deser(as = BytesFallback<IntSeq>)]
269///     legacy: Vec<u8>,
270/// }
271/// ```
272///
273/// To use an encoding in all formats, use the encoding as adapter (for
274/// instance `#[deser(as = Base64Url)]`).  To change the representation of all
275/// bytes, configure the format instead.
276pub struct BytesFallback<F>(PhantomData<fn() -> F>);
277
278impl<T: BytesBuf, F: BytesFallbackFormat> SerializeAs<T> for BytesFallback<F> {
279    #[inline]
280    fn serialize_as<'a>(value: &'a T, _state: &mut State) -> Result<Chunk<'a>, Error> {
281        Ok(Chunk::Atom(Atom::Bytes(
282            Bytes::borrowed(value.bytes()).with_fallback(const { &F::FORMAT }),
283        )))
284    }
285
286    #[inline]
287    fn __private_begin_as<'a>(value: &'a T, state: &mut State) -> Result<Begin<'a>, Error> {
288        Ok(Begin::chunk(
289            Self::serialize_as(value, state)?,
290            ContainerShape::new(),
291            false,
292        ))
293    }
294}
295
296impl<'de, T: BytesBuf, F: BytesFallbackFormat> DeserializeAs<'de, T> for BytesFallback<F> {
297    #[inline]
298    fn deserialize_into_as<'out>(
299        out: &'out mut Option<T>,
300        state: &mut State,
301    ) -> SinkHandle<'out, 'de> {
302        F::deserialize_into(out, state)
303    }
304}