Skip to main content

deser_urlencoded/
stream.rs

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