Skip to main content

deser_xml/
stream.rs

1//! Reading XML documents 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 an XML document from a stream (see
13/// [`deser::stream`](deser_core::stream)).
14///
15/// The stream is a single document which is parsed once the whole stream
16/// was read (what follows the root element can only be checked at the
17/// end).  Like with [`from_slice`](crate::from_slice) the input has to be
18/// UTF-8.
19///
20/// ```
21/// # #[cfg(feature = "io")] {
22/// use deser_xml::DeserializerConfig;
23///
24/// #[derive(deser::Deserialize)]
25/// struct Link {
26///     #[deser(rename = "@href")]
27///     href: String,
28/// }
29///
30/// let mut reader =
31///     DeserializerConfig::new().reader(&br#"<a href="/x"/>"#[..]);
32/// let link: Link = reader.read().unwrap().unwrap();
33/// assert_eq!(link.href, "/x");
34/// assert!(reader.read::<Link>().unwrap().is_none());
35/// # }
36/// ```
37#[derive(Debug, Default)]
38pub struct StreamDeserializer {
39    config: DeserializerConfig,
40    // the document was read
41    done: bool,
42}
43
44impl StreamDeserializer {
45    /// Creates a stream deserializer.
46    pub fn new() -> StreamDeserializer {
47        StreamDeserializer::with_config(DeserializerConfig::new())
48    }
49
50    /// Creates a stream deserializer with the given configuration.
51    pub fn with_config(config: DeserializerConfig) -> StreamDeserializer {
52        StreamDeserializer {
53            config,
54            done: false,
55        }
56    }
57
58    /// Returns the configuration.
59    pub fn config(&self) -> &DeserializerConfig {
60        &self.config
61    }
62}
63
64impl de::StreamDeserializer for StreamDeserializer {
65    fn context(&self) -> deser_core::Context {
66        self.config.context().clone()
67    }
68
69    fn frame(&mut self, input: &[u8], eof: bool) -> Result<Frame, Error> {
70        Ok(if !eof {
71            Frame::Incomplete { consumed: 0 }
72        } else if self.done {
73            Frame::End
74        } else {
75            self.done = true;
76            Frame::Value {
77                start: 0,
78                end: input.len(),
79                consumed: input.len(),
80            }
81        })
82    }
83
84    fn drive_frame<'de>(
85        &mut self,
86        frame: &'de [u8],
87        driver: &mut DeserializeDriver<'_, 'de>,
88    ) -> Result<(), Error> {
89        Deserializer::from_slice_with_config(frame, self.config.without_context()).drive(driver)
90    }
91
92    fn is_text(&self) -> bool {
93        true
94    }
95}
96
97#[cfg(feature = "io")]
98impl DeserializerConfig {
99    /// Creates a reader of an XML document (see
100    /// [`deser::io::Reader`](deser_core::io::Reader)).
101    ///
102    /// See [`StreamDeserializer`].
103    pub fn reader<R: Read>(&self, reader: R) -> deser_core::io::Reader<R, StreamDeserializer> {
104        deser_core::io::Reader::new(reader, StreamDeserializer::with_config(self.clone()))
105    }
106
107    /// Deserializes a document from a reader.
108    ///
109    /// See [`from_reader`].
110    pub fn from_reader<T: DeserializeOwned, R: Read>(&self, reader: R) -> Result<T, Error> {
111        deser_core::io::from_reader(reader, StreamDeserializer::with_config(self.clone()))
112    }
113}
114
115/// Deserializes a document from a reader.
116///
117/// The reader is read to the end, it does not need to be buffered.
118///
119/// ```
120/// #[derive(deser::Deserialize)]
121/// struct Link {
122///     #[deser(rename = "@href")]
123///     href: String,
124/// }
125///
126/// let link: Link = deser_xml::from_reader(&br#"<a href="/x"/>"#[..]).unwrap();
127/// assert_eq!(link.href, "/x");
128/// ```
129#[cfg(feature = "io")]
130pub fn from_reader<T: DeserializeOwned, R: Read>(reader: R) -> Result<T, Error> {
131    DeserializerConfig::new().from_reader(reader)
132}