Skip to main content

deser_csv/
de.rs

1use alloc::format;
2use alloc::string::String;
3use alloc::string::ToString;
4use alloc::sync::Arc;
5use alloc::vec::Vec;
6use core::marker::PhantomData;
7
8use deser_core::Text;
9use deser_core::de::{self, Deserialize, DeserializeDriver, Frame, LexicalRules};
10use deser_core::{Atom, Bytes, BytesFormat, ContainerShape, Error, ErrorKind, Event, Source};
11
12use crate::parser::{Dialect, Field, Options, QUOTED, Scan, Scanner, UNESCAPE, unescape};
13use crate::{Escape, Headers, Nulls, Terminator, Trim};
14
15/// Configures how delimited text is deserialized.
16///
17/// The configuration is independent of the input so it can be created once
18/// (even as a constant) and used for many inputs.  The methods
19/// [`from_str`](Self::from_str) and [`from_slice`](Self::from_slice) work
20/// like the functions of the same name.  The default is CSV as described
21/// by [RFC 4180](https://www.rfc-editor.org/rfc/rfc4180), with a header,
22/// any line ending and blank lines skipped.
23///
24/// ```
25/// use deser_csv::DeserializerConfig;
26///
27/// const SEMICOLONS: DeserializerConfig =
28///     DeserializerConfig::new().delimiter(b';');
29/// let rows: Vec<(String, u32)> = SEMICOLONS
30///     .headers(deser_csv::Headers::None)
31///     .from_str("a;1\nb;2\n")
32///     .unwrap();
33/// assert_eq!(rows, [("a".into(), 1), ("b".into(), 2)]);
34/// ```
35#[derive(Debug, Clone, PartialEq, Eq)]
36pub struct DeserializerConfig {
37    pub(crate) delimiter: u8,
38    pub(crate) quote: Option<u8>,
39    pub(crate) double_quote: bool,
40    pub(crate) escape: Escape,
41    pub(crate) terminator: Terminator,
42    pub(crate) comment: Option<u8>,
43    pub(crate) headers: Headers,
44    pub(crate) trim: Trim,
45    pub(crate) nulls: Nulls,
46    pub(crate) skip_blank_lines: bool,
47    pub(crate) flexible: bool,
48    pub(crate) lenient_quotes: bool,
49    pub(crate) sep_line: bool,
50    pub(crate) max_record_len: usize,
51    pub(crate) bytes: BytesFormat,
52    pub(crate) track_locations: bool,
53}
54
55impl Default for DeserializerConfig {
56    fn default() -> DeserializerConfig {
57        DeserializerConfig::new()
58    }
59}
60
61impl DeserializerConfig {
62    /// Creates the default configuration (CSV).
63    pub const fn new() -> DeserializerConfig {
64        DeserializerConfig {
65            delimiter: b',',
66            quote: Some(b'"'),
67            double_quote: true,
68            escape: Escape::None,
69            terminator: Terminator::Newline,
70            comment: None,
71            headers: Headers::First,
72            trim: Trim::None,
73            nulls: Nulls::None,
74            skip_blank_lines: true,
75            flexible: false,
76            lenient_quotes: false,
77            sep_line: false,
78            max_record_len: 64 * 1024 * 1024,
79            bytes: BytesFormat::BASE64,
80            track_locations: false,
81        }
82    }
83
84    /// Creates the configuration for tab separated values.
85    ///
86    /// Fields are separated by tabs and are not quoted.  Tabs, line breaks
87    /// and backslashes in fields are escaped with backslashes (`\t`, `\n`,
88    /// `\r` and `\\`) and `\N` is null (see [`Escape::Backslash`] and
89    /// [`Nulls::Text`]).  This is how databases (like PostgreSQL's `COPY`
90    /// and MySQL's `LOAD DATA`) and many tools write TSV, and it reads the
91    /// TSV of [IANA](https://www.iana.org/assignments/media-types/text/tab-separated-values)
92    /// (which cannot contain tabs and line breaks in fields) as well.  For
93    /// TSV with quotes (as written by spreadsheets) use
94    /// `DeserializerConfig::new().delimiter(b'\t')`.
95    ///
96    /// ```
97    /// use deser_csv::DeserializerConfig;
98    ///
99    /// #[derive(deser::Deserialize)]
100    /// struct Row {
101    ///     name: String,
102    ///     note: Option<String>,
103    /// }
104    ///
105    /// let rows: Vec<Row> = DeserializerConfig::tsv()
106    ///     .from_str("name\tnote\nJane\ta\\tb\nJohn\t\\N\n")
107    ///     .unwrap();
108    /// assert_eq!(rows[0].note.as_deref(), Some("a\tb"));
109    /// assert_eq!(rows[1].note, None);
110    /// ```
111    pub const fn tsv() -> DeserializerConfig {
112        DeserializerConfig::new()
113            .delimiter(b'\t')
114            .quote(None)
115            .escape(Escape::Backslash)
116            .nulls(Nulls::Text("\\N"))
117    }
118
119    /// Sets the character that separates fields (`,` by default).
120    ///
121    /// Special characters (the delimiter, quote, escape and terminator)
122    /// have to be distinct ASCII characters, otherwise deserializing fails.
123    pub const fn delimiter(mut self, delimiter: u8) -> DeserializerConfig {
124        self.delimiter = delimiter;
125        self
126    }
127
128    /// Sets the character that quotes fields (`"` by default).
129    ///
130    /// Quoted fields can contain the delimiter and line breaks.  With
131    /// `None` quotes are regular characters.
132    pub const fn quote(mut self, quote: Option<u8>) -> DeserializerConfig {
133        self.quote = quote;
134        self
135    }
136
137    /// Sets if two quotes in a quoted field are a quote (`true` by
138    /// default).
139    ///
140    /// Without doubled quotes, quotes in quoted fields have to be escaped
141    /// (see [`escape`](Self::escape)).
142    pub const fn double_quote(mut self, yes: bool) -> DeserializerConfig {
143        self.double_quote = yes;
144        self
145    }
146
147    /// Sets how characters are escaped (not at all by default).
148    pub const fn escape(mut self, escape: Escape) -> DeserializerConfig {
149        self.escape = escape;
150        self
151    }
152
153    /// Sets what ends records ([`Terminator::Newline`] by default).
154    pub const fn terminator(mut self, terminator: Terminator) -> DeserializerConfig {
155        self.terminator = terminator;
156        self
157    }
158
159    /// Sets the character that starts comment lines (none by default).
160    ///
161    /// Lines that start with it are skipped.  The character only starts a
162    /// comment at the start of a line (`a,#b` is a regular record).
163    pub const fn comment(mut self, comment: Option<u8>) -> DeserializerConfig {
164        self.comment = comment;
165        self
166    }
167
168    /// Sets where the names of the columns come from ([`Headers::First`] by
169    /// default).
170    ///
171    /// With names, records are maps of the names to the fields.  Without
172    /// names ([`Headers::None`]) records are sequences.
173    pub const fn headers(mut self, headers: Headers) -> DeserializerConfig {
174        self.headers = headers;
175        self
176    }
177
178    /// Sets which whitespace is removed ([`Trim::None`] by default).
179    ///
180    /// Spaces and tabs are removed from the start and end of unquoted
181    /// fields and around the quotes of quoted fields (`a, "b" ,c`).
182    pub const fn trim(mut self, trim: Trim) -> DeserializerConfig {
183        self.trim = trim;
184        self
185    }
186
187    /// Sets which fields are null ([`Nulls::None`] by default).
188    ///
189    /// Without nulls, empty fields are `None` for optionals of types that
190    /// do not accept the empty string (like `Option<u32>`) and `Some("")`
191    /// for strings.  Quoted fields are never null.
192    pub const fn nulls(mut self, nulls: Nulls) -> DeserializerConfig {
193        self.nulls = nulls;
194        self
195    }
196
197    /// Sets if blank lines are skipped (`true` by default).
198    ///
199    /// Otherwise a blank line is a record with a single empty field.  Lines
200    /// with only whitespace are not blank.
201    pub const fn skip_blank_lines(mut self, yes: bool) -> DeserializerConfig {
202        self.skip_blank_lines = yes;
203        self
204    }
205
206    /// Sets if records can have a different number of fields (`false` by
207    /// default).
208    ///
209    /// By default, records must have as many fields as there are columns
210    /// (or as the first record has, without names).  With flexible records,
211    /// missing fields are missing in the map and fields without names are
212    /// keyed with their index (`"3"`), so they end up in a flattened map
213    /// or are ignored like unknown fields.
214    pub const fn flexible(mut self, yes: bool) -> DeserializerConfig {
215        self.flexible = yes;
216        self
217    }
218
219    /// Sets if quotes that do not follow the rules are accepted (`false` by
220    /// default).
221    ///
222    /// By default, quotes in unquoted fields (`5'10"`) and characters after
223    /// the closing quote of a field (`"a"b`) are errors.  With lenient
224    /// quotes the quotes of unquoted fields are regular characters and
225    /// characters after the closing quote are part of the field (`ab`).
226    pub const fn lenient_quotes(mut self, yes: bool) -> DeserializerConfig {
227        self.lenient_quotes = yes;
228        self
229    }
230
231    /// Sets if a `sep=` line at the start selects the delimiter (`false` by
232    /// default).
233    ///
234    /// Excel writes and understands a first line like `sep=;` which sets
235    /// the delimiter of the file.
236    ///
237    /// ```
238    /// use std::collections::BTreeMap;
239    ///
240    /// let config = deser_csv::DeserializerConfig::new().sep_line(true);
241    /// let rows: Vec<BTreeMap<String, u32>> =
242    ///     config.from_str("sep=;\na;b\n1;2\n").unwrap();
243    /// assert_eq!(rows[0]["b"], 2);
244    /// ```
245    pub const fn sep_line(mut self, yes: bool) -> DeserializerConfig {
246        self.sep_line = yes;
247        self
248    }
249
250    /// Sets the maximum length of a record in a stream in bytes (64 MiB by
251    /// default).
252    ///
253    /// A record in a stream is buffered until it's complete.  A longer
254    /// record is an error which ends the stream, which protects from
255    /// streams that never end a record (like a quoted field that is never
256    /// closed).  Inputs in memory are not limited.
257    pub const fn max_record_len(mut self, len: usize) -> DeserializerConfig {
258        self.max_record_len = len;
259        self
260    }
261
262    /// Sets how fields are decoded into bytes.
263    ///
264    /// Types that expect bytes (like `Vec<u8>`) decode fields as base64 by
265    /// default.  Fields which are not UTF-8 are passed on as bytes (see
266    /// [bytes](deser_core::adapters#bytes)).
267    pub const fn bytes(mut self, format: BytesFormat) -> DeserializerConfig {
268        self.bytes = format;
269        self
270    }
271
272    /// Enables or disables location tracking.
273    ///
274    /// The byte range of every field is always published into the state
275    /// (see [`State::input_range`](deser_core::State::input_range)).  When
276    /// enabled additionally the input is set as source (see
277    /// [`Source`](deser_core::Source)).  This copies the input.
278    pub const fn track_locations(mut self, yes: bool) -> DeserializerConfig {
279        self.track_locations = yes;
280        self
281    }
282
283    /// Deserializes the records of a string.
284    ///
285    /// See [`from_str`](crate::from_str).
286    pub fn from_str<'de, T: Deserialize<'de>>(&self, s: &'de str) -> Result<T, Error> {
287        Deserializer::from_str_with_config(s, self).deserialize()
288    }
289
290    /// Deserializes the records of a byte slice.
291    ///
292    /// See [`from_slice`](crate::from_slice).
293    pub fn from_slice<'de, T: Deserialize<'de>>(&self, bytes: &'de [u8]) -> Result<T, Error> {
294        Deserializer::from_slice_with_config(bytes, self).deserialize()
295    }
296
297    /// Returns how records are scanned.
298    fn options(&self, header: bool) -> Options {
299        Options {
300            trim: match self.trim {
301                Trim::None => false,
302                Trim::Headers => header,
303                Trim::Fields => !header,
304                Trim::All => true,
305            },
306            skip_blank_lines: self.skip_blank_lines,
307            lenient_quotes: self.lenient_quotes,
308            max_record_len: self.max_record_len,
309        }
310    }
311
312    fn dialect(&self, delimiter: u8) -> Result<Dialect, Error> {
313        Dialect::new(
314            delimiter,
315            self.quote,
316            self.double_quote,
317            self.escape,
318            self.terminator,
319            self.comment,
320        )
321    }
322}
323
324/// The state of a stream of records.
325///
326/// This holds the names of the columns and what is needed to split the
327/// records.
328#[derive(Debug, Default)]
329pub(crate) struct StreamState {
330    // `None` before the start of the stream (BOM and `sep=` line) was read
331    dialect: Option<Dialect>,
332    scanner: Scanner,
333    names: Option<Vec<String>>,
334    // the names were read (or given, or there are none)
335    has_names: bool,
336    // the number of fields of the first record (without names)
337    expected_len: Option<usize>,
338    // decoded fields and names
339    scratch: Vec<u8>,
340}
341
342impl StreamState {
343    /// Creates the state of a stream which continues with the given names
344    /// of the columns.
345    pub(crate) fn with_headers(names: Vec<String>) -> StreamState {
346        StreamState {
347            names: Some(names),
348            has_names: true,
349            ..StreamState::default()
350        }
351    }
352
353    /// Returns the names of the columns.
354    pub(crate) fn headers(&self) -> Option<&[String]> {
355        self.names.as_deref()
356    }
357
358    /// Finds the next record.
359    ///
360    /// This works like
361    /// [`StreamDeserializer::frame`](deser_core::de::StreamDeserializer::frame).
362    /// Blank lines, comments and names are consumed without returning a
363    /// record.  The fields of the record are kept in the scanner.
364    pub(crate) fn frame(
365        &mut self,
366        config: &DeserializerConfig,
367        input: &[u8],
368        eof: bool,
369    ) -> Result<Frame, Error> {
370        if self.dialect.is_none() {
371            match self.start(config, input, eof)? {
372                Frame::Incomplete { consumed: 0 } if self.dialect.is_some() => {}
373                frame => return Ok(frame),
374            }
375        }
376        let dialect = self.dialect.as_ref().unwrap();
377        let header = !self.has_names;
378        let options = config.options(header);
379        match self.scanner.scan(dialect, input, eof, options)? {
380            Scan::Record { end, consumed } => {
381                if header {
382                    self.read_names(input)?;
383                    return Ok(Frame::Incomplete { consumed });
384                }
385                if self.names.is_none() && self.expected_len.is_none() {
386                    self.expected_len = Some(self.scanner.fields.len());
387                }
388                Ok(Frame::Value {
389                    start: 0,
390                    end,
391                    consumed,
392                })
393            }
394            Scan::Skip { consumed } => Ok(Frame::Incomplete { consumed }),
395            Scan::Incomplete => Ok(Frame::Incomplete { consumed: 0 }),
396            Scan::End => Ok(Frame::End),
397        }
398    }
399
400    /// Reads the start of the stream: the byte order mark and the `sep=`
401    /// line.
402    fn start(
403        &mut self,
404        config: &DeserializerConfig,
405        input: &[u8],
406        eof: bool,
407    ) -> Result<Frame, Error> {
408        const BOM: &[u8] = b"\xef\xbb\xbf";
409        const SEP: &[u8] = b"sep=";
410        if input.len() < BOM.len() && BOM.starts_with(input) && !eof {
411            return Ok(Frame::Incomplete { consumed: 0 });
412        }
413        if input.starts_with(b"\xff\xfe") || input.starts_with(b"\xfe\xff") {
414            return Err(Error::new(
415                ErrorKind::Unexpected,
416                "input is UTF-16, only UTF-8 is supported",
417            )
418            .with_offset(0));
419        }
420        let bom = if input.starts_with(BOM) { BOM.len() } else { 0 };
421        let rest = &input[bom..];
422        let prefix = rest.len().min(SEP.len());
423        if !config.sep_line || !rest[..prefix].eq_ignore_ascii_case(&SEP[..prefix]) {
424            return self.started(config, config.delimiter, bom);
425        }
426        // wait for the whole line (and the LF after a CR)
427        let end = match rest.iter().position(|&b| b == b'\n' || b == b'\r') {
428            Some(end) if rest[end] == b'\r' && end + 1 == rest.len() && !eof => {
429                return Ok(Frame::Incomplete { consumed: 0 });
430            }
431            Some(end) => end,
432            None if eof => rest.len(),
433            None => return Ok(Frame::Incomplete { consumed: 0 }),
434        };
435        if end != SEP.len() + 1 {
436            return self.started(config, config.delimiter, bom);
437        }
438        let mut consumed = bom + end + 1;
439        if rest.get(end) == Some(&b'\r') && rest.get(end + 1) == Some(&b'\n') {
440            consumed += 1;
441        }
442        self.started(config, rest[SEP.len()], consumed.min(input.len()))
443    }
444
445    fn started(
446        &mut self,
447        config: &DeserializerConfig,
448        delimiter: u8,
449        consumed: usize,
450    ) -> Result<Frame, Error> {
451        self.dialect = Some(config.dialect(delimiter)?);
452        if !self.has_names {
453            match config.headers {
454                Headers::First | Headers::Skip => {}
455                Headers::None => self.has_names = true,
456                Headers::Given(names) => {
457                    self.names = Some(names.iter().map(|name| name.to_string()).collect());
458                    self.has_names = true;
459                }
460            }
461        }
462        Ok(Frame::Incomplete { consumed })
463    }
464
465    /// Takes the names of the columns from the record that was scanned.
466    fn read_names(&mut self, record: &[u8]) -> Result<(), Error> {
467        if let Some((offset, msg)) = self.scanner.error {
468            return Err(Error::new(ErrorKind::Unexpected, msg).with_offset(offset));
469        }
470        let dialect = self.dialect.as_ref().unwrap();
471        let mut names = Vec::with_capacity(self.scanner.fields.len());
472        for field in &self.scanner.fields {
473            let text = &record[field.start..field.end];
474            let text = if field.flags & UNESCAPE != 0 {
475                unescape(dialect, text, field.flags & QUOTED != 0, &mut self.scratch);
476                &self.scratch[..]
477            } else {
478                text
479            };
480            match core::str::from_utf8(text) {
481                Ok(name) => names.push(name.to_string()),
482                Err(_) => {
483                    return Err(Error::new(ErrorKind::Unexpected, "name is not valid UTF-8")
484                        .with_offset(field.span_start));
485                }
486            }
487        }
488        self.names = Some(names);
489        self.has_names = true;
490        Ok(())
491    }
492
493    /// Emits the record that was found last.
494    ///
495    /// `record` holds the bytes of the record, `base` is its offset in the
496    /// input for the input ranges.
497    pub(crate) fn emit_record<'de>(
498        &mut self,
499        config: &DeserializerConfig,
500        record: &'de [u8],
501        base: usize,
502        driver: &mut DeserializeDriver<'_, 'de>,
503    ) -> Result<(), Error> {
504        let StreamState {
505            ref dialect,
506            ref scanner,
507            ref names,
508            expected_len,
509            ref mut scratch,
510            ..
511        } = *self;
512        let self_names_len = names.as_ref().map(Vec::len);
513        let dialect = dialect
514            .as_ref()
515            .expect("records are emitted after the start");
516        if let Some((offset, msg)) = scanner.error {
517            return Err(Error::new(ErrorKind::Unexpected, msg).with_offset(base + offset));
518        }
519        if config.bytes != BytesFormat::BASE64 {
520            config.bytes.set(driver.state_mut());
521        }
522        // everything in a CSV file is text, like in a query string
523        LexicalRules::LENIENT.set(driver.state_mut());
524        let fields = &scanner.fields[..];
525        // with `Headers::Skip` the names are known but not used
526        let names = match config.headers {
527            Headers::Skip => None,
528            _ => names.as_ref(),
529        };
530        let expected = match (names, self_names_len) {
531            (Some(names), _) => names.len(),
532            (None, Some(len)) => len,
533            (None, None) => expected_len.unwrap_or(fields.len()),
534        };
535        if fields.len() != expected && !config.flexible {
536            return Err(Error::new(
537                ErrorKind::Unexpected,
538                format!(
539                    "record has {} field{}, expected {}",
540                    fields.len(),
541                    if fields.len() == 1 { "" } else { "s" },
542                    expected
543                ),
544            )
545            .with_offset(base));
546        }
547
548        let shape = ContainerShape::new().with_len(fields.len());
549        let emitter = FieldEmitter {
550            dialect,
551            nulls: config.nulls,
552            record,
553            // the special characters are ASCII, so if the record is UTF-8
554            // all of its fields are
555            record_is_utf8: record.is_ascii() || core::str::from_utf8(record).is_ok(),
556            base,
557        };
558        // the start and end of the record are at its start and end (for
559        // errors like missing fields)
560        let end = base + record.len();
561        driver.state_mut().set_input_range(base, base);
562        match names {
563            Some(names) => {
564                // header names can repeat: records are multimaps
565                driver.emit(Event::MapStart(shape.with_multimap(true)))?;
566                for (index, field) in fields.iter().enumerate() {
567                    emitter.set_range(driver, field);
568                    match names.get(index) {
569                        // the names are only valid for this call, sinks
570                        // that keep them copy them
571                        Some(name) => driver.emit(Atom::Lexical(Text::borrowed(name.as_str())))?,
572                        None => driver.emit(Atom::Lexical(Text::owned(index.to_string())))?,
573                    }
574                    emitter.emit(driver, field, scratch)?;
575                }
576                driver.state_mut().set_input_range(end, end);
577                driver.emit(Event::MapEnd)
578            }
579            None => {
580                driver.emit(Event::SeqStart(shape))?;
581                for field in fields {
582                    emitter.emit(driver, field, scratch)?;
583                }
584                driver.state_mut().set_input_range(end, end);
585                driver.emit(Event::SeqEnd)
586            }
587        }
588    }
589}
590
591/// Emits the fields of a record.
592struct FieldEmitter<'a, 'de> {
593    dialect: &'a Dialect,
594    nulls: Nulls,
595    record: &'de [u8],
596    record_is_utf8: bool,
597    base: usize,
598}
599
600impl<'de> FieldEmitter<'_, 'de> {
601    #[inline]
602    fn set_range(&self, driver: &mut DeserializeDriver<'_, 'de>, field: &Field) {
603        driver
604            .state_mut()
605            .set_input_range(self.base + field.span_start, self.base + field.span_end);
606    }
607
608    #[inline]
609    fn emit(
610        &self,
611        driver: &mut DeserializeDriver<'_, 'de>,
612        field: &Field,
613        scratch: &mut Vec<u8>,
614    ) -> Result<(), Error> {
615        self.set_range(driver, field);
616        let text = &self.record[field.start..field.end];
617        if field.flags & QUOTED == 0 {
618            match self.nulls {
619                Nulls::Empty if text.is_empty() => return driver.emit(Atom::Null),
620                Nulls::Text(null) if text == null.as_bytes() => return driver.emit(Atom::Null),
621                _ => {}
622            }
623        }
624        if field.flags & UNESCAPE != 0 {
625            unescape(self.dialect, text, field.flags & QUOTED != 0, scratch);
626            // the decoded text is only valid for the call
627            match core::str::from_utf8(scratch) {
628                Ok(text) => driver.emit(Atom::Lexical(Text::borrowed(text))),
629                Err(_) => driver.emit(Atom::Bytes(Bytes::borrowed(scratch))),
630            }
631        } else if self.record_is_utf8 {
632            // SAFETY: the record is UTF-8 and fields start and end at ASCII
633            // characters (or the start and end of the record)
634            let text = unsafe { core::str::from_utf8_unchecked(text) };
635            driver.emit_borrowed(Atom::Lexical(Text::borrowed(text)))
636        } else {
637            match core::str::from_utf8(text) {
638                Ok(text) => driver.emit_borrowed(Atom::Lexical(Text::borrowed(text))),
639                Err(_) => driver.emit_borrowed(Atom::Bytes(Bytes::borrowed(text))),
640            }
641        }
642    }
643}
644
645/// Deserializes delimited text.
646///
647/// Most of the time the [`from_str`](crate::from_str) and
648/// [`from_slice`](crate::from_slice) functions (or the methods of the same
649/// name on [`DeserializerConfig`]) are all that is needed: they deserialize
650/// all records as a sequence.  The deserializer can also read one record
651/// at a time (see [`records`](Self::records)) and configure the driver, for
652/// instance to add layers:
653///
654/// ```
655/// use deser_path::{Path, PathLayer};
656/// use deser_csv::Deserializer;
657///
658/// #[derive(Debug, deser::Deserialize)]
659/// struct Row {
660///     name: String,
661///     age: u32,
662/// }
663///
664/// let err = Deserializer::from_str("name,age\njane,42\njohn,x\n")
665///     .deserialize_with::<Vec<Row>, _>(|driver| {
666///         driver.push_layer(PathLayer::new())
667///     })
668///     .unwrap_err();
669/// assert_eq!(err.message(), "invalid value \"x\", expected u32");
670/// assert_eq!(err.attachment::<Path>().unwrap().to_string(), "[1].age");
671/// assert_eq!((err.line(), err.column()), (Some(3), Some(6)));
672/// ```
673pub struct Deserializer<'a> {
674    input: &'a [u8],
675    pos: usize,
676    config: DeserializerConfig,
677    state: StreamState,
678    failed: bool,
679    // the input as source (with `track_locations`)
680    source: Option<Arc<str>>,
681}
682
683impl<'a> Deserializer<'a> {
684    /// Creates a new deserializer for a string.
685    #[allow(clippy::should_implement_trait)]
686    pub fn from_str(input: &'a str) -> Deserializer<'a> {
687        Deserializer::from_slice_with_config(input.as_bytes(), &DeserializerConfig::new())
688    }
689
690    /// Creates a new deserializer for a string with the given configuration.
691    pub fn from_str_with_config(input: &'a str, config: &DeserializerConfig) -> Deserializer<'a> {
692        Deserializer::from_slice_with_config(input.as_bytes(), config)
693    }
694
695    /// Creates a new deserializer for a byte slice.
696    ///
697    /// Fields which are not UTF-8 are passed on as bytes.
698    pub fn from_slice(input: &'a [u8]) -> Deserializer<'a> {
699        Deserializer::from_slice_with_config(input, &DeserializerConfig::new())
700    }
701
702    /// Creates a new deserializer for a byte slice with the given
703    /// configuration.
704    pub fn from_slice_with_config(
705        input: &'a [u8],
706        config: &DeserializerConfig,
707    ) -> Deserializer<'a> {
708        Deserializer {
709            input,
710            pos: 0,
711            config: config.clone(),
712            state: StreamState::default(),
713            failed: false,
714            source: None,
715        }
716    }
717
718    /// Returns the configuration.
719    pub fn config(&self) -> &DeserializerConfig {
720        &self.config
721    }
722
723    /// Returns the names of the columns.
724    ///
725    /// They are read with the first record.
726    pub fn headers(&self) -> Option<&[String]> {
727        self.state.headers()
728    }
729
730    /// Returns `true` if there are no more records.
731    ///
732    /// This is also the case after an error that the input cannot recover
733    /// from.  Blank lines and comments are not records, but they are only
734    /// skipped when the next record is read.
735    pub fn is_end(&self) -> bool {
736        self.failed || self.pos == self.input.len()
737    }
738
739    /// Deserializes all records as a sequence.
740    ///
741    /// To configure the deserialization (for instance to add layers) use
742    /// [`deserialize_with`](Self::deserialize_with).
743    pub fn deserialize<T: Deserialize<'a>>(&mut self) -> Result<T, Error> {
744        de::Deserializer::deserialize(self)
745    }
746
747    /// Deserializes all records as a sequence with a configured driver.
748    ///
749    /// The callback is invoked with the driver before the value is
750    /// deserialized, for instance to add [`Layer`](deser_core::de::Layer)s.
751    pub fn deserialize_with<T, F>(&mut self, setup: F) -> Result<T, Error>
752    where
753        T: Deserialize<'a>,
754        F: FnOnce(&mut DeserializeDriver<'_, 'a>),
755    {
756        de::Deserializer::deserialize_with(self, setup)
757    }
758
759    /// Deserializes the next record.
760    ///
761    /// Returns `None` if there are no more records.  Errors of a record
762    /// (like a field that does not fit the type) only discard the record,
763    /// the next call continues with the next record.
764    ///
765    /// ```
766    /// #[derive(deser::Deserialize)]
767    /// struct Row {
768    ///     name: String,
769    ///     age: u32,
770    /// }
771    ///
772    /// let mut de = deser_csv::Deserializer::from_str(
773    ///     "name,age\njane,42\njohn,x\nmax,7\n",
774    /// );
775    /// assert_eq!(de.deserialize_record::<Row>().unwrap().unwrap().age, 42);
776    /// assert!(de.deserialize_record::<Row>().is_err());
777    /// assert_eq!(de.deserialize_record::<Row>().unwrap().unwrap().age, 7);
778    /// assert!(de.deserialize_record::<Row>().unwrap().is_none());
779    /// ```
780    pub fn deserialize_record<T: Deserialize<'a>>(&mut self) -> Result<Option<T>, Error> {
781        self.deserialize_record_with(|_| {})
782    }
783
784    /// Deserializes the next record with a configured driver.
785    ///
786    /// See [`deserialize_record`](Self::deserialize_record).
787    pub fn deserialize_record_with<T, F>(&mut self, setup: F) -> Result<Option<T>, Error>
788    where
789        T: Deserialize<'a>,
790        F: FnOnce(&mut DeserializeDriver<'_, 'a>),
791    {
792        let mut out = None;
793        {
794            let mut driver = DeserializeDriver::new(&mut out);
795            setup(&mut driver);
796            if !self.drive_record(&mut driver)? {
797                return Ok(None);
798            }
799        }
800        out.ok_or_else(|| Error::new(ErrorKind::EndOfFile, "empty record"))
801            .map(Some)
802    }
803
804    /// Returns an iterator over the remaining records.
805    ///
806    /// Errors of records are returned and the iteration continues with the
807    /// next record (see [`deserialize_record`](Self::deserialize_record)).
808    pub fn records<T: Deserialize<'a>>(&mut self) -> Records<'_, 'a, T> {
809        Records {
810            de: self,
811            _marker: PhantomData,
812        }
813    }
814
815    /// Feeds the events of the next record into the given driver.
816    ///
817    /// Returns `false` if there are no more records.
818    pub fn drive_record(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<bool, Error> {
819        let rv = self.drive_record_impl(driver);
820        rv.map_err(|err| err.resolve_position(self.input))
821    }
822
823    fn drive_record_impl(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<bool, Error> {
824        let Some((start, end)) = self.next_record()? else {
825            return Ok(false);
826        };
827        let input = self.input;
828        self.set_source(driver);
829        self.state
830            .emit_record(&self.config, &input[start..end], start, driver)?;
831        Ok(true)
832    }
833
834    /// Sets the input as source (with `track_locations`).
835    fn set_source(&mut self, driver: &mut DeserializeDriver<'_, 'a>) {
836        if self.config.track_locations {
837            let input = self.input;
838            let source = self
839                .source
840                .get_or_insert_with(|| String::from_utf8_lossy(input).into());
841            Source::set(driver.state_mut(), source.clone());
842        }
843    }
844
845    /// Finds the next record and returns its range.
846    fn next_record(&mut self) -> Result<Option<(usize, usize)>, Error> {
847        if self.failed {
848            return Ok(None);
849        }
850        loop {
851            let input = &self.input[self.pos..];
852            let frame = match self.state.frame(&self.config, input, true) {
853                Ok(frame) => frame,
854                Err(err) => {
855                    // errors of the structure end the input
856                    self.failed = true;
857                    return Err(err.shift_offset(self.pos));
858                }
859            };
860            match frame {
861                Frame::Value {
862                    start,
863                    end,
864                    consumed,
865                } => {
866                    let range = (self.pos + start, self.pos + end);
867                    self.pos += consumed;
868                    return Ok(Some(range));
869                }
870                Frame::Incomplete { consumed } => self.pos += consumed,
871                Frame::End => return Ok(None),
872            }
873        }
874    }
875
876    /// Parses the input and feeds all records as a sequence into the given
877    /// driver.
878    ///
879    /// Fields that do not need to be decoded are passed on borrowed from
880    /// the input (see
881    /// [`emit_borrowed`](DeserializeDriver::emit_borrowed)).
882    pub fn drive(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
883        let rv = self.drive_impl(driver);
884        rv.map_err(|err| err.resolve_position(self.input))
885    }
886
887    fn drive_impl(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
888        self.set_source(driver);
889        let input = self.input;
890        driver.emit(Event::seq_start())?;
891        while let Some((start, end)) = self.next_record()? {
892            self.state
893                .emit_record(&self.config, &input[start..end], start, driver)?;
894        }
895        driver.emit(Event::SeqEnd)
896    }
897}
898
899impl<'a> de::Deserializer<'a> for Deserializer<'a> {
900    fn drive(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
901        Deserializer::drive(self, driver)
902    }
903}
904
905/// An iterator over the records of a [`Deserializer`].
906///
907/// See [`Deserializer::records`].
908pub struct Records<'d, 'a, T> {
909    de: &'d mut Deserializer<'a>,
910    _marker: PhantomData<fn() -> T>,
911}
912
913impl<'a, T: Deserialize<'a>> Iterator for Records<'_, 'a, T> {
914    type Item = Result<T, Error>;
915
916    fn next(&mut self) -> Option<Self::Item> {
917        self.de.deserialize_record().transpose()
918    }
919}
920
921/// Moves the offset of an error.
922trait ShiftOffset {
923    fn shift_offset(self, base: usize) -> Self;
924}
925
926impl ShiftOffset for Error {
927    fn shift_offset(self, base: usize) -> Error {
928        match self.offset() {
929            Some(offset) => self.with_offset(base + offset),
930            None => self,
931        }
932    }
933}