Skip to main content

csv_legacy2/
error.rs

1use core::fmt;
2
3extern crate alloc;
4#[cfg(feature = "std")]
5use alloc::boxed::Box;
6
7/// Kinds of errors that can occur while reading CSV data.
8#[derive(Clone, Debug, PartialEq)]
9pub enum ReadErrorKind {
10    /// A quoted field was opened but never closed before end of input.
11    UnterminatedQuote,
12    /// Characters appeared after a closing quote before a delimiter or newline.
13    TrailingContent,
14    /// A field contained invalid UTF-8 bytes.
15    InvalidUtf8,
16    /// A serde deserialization error occurred. Carries the error message.
17    #[cfg(feature = "serde")]
18    Deserialize(String),
19    /// An I/O error occurred while reading the underlying source.
20    Io,
21}
22
23/// An error returned when parsing a CSV row.
24///
25/// Includes the line number, the kind of error, and when applicable an
26/// inner source error (e.g. the original `std::io::Error`).
27#[derive(Debug)]
28pub struct ReadError {
29    pub kind: ReadErrorKind,
30    pub line: usize,
31    pub column: usize,
32    #[cfg(feature = "std")]
33    source: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
34}
35
36impl ReadError {
37    pub fn new(kind: ReadErrorKind, line: usize, column: usize) -> Self {
38        ReadError {
39            kind,
40            line,
41            column,
42            #[cfg(feature = "std")]
43            source: None,
44        }
45    }
46
47    pub fn kind(&self) -> &ReadErrorKind {
48        &self.kind
49    }
50
51    /// The inner source error, if any (e.g. the original `std::io::Error` or serde error).
52    #[cfg(feature = "std")]
53    pub fn into_source(self) -> Option<Box<dyn std::error::Error + Send + Sync + 'static>> {
54        self.source
55    }
56}
57
58impl Clone for ReadError {
59    fn clone(&self) -> Self {
60        ReadError {
61            kind: self.kind.clone(),
62            line: self.line,
63            column: self.column,
64            #[cfg(feature = "std")]
65            source: None,
66        }
67    }
68}
69
70impl fmt::Display for ReadError {
71    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72        match &self.kind {
73            ReadErrorKind::UnterminatedQuote => {
74                write!(f, "unterminated quote at line {}, column {}", self.line, self.column)
75            }
76            ReadErrorKind::TrailingContent => {
77                write!(
78                    f,
79                    "trailing content after quoted field at line {}, column {}",
80                    self.line, self.column
81                )
82            }
83            ReadErrorKind::InvalidUtf8 => {
84                write!(f, "invalid UTF-8 at line {}, column {}", self.line, self.column)
85            }
86            #[cfg(feature = "serde")]
87            ReadErrorKind::Deserialize(msg) => {
88                write!(f, "deserialization error at line {}, column {}: {msg}", self.line, self.column)
89            }
90            ReadErrorKind::Io => {
91                write!(f, "I/O error at line {}, column {}", self.line, self.column)
92            }
93        }
94    }
95}
96
97#[cfg(feature = "std")]
98impl std::error::Error for ReadError {
99    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
100        self.source
101            .as_ref()
102            .map(|b| b.as_ref() as &(dyn std::error::Error + 'static))
103    }
104}
105
106#[cfg(all(not(feature = "std"), feature = "serde"))]
107impl core::error::Error for ReadError {}
108
109#[cfg(feature = "std")]
110impl From<std::io::Error> for ReadError {
111    fn from(e: std::io::Error) -> Self {
112        ReadError {
113            kind: ReadErrorKind::Io,
114            line: 0,
115            column: 0,
116            source: Some(Box::new(e)),
117        }
118    }
119}
120
121/// An error returned when writing CSV data.
122#[derive(Debug)]
123pub enum WriteError {
124    /// The number of fields in a row differs from previous rows.
125    InconsistentFieldCount { expected: usize, found: usize, row: usize },
126    /// An I/O error occurred while writing.
127    #[cfg(feature = "std")]
128    Io(std::io::Error),
129}
130
131impl fmt::Display for WriteError {
132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133        match self {
134            WriteError::InconsistentFieldCount {
135                expected,
136                found,
137                row,
138            } => {
139                write!(f, "expected {expected} fields, found {found} in row {row}")
140            }
141            #[cfg(feature = "std")]
142            WriteError::Io(e) => write!(f, "I/O error: {e}"),
143        }
144    }
145}
146
147#[cfg(feature = "std")]
148impl std::error::Error for WriteError {
149    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
150        match self {
151            WriteError::Io(e) => Some(e),
152            _ => None,
153        }
154    }
155}
156
157#[cfg(feature = "std")]
158impl From<std::io::Error> for WriteError {
159    fn from(e: std::io::Error) -> Self {
160        WriteError::Io(e)
161    }
162}