Skip to main content

deser_core/foreign_impls/
bstr.rs

1//! `BString` and `BStr` of `bstr`.
2//!
3//! Byte strings are conventionally UTF-8.  They are serialized as strings if
4//! they are valid UTF-8 and as bytes otherwise.  The bytes carry sequences
5//! of integers as fallback (see [`BytesFormat::SEQ`]) so that formats
6//! without native bytes (like JSON) can tell them apart from strings.
7//!
8//! When deserialized, strings are taken as their UTF-8 bytes (like the
9//! serde implementation of `bstr`).  Besides strings, byte strings accept
10//! bytes and sequences of integers.  `&BStr` borrows strings and bytes from
11//! the data.
12use alloc::borrow::Cow;
13use alloc::boxed::Box;
14use alloc::string::ToString;
15use alloc::vec::Vec;
16use core::mem::take;
17
18use ::bstr::{BStr, BString};
19
20use crate::BytesFormat;
21use crate::State;
22use crate::Text;
23use crate::adapters::bytes::{BytesBufImpl, encoding_adapter};
24use crate::de::impls::{Via, deserialize_via};
25use crate::de::{Deserialize, Sink, SinkHandle, Slot, default_atom};
26use crate::error::{Error, ErrorKind};
27use crate::event::{Atom, Bytes};
28use crate::ser::{Emit, Serialize, plain_atom};
29
30/// Returns the atom of a byte string.
31#[inline]
32fn bstr_atom(bytes: &[u8]) -> Atom<'_> {
33    match core::str::from_utf8(bytes) {
34        Ok(value) => Atom::Str(Text::borrowed(value)),
35        Err(_) => {
36            let mut bytes = Bytes::borrowed(bytes);
37            bytes.fallback = Some(const { &BytesFormat::SEQ });
38            Atom::Bytes(bytes)
39        }
40    }
41}
42
43impl Serialize for BStr {
44    begin_without_finish!();
45
46    fn serialize<'a>(value: &'a Self, _state: &mut State) -> Result<Emit<'a>, Error> {
47        Ok(Emit::Atom(bstr_atom(value)))
48    }
49}
50
51impl Serialize for BString {
52    begin_without_finish!();
53    plain_atom!(|v| bstr_atom(v));
54
55    fn serialize<'a>(value: &'a Self, _state: &mut State) -> Result<Emit<'a>, Error> {
56        Ok(Emit::Atom(bstr_atom(value)))
57    }
58}
59
60/// Converts an atom into a byte string.
61///
62/// Returns the atom back if it's not a string or bytes.
63#[inline]
64fn bstring_from_atom(atom: Atom) -> Result<BString, Atom> {
65    match atom {
66        Atom::Str(value) | Atom::Lexical(value) => Ok(BString::from(value.into_owned())),
67        Atom::Char(value) => Ok(BString::from(value.to_string())),
68        Atom::Bytes(value) => Ok(BString::from(value.into_owned())),
69        other => Err(other),
70    }
71}
72
73/// Deserializes byte strings from strings, bytes and sequences of integers.
74struct BStringSink<'a> {
75    out: &'a mut Option<BString>,
76    bytes: Vec<u8>,
77    element: Option<u8>,
78    is_seq: bool,
79}
80
81impl BStringSink<'_> {
82    #[inline]
83    fn flush(&mut self) {
84        if let Some(byte) = self.element.take() {
85            self.bytes.push(byte);
86        }
87    }
88}
89
90/// What byte strings expect.
91const BSTRING_NAME: &str = "byte string";
92
93impl<'de> Sink<'de> for BStringSink<'_> {
94    fn expecting(&self) -> Cow<'_, str> {
95        Cow::Borrowed(BSTRING_NAME)
96    }
97
98    fn atom(&mut self, atom: Atom, state: &mut State) -> Result<(), Error> {
99        match bstring_from_atom(atom) {
100            Ok(value) => {
101                *self.out = Some(value);
102                Ok(())
103            }
104            Err(other) => default_atom(self, other, state),
105        }
106    }
107
108    fn seq(&mut self, _state: &mut State) -> Result<(), Error> {
109        self.is_seq = true;
110        Ok(())
111    }
112
113    fn next_value(&mut self, state: &mut State) -> Result<SinkHandle<'_, 'de>, Error> {
114        self.flush();
115        Ok(u8::deserialize_into(&mut self.element, state))
116    }
117
118    fn __private_value_atom(&mut self, atom: Atom, state: &mut State) -> Result<(), Error> {
119        self.flush();
120        u8::__private_atom_into(&mut self.element, atom, state)
121    }
122
123    fn finish(&mut self, _state: &mut State) -> Result<(), Error> {
124        if self.is_seq {
125            self.flush();
126            *self.out = Some(BString::from(take(&mut self.bytes)));
127        }
128        Ok(())
129    }
130}
131
132impl<'de> Deserialize<'de> for BString {
133    fn deserialize_into<'out>(
134        out: &'out mut Option<Self>,
135        state: &mut State,
136    ) -> SinkHandle<'out, 'de> {
137        SinkHandle::arena(
138            BStringSink {
139                out,
140                bytes: Vec::new(),
141                element: None,
142                is_seq: false,
143            },
144            state,
145        )
146    }
147
148    fn expecting() -> Cow<'static, str> {
149        Cow::Borrowed(BSTRING_NAME)
150    }
151
152    #[inline]
153    fn __private_atom_into(
154        out: &mut Option<Self>,
155        atom: Atom,
156        state: &mut State,
157    ) -> Result<(), Error> {
158        match bstring_from_atom(atom) {
159            Ok(value) => {
160                *out = Some(value);
161                Ok(())
162            }
163            Err(other) => {
164                let mut sink = BStringSink {
165                    out,
166                    bytes: Vec::new(),
167                    element: None,
168                    is_seq: false,
169                };
170                sink.atom(other, state)
171            }
172        }
173    }
174
175    #[inline]
176    fn __private_borrowed_atom_into(
177        out: &mut Option<Self>,
178        atom: Atom<'de>,
179        state: &mut State,
180    ) -> Result<(), Error> {
181        // the sink does not borrow
182        Self::__private_atom_into(out, atom, state)
183    }
184}
185
186impl Via<BString> for Box<BStr> {
187    #[inline]
188    fn convert(value: BString) -> Result<Self, Error> {
189        Ok(Box::from(Vec::from(value).into_boxed_slice()))
190    }
191}
192
193deserialize_via! {
194    [] Box<BStr> => BString;
195}
196
197/// The bytes adapters represent the raw bytes, not the string.
198impl BytesBufImpl for BString {
199    #[inline]
200    fn bytes(&self) -> &[u8] {
201        self.as_slice()
202    }
203
204    #[inline]
205    fn from_vec(bytes: Vec<u8>) -> Result<Self, Error> {
206        Ok(BString::from(bytes))
207    }
208
209    #[inline]
210    fn deserialize_into<'a, 'de>(
211        out: &'a mut Option<Self>,
212        state: &mut State,
213    ) -> SinkHandle<'a, 'de> {
214        <Self as Deserialize<'de>>::deserialize_into(out, state)
215    }
216
217    fn expecting() -> Cow<'static, str> {
218        <Self as Deserialize<'static>>::expecting()
219    }
220}
221
222encoding_adapter!([] BString);
223
224/// Borrows strings and bytes from the data.
225impl<'de: 'a, 'a> Deserialize<'de> for &'a BStr {
226    fn deserialize_atom(slot: &mut Slot<Self>, atom: Atom, state: &mut State) -> Result<(), Error> {
227        match atom {
228            Atom::Str(_) | Atom::Lexical(_) | Atom::Bytes(_) => Err(Error::new(
229                ErrorKind::UnsupportedType,
230                "unexpected owned byte string, expected a borrowed byte string (the data \
231                 format or the type buffering the value does not support borrowing)",
232            )),
233            other => default_atom(slot, other, state),
234        }
235    }
236
237    fn deserialize_borrowed_atom(
238        slot: &mut Slot<Self>,
239        atom: Atom<'de>,
240        state: &mut State,
241    ) -> Result<(), Error> {
242        match atom {
243            Atom::Str(ref text) | Atom::Lexical(ref text) if text.is_borrowed() => {
244                **slot = text.borrowed_str().map(BStr::new);
245                Ok(())
246            }
247            Atom::Implicit(ref value) if value.text().is_borrowed() => {
248                **slot = value.text().borrowed_str().map(BStr::new);
249                Ok(())
250            }
251            Atom::Bytes(ref value) if value.is_borrowed() => {
252                **slot = value.borrowed_data().map(BStr::new);
253                Ok(())
254            }
255            other => Self::deserialize_atom(slot, other, state),
256        }
257    }
258
259    fn expecting() -> Cow<'static, str> {
260        Cow::Borrowed("borrowed byte string")
261    }
262}