csv/reader.rs
1#[cfg(feature = "serde")]
2use alloc::collections::BTreeMap;
3#[cfg(feature = "serde")]
4use alloc::sync::Arc;
5use alloc::{
6 string::{String, ToString},
7 vec::Vec,
8};
9use core::fmt;
10
11use crate::error::{ReadError, ReadErrorKind};
12
13/// Custom read abstraction that allows `Reader` to work without `std::io::Read`.
14///
15/// This trait is automatically implemented for `&[u8]` and, when the `std`
16/// feature is enabled, for any `std::io::Read` type.
17pub trait Read {
18 /// Read data into `buf`, appending to its contents.
19 ///
20 /// Returns `Ok(true)` when at least one byte was appended to `buf`, or
21 /// `Ok(false)` to signal end-of-input.
22 ///
23 /// Implementations **must not** return `Ok(true)` without appending at
24 /// least one byte. Doing so is a contract violation; rather than spinning
25 /// or panicking, the [`Reader`] reports [`ReadErrorKind::NoProgress`] and
26 /// stops reading.
27 fn read(&mut self, buf: &mut Vec<u8>) -> Result<bool, ReadError>;
28}
29
30#[cfg(not(feature = "std"))]
31impl Read for &[u8] {
32 fn read(&mut self, buf: &mut Vec<u8>) -> Result<bool, ReadError> {
33 let chunk = 16384;
34 let to_copy = chunk.min(self.len());
35 if to_copy == 0 {
36 return Ok(false);
37 }
38 buf.extend_from_slice(&self[..to_copy]);
39 *self = &self[to_copy..];
40 Ok(true)
41 }
42}
43
44#[cfg(feature = "std")]
45impl<R: std::io::Read> Read for R {
46 fn read(&mut self, buf: &mut Vec<u8>) -> Result<bool, ReadError> {
47 let mut tmp = [0u8; 16384];
48 let n = std::io::Read::read(self, &mut tmp)?;
49 if n == 0 {
50 return Ok(false);
51 }
52 buf.extend_from_slice(&tmp[..n]);
53 Ok(true)
54 }
55}
56
57#[derive(Clone, Copy, Debug, PartialEq)]
58enum State {
59 StartOfField,
60 InUnquoted,
61 InQuoted,
62 AfterQuote,
63}
64
65#[derive(Clone, Copy, Debug)]
66enum Src {
67 Buf,
68 Scratch,
69}
70
71#[derive(Clone, Copy, Debug)]
72struct RawField {
73 start: usize,
74 end: usize,
75 src: Src,
76}
77
78#[derive(Clone, Copy, Debug, PartialEq)]
79pub struct FieldRange {
80 pub start: usize,
81 pub end: usize,
82}
83
84/// A pull-based CSV reader that parses records from any [`Read`] source.
85///
86/// The reader supports both in-memory slices (`&[u8]`) and streaming I/O sources
87/// (`std::io::Read`) via the custom [`Read`] trait. Rows are parsed on-demand
88/// by calling [`rows`](Self::rows) or [`rows_bytes`](Self::rows_bytes).
89///
90/// # Configuration
91///
92/// Use builder methods for a fluent setup:
93/// - [`set_delimiter`](Self::set_delimiter) — change the field separator (default `,`)
94/// - [`set_flexible`](Self::set_flexible) — allow variable-length rows (default `false`)
95/// - [`set_headers`](Self::set_headers) — supply column names without parsing
96/// - [`set_max_record_bytes`](Self::set_max_record_bytes),
97/// [`set_max_field_bytes`](Self::set_max_field_bytes) and
98/// [`set_max_columns`](Self::set_max_columns) — opt-in resource limits
99///
100/// # Headers
101///
102/// Call [`parse_headers`](Self::parse_headers) to treat the first row as column
103/// names. After doing so, [`headers`](Self::headers) returns a `Some` slice and
104/// serde deserialization (with the `serde` feature) can match by field name.
105///
106/// # Errors
107///
108/// Parsing errors (unterminated quotes, trailing content after a quoted field,
109/// inconsistent field counts) are stored on the returned row and surfaced when
110/// the row's fields are accessed. I/O errors are also stored on the row. This
111/// allows iteration to continue past malformed rows: when a record is
112/// malformed, the reader skips to the next record boundary before parsing the
113/// following record.
114///
115/// Errors are reported against the line on which the offending record started.
116///
117/// # Resource limits
118///
119/// By default the reader imposes no size limits, so a single enormous record
120/// can consume an unbounded amount of memory. Applications that parse
121/// untrusted input should set [`set_max_record_bytes`](Self::set_max_record_bytes)
122/// (and optionally [`set_max_field_bytes`](Self::set_max_field_bytes) /
123/// [`set_max_columns`](Self::set_max_columns)); exceeding a limit produces an
124/// error on the row instead of exhausting memory.
125///
126/// # Iteration
127///
128/// Produces owned [`Row`] or [`BytesRow`] values. A [`Row`] validates UTF-8
129/// on field access; [`BytesRow`] does not. Rows can outlive the reader.
130///
131/// # Examples
132///
133/// ```rust
134/// use csv::Reader;
135///
136/// let data = b"name,age\nAlice,30\nBob,25\n";
137/// let mut reader = Reader::new(&data[..]);
138///
139/// // Parse the first row as headers.
140/// let headers = reader.parse_headers().unwrap();
141/// assert_eq!(headers, &["name", "age"]);
142///
143/// // Iterate over data rows.
144/// for row in reader.rows() {
145/// for field in row.iter() {
146/// let _: &str = field.unwrap();
147/// }
148/// }
149/// ```
150///
151/// ```no_run
152/// # #[cfg(feature = "std")] {
153/// # use csv::Reader;
154/// let file = std::fs::File::open("data.csv").unwrap();
155/// let mut reader = Reader::new(file).set_delimiter(b';');
156///
157/// for row in reader.rows() {
158/// let name = row.get(0).unwrap().unwrap();
159/// println!("{name}");
160/// }
161/// # }
162/// ```
163pub struct Reader<R: Read> {
164 /// Raw input data read from source.
165 buf: Vec<u8>,
166 /// Temporary storage for quoted field content (unescaped).
167 scratch: Vec<u8>,
168 /// Field ranges into `buf` or `scratch` for the current row.
169 ranges: Vec<RawField>,
170 /// Start of unconsumed data in `buf`.
171 start: usize,
172 /// End of valid data in `buf`.
173 end: usize,
174 /// Number of bytes dropped from the front of `buf` by [`Reader::compact`].
175 ///
176 /// The absolute stream offset of `buf[start]` is `discarded + start`.
177 discarded: usize,
178 /// Absolute stream offset at which the current record started.
179 record_start: usize,
180 /// Physical line number (1-based) of the byte at `buf[start]`.
181 line: usize,
182 /// Physical line number on which the current record started.
183 record_line: usize,
184 /// Start of current unquoted field within `buf`.
185 field_start: usize,
186 /// Start of current quoted field within `scratch`.
187 scratch_field_start: usize,
188 /// Current parser state machine position.
189 state: State,
190 /// Field delimiter byte (default `,`).
191 delimiter: u8,
192 /// If true, rows may have varying field counts.
193 flexible: bool,
194 /// Expected field count per row, inferred from the first data row.
195 num_fields: Option<usize>,
196 /// True once `parse_headers` or `set_headers` has been called.
197 headers_parsed: bool,
198 /// A bare `\r` was the last byte of the previous buffer; next `\n` should be skipped.
199 pending_cr: bool,
200 /// The previous quoted-content slice ended with a bare `\r`; a leading `\n`
201 /// in the next slice continues that line break and must not be counted twice.
202 pending_lf_quoted: bool,
203 /// True once the leading byte-order mark has been considered.
204 bom_checked: bool,
205 /// If true, a UTF-8 byte-order mark at the very start of the input is skipped.
206 strip_bom: bool,
207 /// Maximum accepted size of a single record, in bytes (opt-in).
208 max_record_bytes: Option<usize>,
209 /// Maximum accepted size of a single field, in bytes (opt-in).
210 max_field_bytes: Option<usize>,
211 /// Maximum accepted number of columns per record (opt-in).
212 max_columns: Option<usize>,
213 /// Column names, populated by `parse_headers` or `set_headers`.
214 headers: Vec<String>,
215 #[cfg(feature = "serde")]
216 /// Map from header name -> column index for serde field lookup.
217 header_map: Option<Arc<BTreeMap<String, usize>>>,
218 #[cfg(feature = "serde")]
219 /// True when `headers` contains duplicate names, which makes name-based
220 /// deserialization ambiguous.
221 duplicate_headers: bool,
222 /// The underlying data source.
223 source: R,
224 /// True when the source has signalled end-of-input.
225 eof: bool,
226}
227
228// ── Common methods (always available) ─────────────────────────────────
229
230impl<R: Read> Reader<R> {
231 /// Creates a new `Reader` from any [`Read`] source.
232 ///
233 /// This works with `&[u8]`, `std::io::Cursor`, `std::fs::File`, etc.
234 pub fn new(source: R) -> Self {
235 Reader {
236 buf: Vec::with_capacity(65536),
237 scratch: Vec::new(),
238 ranges: Vec::new(),
239 start: 0,
240 end: 0,
241 discarded: 0,
242 record_start: 0,
243 line: 1,
244 record_line: 1,
245 field_start: 0,
246 scratch_field_start: 0,
247 state: State::StartOfField,
248 delimiter: b',',
249 flexible: false,
250 num_fields: None,
251 headers_parsed: false,
252 pending_cr: false,
253 pending_lf_quoted: false,
254 bom_checked: false,
255 strip_bom: true,
256 max_record_bytes: None,
257 max_field_bytes: None,
258 max_columns: None,
259 headers: Vec::new(),
260 #[cfg(feature = "serde")]
261 header_map: None,
262 #[cfg(feature = "serde")]
263 duplicate_headers: false,
264 source,
265 eof: false,
266 }
267 }
268
269 /// Sets the field delimiter byte (default is `,`).
270 ///
271 /// # Panics
272 ///
273 /// Panics if `byte` is `"`, `\r` or `\n`. These bytes carry structural
274 /// meaning in CSV and cannot be used as a delimiter: `"` would disable
275 /// quoting, and `\r`/`\n` would make record boundaries unrepresentable,
276 /// causing the whole input to be read as a single record.
277 pub fn set_delimiter(mut self, byte: u8) -> Self {
278 assert!(
279 byte != b'"' && byte != b'\r' && byte != b'\n',
280 "invalid CSV delimiter {byte:#04x}: `\"`, `\\r` and `\\n` are not allowed"
281 );
282 self.delimiter = byte;
283 self
284 }
285
286 /// Sets whether variable field counts are allowed (default is `false`).
287 pub fn set_flexible(mut self, yes: bool) -> Self {
288 self.flexible = yes;
289 self
290 }
291
292 /// Controls whether a UTF-8 byte-order mark (`U+FEFF`, the bytes
293 /// `EF BB BF`) at the very start of the input is skipped (default is
294 /// `true`).
295 ///
296 /// This is what makes files produced by Excel, which writes UTF-8 CSV with
297 /// a BOM by default, work with [`parse_headers`](Self::parse_headers) and
298 /// serde: without it the first header would be `"\u{feff}name"` and would
299 /// match no struct field.
300 ///
301 /// Only the first three bytes of the stream are considered, and only once.
302 /// A BOM anywhere else in the input is always treated as data.
303 ///
304 /// Pass `false` to keep the mark as part of the first field.
305 pub fn set_strip_bom(mut self, yes: bool) -> Self {
306 self.strip_bom = yes;
307 self
308 }
309
310 /// Rejects any record longer than `max` bytes.
311 ///
312 /// This is the main defence against a single crafted record exhausting
313 /// memory. When a record exceeds the limit the row carries a
314 /// [`ReadErrorKind::RecordTooLarge`] error and reading stops, because the
315 /// remainder of the oversized record cannot be skipped safely.
316 ///
317 /// By default no limit is applied.
318 pub fn set_max_record_bytes(mut self, max: usize) -> Self {
319 self.max_record_bytes = Some(max);
320 self
321 }
322
323 /// Rejects any field longer than `max` bytes.
324 ///
325 /// When a field exceeds the limit the row carries a
326 /// [`ReadErrorKind::FieldTooLarge`] error and **reading stops**, because the
327 /// remainder of the oversized record cannot be skipped without reading it.
328 ///
329 /// By default no limit is applied.
330 pub fn set_max_field_bytes(mut self, max: usize) -> Self {
331 self.max_field_bytes = Some(max);
332 self
333 }
334
335 /// Rejects any record with more than `max` columns.
336 ///
337 /// Each column costs at least one byte of input, so this is a cheap way to
338 /// bound the bookkeeping memory used by a record made of millions of empty
339 /// fields. When a record exceeds the limit the row carries a
340 /// [`ReadErrorKind::TooManyColumns`] error and **reading stops**, because
341 /// the remainder of the oversized record cannot be skipped without reading
342 /// it.
343 ///
344 /// By default no limit is applied.
345 pub fn set_max_columns(mut self, max: usize) -> Self {
346 self.max_columns = Some(max);
347 self
348 }
349
350 /// Sets the column names for header-based serde deserialization.
351 ///
352 /// Calling this marks headers as parsed so `reader.headers()` returns `Some`,
353 /// and pins the expected field count to the number of names supplied (unless
354 /// [`set_flexible`](Self::set_flexible) is enabled), exactly like
355 /// [`parse_headers`](Self::parse_headers).
356 pub fn set_headers(mut self, headers: Vec<String>) -> Self {
357 self.headers_parsed = true;
358 if !headers.is_empty() {
359 self.num_fields = Some(headers.len());
360 }
361 self.headers = headers;
362 self.rebuild_header_map();
363 self
364 }
365
366 #[cfg(feature = "serde")]
367 fn rebuild_header_map(&mut self) {
368 let map: BTreeMap<String, usize> = self
369 .headers
370 .iter()
371 .enumerate()
372 .map(|(i, name)| (name.clone(), i))
373 .collect();
374 self.duplicate_headers = map.len() != self.headers.len();
375 self.header_map = Some(Arc::new(map));
376 }
377
378 #[cfg(not(feature = "serde"))]
379 fn rebuild_header_map(&mut self) {}
380
381 /// Returns `Some(&[String])` if headers were parsed or set, `None` otherwise.
382 pub fn headers(&self) -> Option<&[String]> {
383 if self.headers_parsed { Some(&self.headers) } else { None }
384 }
385
386 /// Parses the first row as column headers and stores them internally.
387 ///
388 /// Returns the header strings as a slice, and pins the expected field count
389 /// to the number of headers (unless [`set_flexible`](Self::set_flexible) is
390 /// enabled).
391 ///
392 /// If the input is empty this returns an empty slice and leaves
393 /// [`headers`](Self::headers) as `None`, since no header row was seen.
394 pub fn parse_headers(&mut self) -> Result<&[String], ReadError> {
395 let row = match self.read_row() {
396 Some(row) => row,
397 None => return Ok(&[]),
398 };
399 let headers: Vec<String> = row.to_vec()?.iter().map(|s| s.to_string()).collect();
400 self.headers_parsed = true;
401 self.num_fields = Some(headers.len());
402 self.headers = headers;
403 self.rebuild_header_map();
404 Ok(&self.headers)
405 }
406
407 /// Returns an iterator over `Row` values (validated as UTF-8).
408 pub fn rows(&mut self) -> Rows<'_, R> {
409 Rows {
410 reader: self,
411 }
412 }
413
414 /// Returns an iterator over `BytesRow` values (no UTF-8 validation).
415 pub fn rows_bytes(&mut self) -> BytesRows<'_, R> {
416 BytesRows {
417 reader: self,
418 }
419 }
420
421 /// Reads more data from the source into `buf`, updating `self.end`.
422 ///
423 /// Returns `Ok(true)` if new data was loaded, `Ok(false)` at EOF, or `Err` on
424 /// I/O error or when the source violates the [`Read`] contract by reporting
425 /// progress without appending any bytes.
426 ///
427 /// Once EOF is reached, subsequent calls return `Ok(false)` without re-reading.
428 fn fill_buf(&mut self) -> Result<bool, ReadError> {
429 if self.eof {
430 return Ok(false);
431 }
432 let before = self.buf.len();
433 if self.source.read(&mut self.buf)? {
434 if self.buf.len() == before {
435 // Contract violation: `Ok(true)` without progress. Report it
436 // instead of looping forever or indexing out of bounds.
437 self.eof = true;
438 return Err(ReadError::new(ReadErrorKind::NoProgress, self.record_line, 0));
439 }
440 self.end = self.buf.len();
441 Ok(true)
442 } else {
443 self.eof = true;
444 Ok(false)
445 }
446 }
447
448 /// Skips a UTF-8 byte-order mark at the very start of the input.
449 ///
450 /// The decision needs up to three bytes, so this may read ahead before the
451 /// first record is parsed. That is necessary: with a byte-at-a-time source
452 /// the leading `0xEF` would otherwise be consumed as field content before
453 /// the mark could be recognised.
454 fn strip_leading_bom(&mut self) -> Result<(), ReadError> {
455 if self.bom_checked {
456 return Ok(());
457 }
458 self.bom_checked = true;
459 if !self.strip_bom {
460 return Ok(());
461 }
462 while self.end - self.start < 3 && !self.eof {
463 self.fill_buf()?;
464 }
465 if self.buf[self.start..].starts_with(&crate::BOM) {
466 self.start += 3;
467 }
468 Ok(())
469 }
470
471 /// Parses one CSV row from the input, or returns `None` at EOF.
472 ///
473 /// The row's fields are assembled into an owned `Row`. Errors (I/O,
474 /// unterminated quotes, trailing content, inconsistent field counts,
475 /// configured size limits) are stored on the `Row` and deferred until
476 /// access.
477 fn read_row(&mut self) -> Option<Row> {
478 self.compact();
479 self.ranges.clear();
480 self.scratch.clear();
481 self.state = State::StartOfField;
482 self.pending_lf_quoted = false;
483 self.record_line = self.line;
484
485 if let Err(e) = self.strip_leading_bom() {
486 self.eof = true;
487 return Some(self.build_row(Some(e)));
488 }
489
490 self.record_start = self.discarded + self.start;
491
492 loop {
493 if self.start >= self.end {
494 match self.fill_buf() {
495 Err(e) => {
496 self.eof = true;
497 return match self.state {
498 State::InQuoted => Some(self.build_row(Some(e))),
499 _ => {
500 self.finalize_current_field();
501 Some(self.build_row(Some(e)))
502 }
503 };
504 }
505 Ok(false) => {
506 if self.ranges.is_empty() && self.state == State::StartOfField {
507 return None;
508 }
509 return match self.state {
510 State::InQuoted => Some(self.build_row(Some(ReadError::new(
511 ReadErrorKind::UnterminatedQuote,
512 self.record_line,
513 0,
514 )))),
515 _ => {
516 self.finalize_current_field();
517 Some(self.build_row(None))
518 }
519 };
520 }
521 Ok(true) => {}
522 }
523 }
524
525 // Enforce the opt-in resource limits before touching the byte, so a
526 // malicious record cannot grow the buffers any further.
527 if let Some(kind) = self.limit_exceeded() {
528 return Some(self.abandon_record(kind));
529 }
530
531 if self.pending_cr {
532 if self.buf[self.start] == b'\n' {
533 self.start += 1;
534 }
535 self.pending_cr = false;
536 continue;
537 }
538
539 let byte = self.buf[self.start];
540
541 match self.state {
542 State::StartOfField => {
543 if byte == b'\r' || byte == b'\n' {
544 if !self.ranges.is_empty() {
545 self.ranges.push(RawField {
546 start: self.start,
547 end: self.start,
548 src: Src::Buf,
549 });
550 }
551 self.consume_newline();
552 if self.ranges.is_empty() {
553 continue;
554 }
555 return Some(self.build_row(None));
556 }
557 self.field_start = self.start;
558 if byte == self.delimiter {
559 self.ranges.push(RawField {
560 start: self.start,
561 end: self.start,
562 src: Src::Buf,
563 });
564 self.start += 1;
565 continue;
566 }
567 if byte == b'"' {
568 self.scratch_field_start = self.scratch.len();
569 self.start += 1;
570 self.state = State::InQuoted;
571 } else {
572 self.start += 1;
573 self.state = State::InUnquoted;
574 }
575 }
576
577 State::InUnquoted => {
578 let haystack = &self.buf[self.start..self.end];
579 match memchr::memchr3(self.delimiter, b'\r', b'\n', haystack) {
580 Some(offset) => {
581 let pos = self.start + offset;
582 if let Some(kind) = self.field_limit_exceeded(pos - self.field_start) {
583 return Some(self.abandon_record(kind));
584 }
585 self.ranges.push(RawField {
586 start: self.field_start,
587 end: pos,
588 src: Src::Buf,
589 });
590 let b = self.buf[pos];
591 if b == self.delimiter {
592 self.start = pos + 1;
593 self.state = State::StartOfField;
594 } else {
595 self.start = pos;
596 self.consume_newline();
597 return Some(self.build_row(None));
598 }
599 }
600 None => {
601 self.start = self.end;
602 if let Some(kind) = self.field_limit_exceeded(self.end - self.field_start) {
603 return Some(self.abandon_record(kind));
604 }
605 }
606 }
607 }
608
609 State::InQuoted => {
610 let haystack = &self.buf[self.start..self.end];
611 match memchr::memchr(b'"', haystack) {
612 Some(offset) => {
613 let quote_pos = self.start + offset;
614 let segment = &self.buf[self.start..quote_pos];
615 // Check before copying into `scratch`, so the limit
616 // bounds the scratch buffer too.
617 if let Some(kind) =
618 self.field_limit_exceeded(self.scratch.len() - self.scratch_field_start + segment.len())
619 {
620 return Some(self.abandon_record(kind));
621 }
622 self.line += count_line_breaks(segment, &mut self.pending_lf_quoted);
623 // A `"` follows, so a trailing `\r` cannot pair with
624 // anything and has already been counted.
625 self.pending_lf_quoted = false;
626 self.scratch.extend_from_slice(segment);
627 let after_quote = quote_pos + 1;
628 if after_quote < self.end && self.buf[after_quote] == b'"' {
629 self.scratch.push(b'"');
630 self.start = after_quote + 1;
631 } else if after_quote < self.end {
632 self.ranges.push(RawField {
633 start: self.scratch_field_start,
634 end: self.scratch.len(),
635 src: Src::Scratch,
636 });
637 self.start = after_quote;
638 self.state = State::AfterQuote;
639 } else {
640 match self.fill_buf() {
641 Ok(true) if self.buf.get(after_quote) == Some(&b'"') => {
642 self.scratch.push(b'"');
643 self.start = after_quote + 1;
644 }
645 Err(e) => {
646 self.ranges.push(RawField {
647 start: self.scratch_field_start,
648 end: self.scratch.len(),
649 src: Src::Scratch,
650 });
651 self.start = after_quote;
652 self.state = State::AfterQuote;
653 return Some(self.build_row(Some(e)));
654 }
655 _ => {
656 self.ranges.push(RawField {
657 start: self.scratch_field_start,
658 end: self.scratch.len(),
659 src: Src::Scratch,
660 });
661 self.start = after_quote;
662 self.state = State::AfterQuote;
663 }
664 }
665 }
666 }
667 None => {
668 self.line +=
669 count_line_breaks(&self.buf[self.start..self.end], &mut self.pending_lf_quoted);
670 self.scratch.extend_from_slice(&self.buf[self.start..self.end]);
671 self.start = self.end;
672 if let Some(kind) = self.field_limit_exceeded(self.scratch.len() - self.scratch_field_start)
673 {
674 return Some(self.abandon_record(kind));
675 }
676 }
677 }
678 }
679
680 State::AfterQuote => {
681 if byte == self.delimiter {
682 self.start += 1;
683 self.state = State::StartOfField;
684 } else if is_newline(byte) {
685 self.consume_newline();
686 return Some(self.build_row(None));
687 } else {
688 return Some(self.abandon_record(ReadErrorKind::TrailingContent));
689 }
690 }
691 }
692 }
693 }
694
695 /// Returns the first configured limit the current record has exceeded.
696 ///
697 /// Field sizes are checked where a field is resolved (see
698 /// [`field_limit_exceeded`](Self::field_limit_exceeded)); this covers the
699 /// record and column limits, which grow monotonically as parsing advances.
700 fn limit_exceeded(&self) -> Option<ReadErrorKind> {
701 if let Some(limit) = self.max_record_bytes {
702 let consumed = self.discarded + self.start - self.record_start;
703 if consumed > limit {
704 return Some(ReadErrorKind::RecordTooLarge {
705 limit,
706 });
707 }
708 }
709 if let Some(limit) = self.max_columns
710 && self.ranges.len() > limit
711 {
712 return Some(ReadErrorKind::TooManyColumns {
713 limit,
714 });
715 }
716 None
717 }
718
719 /// Returns [`ReadErrorKind::FieldTooLarge`] if a field of `len` bytes
720 /// exceeds the configured field limit.
721 fn field_limit_exceeded(&self, len: usize) -> Option<ReadErrorKind> {
722 match self.max_field_bytes {
723 Some(limit) if len > limit => Some(ReadErrorKind::FieldTooLarge {
724 limit,
725 }),
726 _ => None,
727 }
728 }
729
730 /// Records the fields parsed so far and abandons the current record,
731 /// positioning the reader at the start of the next record where possible.
732 fn abandon_record(&mut self, kind: ReadErrorKind) -> Row {
733 let error = ReadError::new(kind, self.record_line, 0);
734 match error.kind {
735 // A configured limit was exceeded. Reading further would defeat it
736 // (the remainder of the record could be arbitrarily long), so drop
737 // the rest of the buffer and stop.
738 ReadErrorKind::RecordTooLarge {
739 ..
740 }
741 | ReadErrorKind::FieldTooLarge {
742 ..
743 }
744 | ReadErrorKind::TooManyColumns {
745 ..
746 } => {
747 self.start = self.end;
748 self.eof = true;
749 }
750 _ => {
751 // Keep the fields parsed before the offending byte, then skip
752 // the junk so the next record starts at a record boundary.
753 self.finalize_current_field();
754 if !self.skip_record_tail() {
755 self.eof = true;
756 }
757 }
758 }
759 self.build_row(Some(error))
760 }
761
762 /// Consumes input up to and including the next record terminator.
763 ///
764 /// Returns `false` if the skip could not complete (end of input, I/O error,
765 /// or the configured record-size limit was reached), in which case the
766 /// reader is left at end-of-input.
767 fn skip_record_tail(&mut self) -> bool {
768 loop {
769 if self.start >= self.end {
770 match self.fill_buf() {
771 Ok(true) => {}
772 _ => return false,
773 }
774 }
775 if self.pending_cr {
776 if self.buf[self.start] == b'\n' {
777 self.start += 1;
778 }
779 self.pending_cr = false;
780 return true;
781 }
782 let haystack = &self.buf[self.start..self.end];
783 match memchr::memchr2(b'\r', b'\n', haystack) {
784 Some(offset) => {
785 self.start += offset;
786 self.consume_newline();
787 return true;
788 }
789 None => {
790 self.start = self.end;
791 if let Some(limit) = self.max_record_bytes
792 && self.discarded + self.start - self.record_start > limit
793 {
794 return false;
795 }
796 }
797 }
798 }
799 }
800
801 /// Moves unconsumed data to the front of `buf` and truncates.
802 ///
803 /// Compaction is a full copy of the unconsumed tail, so it is only done
804 /// once a meaningful amount of data has been consumed. Compacting on every
805 /// record would memmove the whole remaining buffer per record, which
806 /// dominates runtime for inputs made of small records.
807 ///
808 /// Only ever called at a record boundary, where no parsed field ranges are
809 /// live.
810 fn compact(&mut self) {
811 if self.start == 0 {
812 return;
813 }
814 if self.start < 4096 && self.start * 2 < self.buf.len() {
815 return;
816 }
817 let shift = self.start;
818 let remaining = self.end - shift;
819 if remaining > 0 {
820 self.buf.copy_within(shift..self.end, 0);
821 }
822 self.buf.truncate(remaining);
823 self.end = remaining;
824 self.start = 0;
825 self.discarded += shift;
826
827 // Give back memory retained from an unusually large record. This only
828 // triggers once the buffer has grown far beyond its initial capacity,
829 // so it never affects steady-state throughput.
830 const RETAINED_CAPACITY: usize = 1 << 20;
831 if self.buf.capacity() > RETAINED_CAPACITY && self.end <= RETAINED_CAPACITY {
832 self.buf.shrink_to_fit();
833 }
834 }
835
836 /// Consumes a `\r\n`, `\n`, or `\r` line ending, incrementing the line counter.
837 ///
838 /// If a bare `\r` is at the end of the buffer, sets `pending_cr` so the
839 /// following `\n` is skipped on the next read.
840 fn consume_newline(&mut self) {
841 if self.start < self.end && self.buf[self.start] == b'\r' {
842 self.start += 1;
843 if self.start >= self.end {
844 self.pending_cr = true;
845 }
846 }
847 if self.start < self.end && self.buf[self.start] == b'\n' {
848 self.start += 1;
849 }
850 self.line += 1;
851 }
852
853 /// Pushes a `RawField` entry for the current unquoted or empty field.
854 ///
855 /// Does nothing in the `AfterQuote` state (the field is already recorded).
856 fn finalize_current_field(&mut self) {
857 match self.state {
858 State::InUnquoted => {
859 self.ranges.push(RawField {
860 start: self.field_start,
861 end: self.start,
862 src: Src::Buf,
863 });
864 }
865 State::InQuoted => {
866 self.ranges.push(RawField {
867 start: self.scratch_field_start,
868 end: self.scratch.len(),
869 src: Src::Scratch,
870 });
871 }
872 State::AfterQuote => {}
873 State::StartOfField => {
874 if !self.ranges.is_empty() {
875 self.ranges.push(RawField {
876 start: self.start,
877 end: self.start,
878 src: Src::Buf,
879 });
880 }
881 }
882 }
883 }
884
885 /// Wraps the bytes row into a `Row`, attaching the header map if available.
886 fn build_row(&mut self, error: Option<ReadError>) -> Row {
887 let bytes_row = self.build_bytes_row(error);
888 Row {
889 inner: bytes_row,
890 #[cfg(feature = "serde")]
891 header_map: self.header_map.clone(),
892 #[cfg(feature = "serde")]
893 duplicate_headers: self.duplicate_headers,
894 }
895 }
896
897 /// Assembles the parsed fields into an owned `BytesRow`, checking field-count consistency.
898 fn build_bytes_row(&mut self, error: Option<ReadError>) -> BytesRow {
899 let mut total: usize = 0;
900 for r in &self.ranges {
901 total += r.end - r.start;
902 }
903
904 let mut row_buf = Vec::with_capacity(total);
905 let mut row_ranges = Vec::with_capacity(self.ranges.len());
906
907 for r in &self.ranges {
908 let slice = match r.src {
909 Src::Buf => &self.buf[r.start..r.end],
910 Src::Scratch => &self.scratch[r.start..r.end],
911 };
912 let start = row_buf.len();
913 row_buf.extend_from_slice(slice);
914 let end = row_buf.len();
915 row_ranges.push(FieldRange {
916 start,
917 end,
918 });
919 }
920
921 let field_count = row_ranges.len();
922
923 let error = if !self.flexible {
924 error.or_else(|| match self.num_fields {
925 Some(expected) if field_count != expected => Some(ReadError::new(
926 ReadErrorKind::InconsistentFieldCount {
927 expected,
928 found: field_count,
929 },
930 self.record_line,
931 0,
932 )),
933 _ => None,
934 })
935 } else {
936 error
937 };
938
939 // Only a well-formed record may establish the expected field count.
940 // Otherwise one malformed record would cascade errors over the rest of
941 // the input.
942 if self.num_fields.is_none() && field_count > 0 && error.is_none() {
943 self.num_fields = Some(field_count);
944 }
945
946 BytesRow {
947 buf: row_buf,
948 ranges: row_ranges,
949 error,
950 line: self.record_line,
951 }
952 }
953}
954
955/// Counts line breaks in a slice of quoted-field content.
956///
957/// A `\r` immediately followed by `\n` counts as a single break, even when the
958/// pair is split across two slices: `pending_cr` is set when a slice ends on a
959/// bare `\r` and consulted by the following call.
960///
961/// Quoted content usually contains no line breaks at all, so a `memchr2`
962/// pre-scan (which is vectorised) keeps this off the hot path.
963fn count_line_breaks(bytes: &[u8], pending_cr: &mut bool) -> usize {
964 if memchr::memchr2(b'\r', b'\n', bytes).is_none() {
965 // No break in this slice, so a pending `\r` cannot pair with a leading
966 // `\n` here; any consumed byte clears it.
967 if !bytes.is_empty() {
968 *pending_cr = false;
969 }
970 return 0;
971 }
972
973 let mut breaks = 0;
974 let mut i = 0;
975 if *pending_cr {
976 if bytes.first() == Some(&b'\n') {
977 i = 1;
978 }
979 *pending_cr = false;
980 }
981 while i < bytes.len() {
982 match bytes[i] {
983 b'\n' => {
984 breaks += 1;
985 i += 1;
986 }
987 b'\r' => {
988 breaks += 1;
989 i += 1;
990 if i < bytes.len() {
991 if bytes[i] == b'\n' {
992 i += 1;
993 }
994 } else {
995 *pending_cr = true;
996 }
997 }
998 _ => i += 1,
999 }
1000 }
1001 breaks
1002}
1003
1004fn is_newline(b: u8) -> bool {
1005 b == b'\n' || b == b'\r'
1006}
1007
1008// ── BytesRow ──────────────────────────────────────────────────────────
1009
1010pub struct BytesRow {
1011 pub(crate) buf: Vec<u8>,
1012 pub(crate) ranges: Vec<FieldRange>,
1013 pub(crate) error: Option<ReadError>,
1014 pub(crate) line: usize,
1015}
1016
1017impl BytesRow {
1018 /// The parse error for this row, if any.
1019 ///
1020 /// Unlike [`Row`], a `BytesRow` never fails: the error is stored here and
1021 /// the raw field bytes remain accessible through [`get`](Self::get) and
1022 /// [`iter`](Self::iter). [`to_vec`](Self::to_vec) is the accessor that
1023 /// surfaces the error.
1024 pub fn error(&self) -> Option<&ReadError> {
1025 self.error.as_ref()
1026 }
1027
1028 pub fn len(&self) -> usize {
1029 self.ranges.len()
1030 }
1031
1032 pub fn is_empty(&self) -> bool {
1033 self.ranges.is_empty()
1034 }
1035
1036 pub fn get(&self, index: usize) -> Option<&[u8]> {
1037 self.ranges.get(index).map(|r| &self.buf[r.start..r.end])
1038 }
1039
1040 pub fn to_vec(&self) -> Result<Vec<&[u8]>, ReadError> {
1041 if let Some(ref e) = self.error {
1042 return Err(e.clone());
1043 }
1044 Ok(self.ranges.iter().map(|r| &self.buf[r.start..r.end]).collect())
1045 }
1046
1047 pub fn iter(&self) -> BytesFields<'_> {
1048 BytesFields {
1049 buf: &self.buf,
1050 iter: self.ranges.iter(),
1051 }
1052 }
1053}
1054
1055impl fmt::Debug for BytesRow {
1056 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1057 match &self.error {
1058 Some(e) => write!(f, "BytesRow(Err({e}))"),
1059 None => f
1060 .debug_list()
1061 .entries(self.ranges.iter().map(|r| &self.buf[r.start..r.end]))
1062 .finish(),
1063 }
1064 }
1065}
1066
1067pub struct BytesFields<'a> {
1068 buf: &'a [u8],
1069 iter: core::slice::Iter<'a, FieldRange>,
1070}
1071
1072impl<'a> Iterator for BytesFields<'a> {
1073 type Item = &'a [u8];
1074 fn next(&mut self) -> Option<&'a [u8]> {
1075 let r = self.iter.next()?;
1076 Some(&self.buf[r.start..r.end])
1077 }
1078 fn size_hint(&self) -> (usize, Option<usize>) {
1079 self.iter.size_hint()
1080 }
1081}
1082
1083impl<'a> ExactSizeIterator for BytesFields<'a> {}
1084
1085// ── Row ───────────────────────────────────────────────────────────────
1086
1087pub struct Row {
1088 pub(crate) inner: BytesRow,
1089 #[cfg(feature = "serde")]
1090 pub(crate) header_map: Option<Arc<BTreeMap<String, usize>>>,
1091 #[cfg(feature = "serde")]
1092 pub(crate) duplicate_headers: bool,
1093}
1094
1095impl Row {
1096 /// The parse error for this row, if any.
1097 pub fn error(&self) -> Option<&ReadError> {
1098 self.inner.error()
1099 }
1100
1101 /// Number of fields parsed for this row.
1102 ///
1103 /// Fields are still counted when the row carries an error.
1104 pub fn len(&self) -> usize {
1105 self.inner.len()
1106 }
1107
1108 pub fn is_empty(&self) -> bool {
1109 self.inner.is_empty()
1110 }
1111
1112 /// Returns the field at `index`, or `None` if there is no such field.
1113 ///
1114 /// Consistent with [`to_vec`](Self::to_vec) and [`iter`](Self::iter): if
1115 /// the row carries a parse error, every in-range index yields `Err`. Only
1116 /// an out-of-range index yields `None`.
1117 pub fn get(&self, index: usize) -> Option<Result<&str, ReadError>> {
1118 self.inner.get(index).map(|bytes| {
1119 if let Some(ref e) = self.inner.error {
1120 return Err(e.clone());
1121 }
1122 core::str::from_utf8(bytes).map_err(|_| ReadError::new(ReadErrorKind::InvalidUtf8, self.inner.line, 0))
1123 })
1124 }
1125
1126 /// Returns all fields as `&str`, or the row's parse error.
1127 pub fn to_vec(&self) -> Result<Vec<&str>, ReadError> {
1128 if let Some(ref e) = self.inner.error {
1129 return Err(e.clone());
1130 }
1131 self.inner
1132 .ranges
1133 .iter()
1134 .map(|r| {
1135 core::str::from_utf8(&self.inner.buf[r.start..r.end])
1136 .map_err(|_| ReadError::new(ReadErrorKind::InvalidUtf8, self.inner.line, 0))
1137 })
1138 .collect()
1139 }
1140
1141 /// Iterates over the fields, yielding the row's parse error for each field
1142 /// when the row is malformed.
1143 pub fn iter(&self) -> Fields<'_> {
1144 Fields {
1145 buf: &self.inner.buf,
1146 iter: self.inner.ranges.iter(),
1147 error: self.inner.error.as_ref().map(|e| &e.kind),
1148 line: self.inner.line,
1149 }
1150 }
1151}
1152
1153impl fmt::Debug for Row {
1154 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1155 match &self.inner.error {
1156 Some(e) => write!(f, "Row(Err({e}))"),
1157 None => {
1158 f.debug_list()
1159 .entries(
1160 self.inner.ranges.iter().map(|r| {
1161 core::str::from_utf8(&self.inner.buf[r.start..r.end]).unwrap_or("<invalid utf-8>")
1162 }),
1163 )
1164 .finish()
1165 }
1166 }
1167 }
1168}
1169
1170pub struct Fields<'a> {
1171 buf: &'a [u8],
1172 iter: core::slice::Iter<'a, FieldRange>,
1173 error: Option<&'a ReadErrorKind>,
1174 line: usize,
1175}
1176
1177impl<'a> Iterator for Fields<'a> {
1178 type Item = Result<&'a str, ReadError>;
1179 fn next(&mut self) -> Option<Self::Item> {
1180 let r = self.iter.next()?;
1181 if let Some(kind) = self.error {
1182 return Some(Err(ReadError::new(kind.clone(), self.line, 0)));
1183 }
1184 Some(
1185 core::str::from_utf8(&self.buf[r.start..r.end])
1186 .map_err(|_| ReadError::new(ReadErrorKind::InvalidUtf8, self.line, 0)),
1187 )
1188 }
1189 fn size_hint(&self) -> (usize, Option<usize>) {
1190 self.iter.size_hint()
1191 }
1192}
1193
1194impl<'a> ExactSizeIterator for Fields<'a> {}
1195
1196// ── Iterators ─────────────────────────────────────────────────────────
1197
1198pub struct BytesRows<'r, R: Read> {
1199 reader: &'r mut Reader<R>,
1200}
1201
1202impl<'r, R: Read> Iterator for BytesRows<'r, R> {
1203 type Item = BytesRow;
1204 fn next(&mut self) -> Option<Self::Item> {
1205 self.reader.read_row().map(|r| r.inner)
1206 }
1207}
1208
1209pub struct Rows<'r, R: Read> {
1210 reader: &'r mut Reader<R>,
1211}
1212
1213impl<'r, R: Read> Iterator for Rows<'r, R> {
1214 type Item = Row;
1215 fn next(&mut self) -> Option<Self::Item> {
1216 self.reader.read_row()
1217 }
1218}