Skip to main content

deser_toml/
stream.rs

1//! Reading TOML from streams.
2#[cfg(feature = "io")]
3use std::io::Read;
4
5use deser_core::Error;
6#[cfg(feature = "io")]
7use deser_core::de::DeserializeOwned;
8use deser_core::de::{self, DeserializeDriver, Frame};
9
10use crate::de::{Deserializer, DeserializerConfig};
11
12/// Reads a TOML document from a stream (see
13/// [`deser::stream`](deser_core::stream)).
14///
15/// TOML documents cannot be split: tables can be extended anywhere in the
16/// document.  The stream is a single document which is parsed once the
17/// whole stream was read.  An empty stream is an empty table.
18///
19/// ```
20/// # #[cfg(feature = "io")] {
21/// use std::collections::BTreeMap;
22/// use deser_toml::DeserializerConfig;
23///
24/// let mut reader =
25///     DeserializerConfig::new().reader(&b"a = 1\nb = 2\n"[..]);
26/// let value: BTreeMap<String, u32> = reader.read().unwrap().unwrap();
27/// assert_eq!(value["b"], 2);
28/// assert!(reader.read::<BTreeMap<String, u32>>().unwrap().is_none());
29/// # }
30/// ```
31#[derive(Debug, Default)]
32pub struct StreamDeserializer {
33    config: DeserializerConfig,
34    // the document was read
35    done: bool,
36}
37
38impl StreamDeserializer {
39    /// Creates a stream deserializer.
40    pub fn new() -> StreamDeserializer {
41        StreamDeserializer::with_config(DeserializerConfig::new())
42    }
43
44    /// Creates a stream deserializer with the given configuration.
45    pub fn with_config(config: DeserializerConfig) -> StreamDeserializer {
46        StreamDeserializer {
47            config,
48            done: false,
49        }
50    }
51
52    /// Returns the configuration.
53    pub fn config(&self) -> &DeserializerConfig {
54        &self.config
55    }
56}
57
58impl de::StreamDeserializer for StreamDeserializer {
59    fn context(&self) -> deser_core::Context {
60        self.config.context().clone()
61    }
62
63    fn frame(&mut self, input: &[u8], eof: bool) -> Result<Frame, Error> {
64        Ok(if !eof {
65            Frame::Incomplete { consumed: 0 }
66        } else if self.done {
67            Frame::End
68        } else {
69            self.done = true;
70            Frame::Value {
71                start: 0,
72                end: input.len(),
73                consumed: input.len(),
74            }
75        })
76    }
77
78    fn drive_frame<'de>(
79        &mut self,
80        frame: &'de [u8],
81        driver: &mut DeserializeDriver<'_, 'de>,
82    ) -> Result<(), Error> {
83        Deserializer::from_slice_with_config(frame, self.config.without_context()).drive(driver)
84    }
85
86    fn is_text(&self) -> bool {
87        true
88    }
89}
90
91#[cfg(feature = "io")]
92impl DeserializerConfig {
93    /// Creates a reader of a TOML document (see
94    /// [`deser::io::Reader`](deser_core::io::Reader)).
95    ///
96    /// See [`StreamDeserializer`].
97    pub fn reader<R: Read>(&self, reader: R) -> deser_core::io::Reader<R, StreamDeserializer> {
98        deser_core::io::Reader::new(reader, StreamDeserializer::with_config(self.clone()))
99    }
100
101    /// Deserializes a document from a reader.
102    ///
103    /// See [`from_reader`].
104    pub fn from_reader<T: DeserializeOwned, R: Read>(&self, reader: R) -> Result<T, Error> {
105        deser_core::io::from_reader(reader, StreamDeserializer::with_config(self.clone()))
106    }
107}
108
109/// Deserializes a document from a reader.
110///
111/// The reader is read to the end, it does not need to be buffered.
112///
113/// ```
114/// use std::collections::BTreeMap;
115///
116/// let value: BTreeMap<String, u32> =
117///     deser_toml::from_reader(&b"a = 1"[..]).unwrap();
118/// assert_eq!(value["a"], 1);
119/// ```
120#[cfg(feature = "io")]
121pub fn from_reader<T: DeserializeOwned, R: Read>(reader: R) -> Result<T, Error> {
122    DeserializerConfig::new().from_reader(reader)
123}