Skip to main content

deser_php/
de.rs

1use alloc::string::String;
2use alloc::vec::Vec;
3use core::marker::PhantomData;
4
5use deser_core::adapters::BytesEncoding;
6use deser_core::de::{self, Deserialize, DeserializeDriver, deserialize_value};
7use deser_core::{BytesFormat, Error};
8
9use crate::parser::{self, syntax_error};
10
11/// Configures how PHP's serialization format is deserialized.
12///
13/// The configuration is independent of the input so it can be created once
14/// (even as a constant) and used for many inputs.  The method
15/// [`from_slice`](Self::from_slice) works like the function of the same
16/// name.  The only option is the [`Context`](deser_core::Context) (see
17/// [`set_context`](Self::set_context)).
18///
19/// ```
20/// use deser_php::DeserializerConfig;
21///
22/// const CONFIG: DeserializerConfig = DeserializerConfig::new();
23/// assert_eq!(CONFIG.from_slice::<Vec<u32>>(b"a:2:{i:0;i:1;i:1;i:2;}").unwrap(), [1, 2]);
24/// ```
25#[derive(Debug, Clone, Default, PartialEq, Eq)]
26pub struct DeserializerConfig {
27    context: deser_core::Context,
28}
29
30impl DeserializerConfig {
31    /// Creates the default configuration.
32    pub const fn new() -> DeserializerConfig {
33        DeserializerConfig {
34            context: deser_core::Context::new(),
35        }
36    }
37
38    /// Returns a builder for the configuration (see [`DeserializerConfigBuilder`]).
39    pub const fn builder() -> DeserializerConfigBuilder {
40        DeserializerConfigBuilder::new()
41    }
42
43    /// Returns a builder that starts with this configuration.
44    pub const fn into_builder(self) -> DeserializerConfigBuilder {
45        DeserializerConfigBuilder { value: self }
46    }
47
48    /// Sets the context the values are deserialized in.
49    ///
50    /// The values of the context are the defaults of the extension values
51    /// of the state (see [`Context`](deser_core::Context)), for instance
52    /// the variants of open enums.  The deserializers and readers created
53    /// with the configuration use this context.  A context set on the
54    /// driver takes precedence.
55    pub fn set_context(&mut self, context: deser_core::Context) {
56        self.context = context;
57    }
58
59    /// Returns the context the values are deserialized in.
60    pub fn context(&self) -> &deser_core::Context {
61        &self.context
62    }
63
64    /// Deserializes a value.
65    ///
66    /// See [`from_slice`].
67    pub fn from_slice<'de, T: Deserialize<'de>>(&self, input: &'de [u8]) -> Result<T, Error> {
68        deserialize_value(|driver| self.drive_slice(input, driver))
69    }
70
71    /// Deserializes a value from a string.
72    ///
73    /// See [`from_str`].
74    pub fn from_str<'de, T: Deserialize<'de>>(&self, input: &'de str) -> Result<T, Error> {
75        self.from_slice(input.as_bytes())
76    }
77
78    /// The part of [`from_slice`](Self::from_slice) that does not depend on
79    /// the type of the value, it exists once.
80    fn drive_slice<'de>(
81        &self,
82        input: &'de [u8],
83        driver: &mut DeserializeDriver<'_, 'de>,
84    ) -> Result<(), Error> {
85        let mut deserializer = Deserializer::from_slice_with_config(input, self.clone());
86        de::Deserializer::drive(&mut deserializer, driver)?;
87        deserializer.end()
88    }
89}
90
91/// Builds a [`DeserializerConfig`].
92///
93/// The methods have the names of the setters of [`DeserializerConfig`] (without `set_`).
94#[derive(Debug, Clone)]
95#[must_use]
96pub struct DeserializerConfigBuilder {
97    value: DeserializerConfig,
98}
99
100impl DeserializerConfigBuilder {
101    /// Creates a builder that starts with the default.
102    pub const fn new() -> DeserializerConfigBuilder {
103        DeserializerConfigBuilder {
104            value: DeserializerConfig::new(),
105        }
106    }
107
108    /// Sets the context the values are deserialized in.
109    ///
110    /// See [`DeserializerConfig::set_context`].
111    pub fn context(mut self, context: deser_core::Context) -> DeserializerConfigBuilder {
112        self.value.set_context(context);
113        self
114    }
115
116    /// Returns the built [`DeserializerConfig`].
117    pub const fn build(self) -> DeserializerConfig {
118        // the value cannot be moved out of the builder in a const fn as the
119        // builder needs dropping (the context has a destructor)
120        // SAFETY: the value is read once and the builder is forgotten
121        let value = unsafe { core::ptr::read(&self.value) };
122        core::mem::forget(self);
123        value
124    }
125}
126
127impl Default for DeserializerConfigBuilder {
128    fn default() -> DeserializerConfigBuilder {
129        DeserializerConfigBuilder::new()
130    }
131}
132
133/// Deserializes values of PHP's serialization format.
134///
135/// A deserializer reads values from a slice.  PHP reads a single value but
136/// values can be concatenated, so a deserializer can be used to read more
137/// than one:
138///
139/// ```
140/// use deser_php::Deserializer;
141///
142/// let mut de = Deserializer::from_slice(b"i:1;s:2:\"hi\";");
143/// assert_eq!(de.deserialize::<u32>().unwrap(), 1);
144/// assert_eq!(de.deserialize::<String>().unwrap(), "hi");
145/// assert!(de.is_end());
146/// ```
147///
148/// To deserialize a single value, use [`from_slice`]
149/// (or the method of the same name on [`DeserializerConfig`]).
150pub struct Deserializer<'a> {
151    input: &'a [u8],
152    pos: usize,
153    config: DeserializerConfig,
154}
155
156impl<'a> Deserializer<'a> {
157    /// Creates a new deserializer for a byte slice.
158    pub fn from_slice(input: &'a [u8]) -> Deserializer<'a> {
159        Deserializer::from_slice_with_config(input, DeserializerConfig::new())
160    }
161
162    /// Creates a new deserializer for a byte slice with the given
163    /// configuration.
164    pub fn from_slice_with_config(input: &'a [u8], config: DeserializerConfig) -> Deserializer<'a> {
165        Deserializer {
166            input,
167            pos: 0,
168            config,
169        }
170    }
171
172    /// Returns the configuration.
173    pub fn config(&self) -> &DeserializerConfig {
174        &self.config
175    }
176
177    /// Returns the current offset in the input.
178    pub fn offset(&self) -> usize {
179        self.pos
180    }
181
182    /// Returns `true` if the entire input was consumed.
183    pub fn is_end(&self) -> bool {
184        self.pos >= self.input.len()
185    }
186
187    /// Fails if the input was not consumed entirely.
188    ///
189    /// Unlike PHP (which ignores data after the value with a warning) the
190    /// functions that deserialize a single value reject it.
191    pub fn end(&self) -> Result<(), Error> {
192        if self.is_end() {
193            Ok(())
194        } else {
195            Err(syntax_error(self.pos, "trailing data after value"))
196        }
197    }
198
199    /// Deserializes the next value.
200    ///
201    /// This does not check if there is more data after the value.  Use
202    /// [`end`](Self::end) for this or [`from_slice`] which does it
203    /// automatically.
204    ///
205    /// To configure the deserialization (for instance to add layers) use
206    /// [`deserialize_with`](Self::deserialize_with).
207    pub fn deserialize<T: Deserialize<'a>>(&mut self) -> Result<T, Error> {
208        de::Deserializer::deserialize(self)
209    }
210
211    /// Deserializes the next value with a configured driver.
212    ///
213    /// The callback is invoked with the driver before the value is
214    /// deserialized, for instance to add [`Layer`](deser_core::de::Layer)s.
215    pub fn deserialize_with<T, F>(&mut self, setup: F) -> Result<T, Error>
216    where
217        T: Deserialize<'a>,
218        F: FnOnce(&mut DeserializeDriver<'_, 'a>),
219    {
220        de::Deserializer::deserialize_with(self, setup)
221    }
222
223    /// Returns an iterator over the remaining values.
224    ///
225    /// The iterator stops after the first error.
226    ///
227    /// ```
228    /// let mut de = deser_php::Deserializer::from_slice(b"i:1;i:2;i:3;");
229    /// let items = de.iter::<u32>().collect::<Result<Vec<_>, _>>().unwrap();
230    /// assert_eq!(items, [1, 2, 3]);
231    /// ```
232    pub fn iter<T: Deserialize<'a>>(&mut self) -> Iter<'_, 'a, T> {
233        Iter {
234            de: self,
235            failed: false,
236            _marker: PhantomData,
237        }
238    }
239
240    /// Parses the next value and feeds the events into the given driver.
241    ///
242    /// This is useful to deserialize into a custom
243    /// [`Sink`](deser_core::de::Sink) or to wrap the sink of a value.
244    ///
245    /// The value is validated before the first event is emitted.  Strings
246    /// are passed on borrowed from the input.  The byte ranges of the
247    /// values are published as input ranges (see
248    /// [`State::input_range`](deser_core::State::input_range)) and errors
249    /// carry the offset in the input (see [`Error::offset`]).
250    pub fn drive(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
251        // strings are bytes in PHP, types that expect bytes take them as
252        // they are
253        driver
254            .state_mut()
255            .set_default(BytesFormat::encoded::<PhpStrings>());
256        let scan = parser::scan(self.input, self.pos)?;
257        parser::emit(self.input, self.pos, &scan.lists, driver)?;
258        self.pos = scan.end;
259        Ok(())
260    }
261}
262
263/// An iterator over concatenated values.
264///
265/// See [`Deserializer::iter`].
266pub struct Iter<'b, 'a, T> {
267    de: &'b mut Deserializer<'a>,
268    failed: bool,
269    _marker: PhantomData<fn() -> T>,
270}
271
272impl<'b, 'a, T: Deserialize<'a>> Iterator for Iter<'b, 'a, T> {
273    type Item = Result<T, Error>;
274
275    fn next(&mut self) -> Option<Self::Item> {
276        if self.failed || self.de.is_end() {
277            return None;
278        }
279        let rv = self.de.deserialize();
280        self.failed = rv.is_err();
281        Some(rv)
282    }
283}
284
285impl<'a> de::Deserializer<'a> for Deserializer<'a> {
286    fn drive(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
287        if !self.config.context.is_empty() {
288            driver.set_default_context(self.config.context.clone());
289        }
290        Deserializer::drive(self, driver)
291    }
292}
293
294/// The bytes of PHP strings are the bytes of the text.
295///
296/// This is the default [`BytesFormat`] of the deserialization: PHP strings
297/// are bytes, the ones that are valid UTF-8 are passed on as text.  Types
298/// that expect bytes take their bytes rather than decoding them as base64.
299struct PhpStrings;
300
301impl BytesEncoding for PhpStrings {
302    const NAME: &'static str = "php string";
303
304    fn encode(bytes: &[u8], out: &mut String) {
305        // only used for decoding, bytes that are not UTF-8 are bytes in PHP
306        out.push_str(&String::from_utf8_lossy(bytes));
307    }
308
309    fn decode(s: &str) -> Result<Vec<u8>, Error> {
310        Ok(s.as_bytes().to_vec())
311    }
312}
313
314/// Deserializes a value of PHP's serialization format.
315///
316/// The input must contain exactly one value.  This uses the default
317/// [`DeserializerConfig`].
318///
319/// ```
320/// use std::collections::BTreeMap;
321///
322/// let input = br#"a:2:{s:4:"name";s:5:"deser";s:4:"tags";a:2:{i:0;s:1:"a";i:1;s:1:"b";}}"#;
323/// #[derive(deser::Deserialize)]
324/// struct Package {
325///     name: String,
326///     tags: Vec<String>,
327/// }
328/// let package: Package = deser_php::from_slice(input).unwrap();
329/// assert_eq!(package.name, "deser");
330/// assert_eq!(package.tags, ["a", "b"]);
331/// ```
332pub fn from_slice<'de, T: Deserialize<'de>>(input: &'de [u8]) -> Result<T, Error> {
333    DeserializerConfig::new().from_slice(input)
334}
335
336/// Deserializes a value of PHP's serialization format from a string.
337///
338/// This is [`from_slice`] for input that is held in a string.
339///
340/// ```
341/// let value: Vec<u32> = deser_php::from_str("a:2:{i:0;i:1;i:1;i:2;}").unwrap();
342/// assert_eq!(value, [1, 2]);
343/// ```
344pub fn from_str<'de, T: Deserialize<'de>>(input: &'de str) -> Result<T, Error> {
345    DeserializerConfig::new().from_str(input)
346}