Skip to main content

deser_csv/
stream.rs

1//! Reading delimited text from streams.
2#[cfg(feature = "io")]
3use std::io::Read;
4
5use alloc::string::String;
6use deser_core::Error;
7#[cfg(feature = "io")]
8use deser_core::de::DeserializeOwned;
9use deser_core::de::{self, DeserializeDriver, Frame};
10
11use crate::de::{DeserializerConfig, StreamState};
12
13/// Reads the records of a stream (see [`deser::stream`](deser_core::stream)).
14///
15/// Every value of the stream is a record.  The names of the columns are
16/// read before the first record (see [`headers`](Self::headers)).  Errors
17/// of records (like fields that do not fit the type or records with the
18/// wrong number of fields) only discard the record, reading continues with
19/// the next one.  Errors of the stream (like a record that exceeds
20/// [`max_record_len`](DeserializerConfig::max_record_len)) end it.
21///
22/// ```
23/// # #[cfg(feature = "io")] {
24/// use deser_csv::DeserializerConfig;
25///
26/// #[derive(deser::Deserialize)]
27/// struct Row {
28///     name: String,
29///     age: u32,
30/// }
31///
32/// let mut reader =
33///     DeserializerConfig::new().reader(&b"name,age\njane,42\njohn,23\n"[..]);
34/// let rows = reader.iter::<Row>().collect::<Result<Vec<_>, _>>().unwrap();
35/// assert_eq!(rows[1].age, 23);
36/// # }
37/// ```
38///
39/// Records are parsed like with a [`Deserializer`](crate::Deserializer), so
40/// they can borrow from the stream's buffer (see
41/// [`InputBuffer::deserialize`](deser_core::stream::InputBuffer::deserialize)).
42/// The input ranges (and thus locations) of fields refer to the start of
43/// their record.
44#[derive(Debug)]
45pub struct StreamDeserializer {
46    config: DeserializerConfig,
47    state: StreamState,
48}
49
50impl Default for StreamDeserializer {
51    fn default() -> StreamDeserializer {
52        StreamDeserializer::new()
53    }
54}
55
56impl StreamDeserializer {
57    /// Creates a stream deserializer.
58    pub fn new() -> StreamDeserializer {
59        StreamDeserializer::with_config(&DeserializerConfig::new())
60    }
61
62    /// Creates a stream deserializer with the given configuration.
63    pub fn with_config(config: &DeserializerConfig) -> StreamDeserializer {
64        StreamDeserializer {
65            config: config.clone(),
66            state: StreamState::default(),
67        }
68    }
69
70    /// Creates a stream deserializer for a stream which continues with the
71    /// given names of the columns.
72    ///
73    /// The stream does not start with names (they are not read from the
74    /// first record), for instance because it's the second half of a file:
75    ///
76    /// ```
77    /// # #[cfg(feature = "io")] {
78    /// use deser::io::Reader;
79    /// use deser_csv::{DeserializerConfig, StreamDeserializer};
80    ///
81    /// #[derive(deser::Deserialize)]
82    /// struct Row {
83    ///     name: String,
84    ///     age: u32,
85    /// }
86    ///
87    /// let de = StreamDeserializer::with_headers(&DeserializerConfig::new(), ["name", "age"]);
88    /// let mut reader = Reader::new(&b"jane,42\n"[..], de);
89    /// let row: Row = reader.read().unwrap().unwrap();
90    /// assert_eq!((row.name.as_str(), row.age), ("jane", 42));
91    /// # }
92    /// ```
93    pub fn with_headers<I, S>(config: &DeserializerConfig, names: I) -> StreamDeserializer
94    where
95        I: IntoIterator<Item = S>,
96        S: Into<String>,
97    {
98        StreamDeserializer {
99            config: config.clone(),
100            state: StreamState::with_headers(names.into_iter().map(Into::into).collect()),
101        }
102    }
103
104    /// Returns the configuration.
105    pub fn config(&self) -> &DeserializerConfig {
106        &self.config
107    }
108
109    /// Returns the names of the columns.
110    ///
111    /// This is `None` until the first record was read (with
112    /// [`Headers::First`](crate::Headers::First)) or if records have no
113    /// names ([`Headers::None`](crate::Headers::None)).
114    pub fn headers(&self) -> Option<&[String]> {
115        self.state.headers()
116    }
117}
118
119impl de::StreamDeserializer for StreamDeserializer {
120    fn frame(&mut self, input: &[u8], eof: bool) -> Result<Frame, Error> {
121        self.state.frame(&self.config, input, eof)
122    }
123
124    fn drive_frame<'de>(
125        &mut self,
126        frame: &'de [u8],
127        driver: &mut DeserializeDriver<'_, 'de>,
128    ) -> Result<(), Error> {
129        self.state
130            .emit_record(&self.config, frame, 0, driver)
131            .map_err(|err| err.resolve_position(frame))
132    }
133
134    fn is_text(&self) -> bool {
135        true
136    }
137}
138
139#[cfg(feature = "io")]
140impl DeserializerConfig {
141    /// Creates a reader of a stream of records (see
142    /// [`deser::io::Reader`](deser_core::io::Reader)).
143    ///
144    /// Every value is a record, see [`StreamDeserializer`].
145    pub fn reader<R: Read>(&self, reader: R) -> deser_core::io::Reader<R, StreamDeserializer> {
146        deser_core::io::Reader::new(reader, StreamDeserializer::with_config(self))
147    }
148
149    /// Deserializes the records of a reader.
150    ///
151    /// See [`from_reader`](crate::from_reader).
152    pub fn from_reader<T: DeserializeOwned, R: Read>(&self, mut reader: R) -> Result<T, Error> {
153        let mut input = alloc::vec::Vec::new();
154        reader.read_to_end(&mut input)?;
155        self.from_slice(&input)
156    }
157}
158
159/// Deserializes the records of a reader.
160///
161/// This works like [`from_str`](crate::from_str): all records are
162/// deserialized as a sequence.  The reader is read to the end, it does not
163/// need to be buffered.  To read one record at a time use
164/// [`DeserializerConfig::reader`].
165///
166/// ```
167/// use std::collections::BTreeMap;
168///
169/// let rows: Vec<BTreeMap<String, u32>> =
170///     deser_csv::from_reader(&b"a,b\n1,2\n"[..]).unwrap();
171/// assert_eq!(rows[0]["b"], 2);
172/// ```
173#[cfg(feature = "io")]
174pub fn from_reader<T: DeserializeOwned, R: Read>(reader: R) -> Result<T, Error> {
175    DeserializerConfig::new().from_reader(reader)
176}