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: config.clone(),
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 frame(&mut self, input: &[u8], eof: bool) -> Result<Frame, Error> {
66 Ok(if !eof {
67 Frame::Incomplete { consumed: 0 }
68 } else if self.done {
69 Frame::End
70 } else {
71 self.done = true;
72 Frame::Value {
73 start: 0,
74 end: input.len(),
75 consumed: input.len(),
76 }
77 })
78 }
79
80 fn drive_frame<'de>(
81 &mut self,
82 frame: &'de [u8],
83 driver: &mut DeserializeDriver<'_, 'de>,
84 ) -> Result<(), Error> {
85 Deserializer::from_slice_with_config(frame, &self.config).drive(driver)
86 }
87
88 fn is_text(&self) -> bool {
89 true
90 }
91}
92
93#[cfg(feature = "io")]
94impl DeserializerConfig {
95 /// Creates a reader of an XML document (see
96 /// [`deser::io::Reader`](deser_core::io::Reader)).
97 ///
98 /// See [`StreamDeserializer`].
99 pub fn reader<R: Read>(&self, reader: R) -> deser_core::io::Reader<R, StreamDeserializer> {
100 deser_core::io::Reader::new(reader, StreamDeserializer::with_config(self))
101 }
102
103 /// Deserializes a document from a reader.
104 ///
105 /// See [`from_reader`](crate::from_reader).
106 pub fn from_reader<T: DeserializeOwned, R: Read>(&self, reader: R) -> Result<T, Error> {
107 deser_core::io::from_reader(reader, StreamDeserializer::with_config(self))
108 }
109}
110
111/// Deserializes a document from a reader.
112///
113/// The reader is read to the end, it does not need to be buffered.
114///
115/// ```
116/// #[derive(deser::Deserialize)]
117/// struct Link {
118/// #[deser(rename = "@href")]
119/// href: String,
120/// }
121///
122/// let link: Link = deser_xml::from_reader(&br#"<a href="/x"/>"#[..]).unwrap();
123/// assert_eq!(link.href, "/x");
124/// ```
125#[cfg(feature = "io")]
126pub fn from_reader<T: DeserializeOwned, R: Read>(reader: R) -> Result<T, Error> {
127 DeserializerConfig::new().from_reader(reader)
128}