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