Skip to main content

csv_legacy/
error.rs

1use core::fmt;
2
3/// Kinds of errors that can occur when reading CSV data.
4#[derive(Debug)]
5pub enum ReadErrorKind {
6    /// A quoted field was opened but never closed before end of input.
7    UnterminatedQuote,
8    /// Non-delimiter, non-newline content appeared after a closing quote.
9    TrailingContent,
10    /// An I/O error from the underlying read source.
11    #[cfg(feature = "std")]
12    Io(std::io::Error),
13    /// The CSV data contains invalid UTF-8.
14    InvalidUtf8,
15}
16
17impl fmt::Display for ReadErrorKind {
18    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19        match self {
20            ReadErrorKind::UnterminatedQuote => f.write_str("unterminated quote"),
21            ReadErrorKind::TrailingContent => f.write_str("trailing content after closing quote"),
22            ReadErrorKind::InvalidUtf8 => f.write_str("invalid UTF-8 in CSV data"),
23            #[cfg(feature = "std")]
24            ReadErrorKind::Io(e) => write!(f, "I/O error: {e}"),
25        }
26    }
27}
28
29/// Errors that can occur when reading CSV data.
30pub struct ReadError {
31    kind: ReadErrorKind,
32    /// 1-indexed line number
33    pub line: usize,
34    /// 1-indexed byte offset within the line
35    pub column: usize,
36}
37
38impl ReadError {
39    pub(crate) fn new(kind: ReadErrorKind, line: usize, column: usize) -> Self {
40        ReadError {
41            kind,
42            line,
43            column,
44        }
45    }
46
47    /// Returns a reference to the [`ReadErrorKind`] of this error.
48    pub fn kind(&self) -> &ReadErrorKind {
49        &self.kind
50    }
51}
52
53impl fmt::Display for ReadError {
54    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55        match &self.kind {
56            ReadErrorKind::UnterminatedQuote => {
57                write!(f, "unterminated quote at line {}, column {}", self.line, self.column)
58            }
59            ReadErrorKind::TrailingContent => {
60                write!(
61                    f,
62                    "trailing content after closing quote at line {}, column {}",
63                    self.line, self.column
64                )
65            }
66            ReadErrorKind::InvalidUtf8 => {
67                write!(f, "invalid UTF-8 at line {}", self.line)
68            }
69            #[cfg(feature = "std")]
70            ReadErrorKind::Io(e) => write!(f, "I/O error at line {}, column {}: {}", self.line, self.column, e),
71        }
72    }
73}
74
75impl fmt::Debug for ReadError {
76    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77        write!(f, "ReadError({})", self)
78    }
79}
80
81#[cfg(feature = "std")]
82impl std::error::Error for ReadError {
83    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
84        match &self.kind {
85            ReadErrorKind::Io(e) => Some(e),
86            _ => None,
87        }
88    }
89}
90
91#[cfg(feature = "std")]
92impl From<std::io::Error> for ReadError {
93    fn from(e: std::io::Error) -> Self {
94        ReadError::new(ReadErrorKind::Io(e), 0, 0)
95    }
96}
97
98/// Errors that can occur when writing CSV data.
99#[derive(Debug)]
100pub enum WriteError {
101    /// The records have inconsistent field counts.
102    InconsistentFieldCount {
103        /// Number of fields expected.
104        expected: usize,
105        /// Number of fields found in the offending record.
106        found: usize,
107        /// The 1-indexed record number where the mismatch occurred.
108        row: usize,
109    },
110    /// An I/O error from the underlying writer.
111    #[cfg(feature = "std")]
112    Io(std::io::Error),
113}
114
115impl fmt::Display for WriteError {
116    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117        match self {
118            WriteError::InconsistentFieldCount {
119                expected,
120                found,
121                row,
122            } => {
123                write!(f, "expected {expected} fields, found {found} fields at row {row}")
124            }
125            #[cfg(feature = "std")]
126            WriteError::Io(e) => write!(f, "I/O error: {e}"),
127        }
128    }
129}
130
131#[cfg(feature = "std")]
132impl std::error::Error for WriteError {
133    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
134        match self {
135            WriteError::Io(e) => Some(e),
136            _ => None,
137        }
138    }
139}
140
141#[cfg(feature = "std")]
142impl From<std::io::Error> for WriteError {
143    fn from(e: std::io::Error) -> Self {
144        WriteError::Io(e)
145    }
146}