Skip to main content

deser_toml/
de.rs

1use std::borrow::Cow;
2
3use deser_core::Text;
4use deser_core::de::{self, Deserialize, DeserializeDriver, deserialize_value};
5use deser_core::ext::ExtValue;
6use deser_core::hints::Layout;
7use deser_core::{Atom, ContainerShape, Error, ErrorKind, Event, Source, TrackLocations};
8
9use crate::document::{Document, Item, Span, TableKind, Value};
10use crate::parser::{ROOT, parse};
11
12/// Configures how TOML is deserialized.
13///
14/// The configuration is independent of the input so it can be created once
15/// (even as a constant) and used for many inputs.  The methods
16/// [`from_str`](Self::from_str) and [`from_slice`](Self::from_slice) work
17/// like the functions of the same name.  To create a [`Deserializer`] with
18/// the configuration use [`Deserializer::from_str_with_config`] or
19/// [`Deserializer::from_slice_with_config`].  The only option is the
20/// [`Context`](deser_core::Context) (see [`set_context`](Self::set_context)),
21/// which holds what is configured from the outside (like
22/// [`TrackLocations`]).
23///
24/// ```
25/// use std::collections::BTreeMap;
26/// use deser_toml::DeserializerConfig;
27///
28/// const CONFIG: DeserializerConfig = DeserializerConfig::new();
29/// let value: BTreeMap<String, u32> = CONFIG.from_str("a = 1").unwrap();
30/// assert_eq!(value["a"], 1);
31/// ```
32#[derive(Debug, Clone, PartialEq, Eq)]
33pub struct DeserializerConfig {
34    context: deser_core::Context,
35}
36
37impl Default for DeserializerConfig {
38    fn default() -> DeserializerConfig {
39        DeserializerConfig::new()
40    }
41}
42
43impl DeserializerConfig {
44    /// Creates the default configuration.
45    pub const fn new() -> DeserializerConfig {
46        DeserializerConfig {
47            context: deser_core::Context::new(),
48        }
49    }
50
51    /// Returns a builder for the configuration (see [`DeserializerConfigBuilder`]).
52    pub const fn builder() -> DeserializerConfigBuilder {
53        DeserializerConfigBuilder::new()
54    }
55
56    /// Returns a builder that starts with this configuration.
57    pub const fn into_builder(self) -> DeserializerConfigBuilder {
58        DeserializerConfigBuilder { value: self }
59    }
60
61    /// Sets the context the values are deserialized in.
62    ///
63    /// The values of the context are the defaults of the extension values
64    /// of the state (see [`Context`](deser_core::Context)), for instance
65    /// the variants of open enums.  The deserializers and readers created
66    /// with the configuration use this context.  A context set
67    /// on the driver takes precedence.
68    pub fn set_context(&mut self, context: deser_core::Context) {
69        self.context = context;
70    }
71
72    /// Returns the configuration without its context (for the frames of
73    /// streams, which get the context of the stream).
74    pub(crate) fn without_context(&self) -> DeserializerConfig {
75        let mut config = self.clone();
76        config.context = deser_core::Context::default();
77        config
78    }
79
80    /// Returns the context the values are deserialized in.
81    pub fn context(&self) -> &deser_core::Context {
82        &self.context
83    }
84
85    /// Deserializes a value from TOML.
86    ///
87    /// See [`from_str`].
88    pub fn from_str<'de, T: Deserialize<'de>>(&self, s: &'de str) -> Result<T, Error> {
89        deserialize_value(|driver| self.drive_str(s, driver))
90    }
91
92    /// The part of [`from_str`](Self::from_str) that does not depend on the type
93    /// of the value, it exists once.
94    fn drive_str<'de>(
95        &self,
96        s: &'de str,
97        driver: &mut DeserializeDriver<'_, 'de>,
98    ) -> Result<(), Error> {
99        de::Deserializer::drive(
100            &mut Deserializer::from_str_with_config(s, self.clone()),
101            driver,
102        )
103    }
104
105    /// Deserializes a value from TOML in a byte slice.
106    ///
107    /// See [`from_slice`].
108    pub fn from_slice<'de, T: Deserialize<'de>>(&self, bytes: &'de [u8]) -> Result<T, Error> {
109        deserialize_value(|driver| self.drive_slice(bytes, driver))
110    }
111
112    /// The part of [`from_slice`](Self::from_slice) that does not depend on the type
113    /// of the value, it exists once.
114    fn drive_slice<'de>(
115        &self,
116        bytes: &'de [u8],
117        driver: &mut DeserializeDriver<'_, 'de>,
118    ) -> Result<(), Error> {
119        de::Deserializer::drive(
120            &mut Deserializer::from_slice_with_config(bytes, self.clone()),
121            driver,
122        )
123    }
124}
125
126/// Builds a [`DeserializerConfig`].
127///
128/// The methods have the names of the setters of [`DeserializerConfig`] (without `set_`).
129#[derive(Debug, Clone)]
130#[must_use]
131pub struct DeserializerConfigBuilder {
132    value: DeserializerConfig,
133}
134
135impl DeserializerConfigBuilder {
136    /// Creates a builder that starts with the default.
137    pub const fn new() -> DeserializerConfigBuilder {
138        DeserializerConfigBuilder {
139            value: DeserializerConfig::new(),
140        }
141    }
142
143    /// Sets the context the values are deserialized in.
144    ///
145    /// See [`DeserializerConfig::set_context`].
146    pub fn context(mut self, context: deser_core::Context) -> DeserializerConfigBuilder {
147        self.value.set_context(context);
148        self
149    }
150
151    /// Returns the built [`DeserializerConfig`].
152    pub const fn build(self) -> DeserializerConfig {
153        // the value cannot be moved out of the builder in a const fn as the
154        // builder needs dropping (the context has a destructor)
155        // SAFETY: the value is read once and the builder is forgotten
156        let value = unsafe { core::ptr::read(&self.value) };
157        core::mem::forget(self);
158        value
159    }
160}
161
162impl Default for DeserializerConfigBuilder {
163    fn default() -> DeserializerConfigBuilder {
164        DeserializerConfigBuilder::new()
165    }
166}
167
168/// Deserializes TOML.
169///
170/// Most of the time the [`from_str`] and
171/// [`from_slice`] functions (or the methods of the same
172/// name on [`DeserializerConfig`]) are all that is needed.  The
173/// deserializer is useful to [`drive`](Self::drive) a custom sink.
174///
175/// With [`TrackLocations`] in the context, tables report the location of
176/// the header that defines them (the whole document for the root table),
177/// tables created by dotted keys report the location of the key.  Arrays
178/// of tables report the location of their first header.
179///
180/// ```
181/// use deser_toml::Deserializer;
182/// use std::collections::BTreeMap;
183///
184/// let mut de = Deserializer::from_str("a = 1\nb = 2");
185/// let value: BTreeMap<String, u32> = de.deserialize().unwrap();
186/// assert_eq!(value["b"], 2);
187/// ```
188pub struct Deserializer<'a> {
189    input: &'a str,
190    /// An error that is reported instead of parsing (invalid UTF-8).
191    error: Option<Error>,
192    config: DeserializerConfig,
193}
194
195impl<'a> Deserializer<'a> {
196    /// Creates a new deserializer for a string.
197    #[allow(clippy::should_implement_trait)]
198    pub fn from_str(input: &'a str) -> Deserializer<'a> {
199        Deserializer::from_str_with_config(input, DeserializerConfig::new())
200    }
201
202    /// Creates a new deserializer for a string with the given configuration.
203    pub fn from_str_with_config(input: &'a str, config: DeserializerConfig) -> Deserializer<'a> {
204        Deserializer {
205            input,
206            error: None,
207            config,
208        }
209    }
210
211    /// Creates a new deserializer for a byte slice.
212    ///
213    /// The input must be UTF-8, otherwise deserializing fails.
214    pub fn from_slice(input: &'a [u8]) -> Deserializer<'a> {
215        Deserializer::from_slice_with_config(input, DeserializerConfig::new())
216    }
217
218    /// Creates a new deserializer for a byte slice with the given
219    /// configuration.
220    ///
221    /// The input must be UTF-8, otherwise deserializing fails.
222    pub fn from_slice_with_config(input: &'a [u8], config: DeserializerConfig) -> Deserializer<'a> {
223        match str_from_utf8(input) {
224            Ok(input) => Deserializer::from_str_with_config(input, config),
225            Err(err) => Deserializer {
226                input: "",
227                error: Some(err),
228                config,
229            },
230        }
231    }
232
233    /// Returns the configuration.
234    pub fn config(&self) -> &DeserializerConfig {
235        &self.config
236    }
237
238    /// Deserializes the document.
239    ///
240    /// To configure the deserialization (for instance to add layers) use
241    /// [`deserialize_with`](Self::deserialize_with).
242    pub fn deserialize<T: Deserialize<'a>>(&mut self) -> Result<T, Error> {
243        de::Deserializer::deserialize(self)
244    }
245
246    /// Deserializes the next value with a configured driver.
247    ///
248    /// The callback is invoked with the driver before the value is
249    /// deserialized, for instance to add [`Layer`](deser_core::de::Layer)s.
250    pub fn deserialize_with<T, F>(&mut self, setup: F) -> Result<T, Error>
251    where
252        T: Deserialize<'a>,
253        F: FnOnce(&mut DeserializeDriver<'_, 'a>),
254    {
255        de::Deserializer::deserialize_with(self, setup)
256    }
257
258    /// Parses the input and feeds the events into the given driver.
259    ///
260    /// The whole document is parsed before the first event is emitted, so
261    /// syntax errors are reported before any value is deserialized.  Keys
262    /// and strings without escape sequences are passed on borrowed from the
263    /// input (see [`emit_borrowed`](DeserializeDriver::emit_borrowed)).
264    /// Errors carry the location in the input (see [`Error::line`]).
265    ///
266    /// The context of the configuration is given to the driver (values that
267    /// the context of the driver has take precedence, see
268    /// [`DeserializeDriver::set_default_context`]).
269    pub fn drive(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
270        if !self.config.context.is_empty() {
271            driver.set_default_context(self.config.context.clone());
272        }
273        if let Some(err) = self.error.take() {
274            return Err(err);
275        }
276        let doc = parse(self.input)?;
277
278        if TrackLocations::of(driver.state()) {
279            Source(self.input.into()).set(driver.state_mut());
280        }
281        emit(&doc, driver).map_err(|mut err| {
282            err.resolve_position(self.input.as_bytes());
283            err
284        })
285    }
286}
287
288impl<'a> de::Deserializer<'a> for Deserializer<'a> {
289    fn drive(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
290        Deserializer::drive(self, driver)
291    }
292}
293
294/// Emits an event with the byte range of its span.
295#[inline(always)]
296fn emit_at<'e, E: Into<Event<'e>>>(
297    driver: &mut DeserializeDriver<'_, '_>,
298    event: E,
299    span: Span,
300) -> Result<(), Error> {
301    driver.state_mut().set_input_range(span.start, span.end);
302    driver.emit(event)
303}
304
305/// Emits a string, borrowed if it's a slice of the input.
306// the `Cow` tells if the string is a slice of the input
307#[allow(clippy::ptr_arg)]
308#[inline(always)]
309fn emit_str<'a>(
310    driver: &mut DeserializeDriver<'_, 'a>,
311    value: &Cow<'a, str>,
312    span: Span,
313) -> Result<(), Error> {
314    driver.state_mut().set_input_range(span.start, span.end);
315    match *value {
316        Cow::Borrowed(value) => driver.emit_borrowed(value),
317        Cow::Owned(ref value) => driver.emit(value.as_str()),
318    }
319}
320
321/// Emits a key.
322///
323/// Keys are always strings in TOML, they are lexical: they can stand for
324/// values of other types (like integers).
325// the key is a `Cow` as borrowed keys are passed on for `'a`
326#[allow(clippy::ptr_arg)]
327fn emit_key<'a>(
328    driver: &mut DeserializeDriver<'_, 'a>,
329    key: &Cow<'a, str>,
330    span: Span,
331) -> Result<(), Error> {
332    driver.state_mut().set_input_range(span.start, span.end);
333    match *key {
334        Cow::Borrowed(key) => driver.emit_borrowed(Atom::Lexical(Text::borrowed(key))),
335        Cow::Owned(ref key) => driver.emit(Atom::Lexical(Text::borrowed(key.as_str()))),
336    }
337}
338
339/// A container whose events are emitted, with the index of the next child.
340enum Frame {
341    Table(usize, usize),
342    Array(usize, usize),
343}
344
345/// Emits the events of a document.
346fn emit<'a>(doc: &Document<'a>, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
347    let mut stack = vec![Frame::Table(ROOT, 0)];
348    let shape = ContainerShape::with_len(doc.tables[ROOT].entries.len());
349    emit_at(driver, Event::MapStart(shape), doc.tables[ROOT].span)?;
350
351    while let Some(frame) = stack.last_mut() {
352        let item: &Item = match *frame {
353            Frame::Table(id, ref mut index) => {
354                let table = &doc.tables[id];
355                match table.entries.get(*index) {
356                    Some(entry) => {
357                        *index += 1;
358                        emit_key(driver, &entry.key, entry.key_span)?;
359                        &entry.item
360                    }
361                    None => {
362                        stack.pop();
363                        emit_at(driver, Event::MapEnd, table.span)?;
364                        continue;
365                    }
366                }
367            }
368            Frame::Array(id, ref mut index) => {
369                let array = &doc.arrays[id];
370                match array.items.get(*index) {
371                    Some(item) => {
372                        *index += 1;
373                        item
374                    }
375                    None => {
376                        stack.pop();
377                        emit_at(driver, Event::SeqEnd, array.span)?;
378                        continue;
379                    }
380                }
381            }
382        };
383
384        match item.value {
385            Value::Table(id) => {
386                let table = &doc.tables[id];
387                // inline tables are compact so that they stay inline when
388                // they are serialized again
389                if table.kind == TableKind::Inline {
390                    Layout::Compact.set(driver.state_mut());
391                }
392                let shape = ContainerShape::with_len(table.entries.len());
393                emit_at(driver, Event::MapStart(shape), table.span)?;
394                stack.push(Frame::Table(id, 0));
395            }
396            Value::Array(id) => {
397                let array = &doc.arrays[id];
398                // same for inline arrays of tables
399                if !array.of_tables
400                    && array
401                        .items
402                        .first()
403                        .is_some_and(|x| matches!(x.value, Value::Table(_)))
404                {
405                    Layout::Compact.set(driver.state_mut());
406                }
407                let shape = ContainerShape::with_len(array.items.len());
408                emit_at(driver, Event::SeqStart(shape), array.span)?;
409                stack.push(Frame::Array(id, 0));
410            }
411            Value::Str(ref value) => emit_str(driver, value, item.span)?,
412            ref scalar => {
413                let atom = match *scalar {
414                    Value::Int(value) if value >= 0 => Atom::U64(value as u64),
415                    Value::Int(value) => Atom::I64(value),
416                    Value::UInt(value) => Atom::U64(value),
417                    Value::Float(value) => Atom::F64(value),
418                    Value::Bool(value) => Atom::Bool(value),
419                    Value::Datetime(ref value) => Atom::Ext(ExtValue::borrowed(value)),
420                    Value::Str(_) | Value::Table(_) | Value::Array(_) => unreachable!(),
421                    Value::Float32(_) | Value::FloatText(_) => {
422                        unreachable!("only used when serializing")
423                    }
424                };
425                emit_at(driver, atom, item.span)?;
426            }
427        }
428    }
429
430    Ok(())
431}
432
433fn str_from_utf8(bytes: &[u8]) -> Result<&str, Error> {
434    #[cfg(feature = "speedups")]
435    {
436        if simdutf8::basic::from_utf8(bytes).is_ok() {
437            // SAFETY: validated above
438            return Ok(unsafe { std::str::from_utf8_unchecked(bytes) });
439        }
440    }
441    std::str::from_utf8(bytes)
442        .map_err(|err| Error::with_offset(ErrorKind::Syntax, "invalid UTF-8", err.valid_up_to()))
443}
444
445/// Deserializes a value from TOML.
446///
447/// A TOML document is a table, so the value has to be deserializable from
448/// a map (such as a struct or a map type).
449///
450/// This uses the default [`DeserializerConfig`].
451pub fn from_str<'de, T: Deserialize<'de>>(s: &'de str) -> Result<T, Error> {
452    DeserializerConfig::new().from_str(s)
453}
454
455/// Deserializes a value from TOML in a byte slice.
456///
457/// The input must be UTF-8.  Otherwise this works like [`from_str`].  This
458/// uses the default [`DeserializerConfig`].
459pub fn from_slice<'de, T: Deserialize<'de>>(bytes: &'de [u8]) -> Result<T, Error> {
460    DeserializerConfig::new().from_slice(bytes)
461}