-
Notifications
You must be signed in to change notification settings - Fork 217
/
error.rs
336 lines (304 loc) · 10.2 KB
/
error.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
use std::{error::Error as StdError, fmt, io, result};
use crate::{
byte_record::{ByteRecord, Position},
deserializer::DeserializeError,
};
/// A type alias for `Result<T, csv::Error>`.
pub type Result<T> = result::Result<T, Error>;
/// An error that can occur when processing CSV data.
///
/// This error can happen when writing or reading CSV data.
///
/// There are some important scenarios where an error is impossible to occur.
/// For example, if a CSV reader is used on an in-memory buffer with the
/// `flexible` option enabled and one is reading records as raw byte strings,
/// then no error can occur.
#[derive(Debug)]
pub struct Error(Box<ErrorKind>);
impl Error {
/// A crate private constructor for `Error`.
pub(crate) fn new(kind: ErrorKind) -> Error {
Error(Box::new(kind))
}
/// Return the specific type of this error.
pub fn kind(&self) -> &ErrorKind {
&self.0
}
/// Unwrap this error into its underlying type.
pub fn into_kind(self) -> ErrorKind {
*self.0
}
/// Returns true if this is an I/O error.
///
/// If this is true, the underlying `ErrorKind` is guaranteed to be
/// `ErrorKind::Io`.
pub fn is_io_error(&self) -> bool {
match *self.0 {
ErrorKind::Io(_) => true,
_ => false,
}
}
/// Return the position for this error, if one exists.
///
/// This is a convenience function that permits callers to easily access
/// the position on an error without doing case analysis on `ErrorKind`.
pub fn position(&self) -> Option<&Position> {
self.0.position()
}
}
/// The specific type of an error.
#[derive(Debug)]
pub enum ErrorKind {
/// An I/O error that occurred while reading CSV data.
Io(io::Error),
/// A UTF-8 decoding error that occured while reading CSV data into Rust
/// `String`s.
Utf8 {
/// The position of the record in which this error occurred, if
/// available.
pos: Option<Position>,
/// The corresponding UTF-8 error.
err: Utf8Error,
},
/// This error occurs when two records with an unequal number of fields
/// are found. This error only occurs when the `flexible` option in a
/// CSV reader/writer is disabled.
UnequalLengths {
/// The position of the first record with an unequal number of fields
/// to the previous record, if available.
pos: Option<Position>,
/// The expected number of fields in a record. This is the number of
/// fields in the record read prior to the record indicated by
/// `pos`.
expected_len: u64,
/// The number of fields in the bad record.
len: u64,
},
/// This error occurs when either the `byte_headers` or `headers` methods
/// are called on a CSV reader that was asked to `seek` before it parsed
/// the first record.
Seek,
/// An error of this kind occurs only when using the Serde serializer.
Serialize(String),
/// An error of this kind occurs only when performing automatic
/// deserialization with serde.
Deserialize {
/// The position of this error, if available.
pos: Option<Position>,
/// The deserialization error.
err: DeserializeError,
},
/// Hints that destructuring should not be exhaustive.
///
/// This enum may grow additional variants, so this makes sure clients
/// don't count on exhaustive matching. (Otherwise, adding a new variant
/// could break existing code.)
#[doc(hidden)]
__Nonexhaustive,
}
impl ErrorKind {
/// Return the position for this error, if one exists.
///
/// This is a convenience function that permits callers to easily access
/// the position on an error without doing case analysis on `ErrorKind`.
pub fn position(&self) -> Option<&Position> {
match *self {
ErrorKind::Utf8 { ref pos, .. } => pos.as_ref(),
ErrorKind::UnequalLengths { ref pos, .. } => pos.as_ref(),
ErrorKind::Deserialize { ref pos, .. } => pos.as_ref(),
_ => None,
}
}
}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Error {
Error::new(ErrorKind::Io(err))
}
}
impl From<Error> for io::Error {
fn from(err: Error) -> io::Error {
io::Error::new(io::ErrorKind::Other, err)
}
}
impl StdError for Error {}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self.0 {
ErrorKind::Io(ref err) => err.fmt(f),
ErrorKind::Utf8 { pos: None, ref err } => {
write!(f, "CSV parse error: field {}: {}", err.field(), err)
}
ErrorKind::Utf8 { pos: Some(ref pos), ref err } => write!(
f,
"CSV parse error: record {} \
(line {}, field: {}, byte: {}): {}",
pos.record(),
pos.line(),
err.field(),
pos.byte(),
err
),
ErrorKind::UnequalLengths { pos: None, expected_len, len } => {
write!(
f,
"CSV error: \
found record with {} fields, but the previous record \
has {} fields",
len, expected_len
)
}
ErrorKind::UnequalLengths {
pos: Some(ref pos),
expected_len,
len,
} => write!(
f,
"CSV error: record {} (line: {}, byte: {}): \
found record with {} fields, but the previous record \
has {} fields",
pos.record(),
pos.line(),
pos.byte(),
len,
expected_len
),
ErrorKind::Seek => write!(
f,
"CSV error: cannot access headers of CSV data \
when the parser was seeked before the first record \
could be read"
),
ErrorKind::Serialize(ref err) => {
write!(f, "CSV write error: {}", err)
}
ErrorKind::Deserialize { pos: None, ref err } => {
write!(f, "CSV deserialize error: {}", err)
}
ErrorKind::Deserialize { pos: Some(ref pos), ref err } => write!(
f,
"CSV deserialize error: record {} \
(line: {}, byte: {}): {}",
pos.record(),
pos.line(),
pos.byte(),
err
),
_ => unreachable!(),
}
}
}
/// A UTF-8 validation error during record conversion.
///
/// This occurs when attempting to convert a `ByteRecord` into a
/// `StringRecord`.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FromUtf8Error {
record: ByteRecord,
err: Utf8Error,
}
impl FromUtf8Error {
/// Create a new FromUtf8Error.
pub(crate) fn new(record: ByteRecord, err: Utf8Error) -> FromUtf8Error {
FromUtf8Error { record, err }
}
/// Access the underlying `ByteRecord` that failed UTF-8 validation.
pub fn into_byte_record(self) -> ByteRecord {
self.record
}
/// Access the underlying UTF-8 validation error.
pub fn utf8_error(&self) -> &Utf8Error {
&self.err
}
}
impl fmt::Display for FromUtf8Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.err.fmt(f)
}
}
impl StdError for FromUtf8Error {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
Some(&self.err)
}
}
/// A UTF-8 validation error.
///
/// This occurs when attempting to convert a `ByteRecord` into a
/// `StringRecord`.
///
/// The error includes the index of the field that failed validation, and the
/// last byte at which valid UTF-8 was verified.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Utf8Error {
/// The field index of a byte record in which UTF-8 validation failed.
field: usize,
/// The index into the given field up to which valid UTF-8 was verified.
valid_up_to: usize,
}
/// Create a new UTF-8 error.
pub fn new_utf8_error(field: usize, valid_up_to: usize) -> Utf8Error {
Utf8Error { field, valid_up_to }
}
impl Utf8Error {
/// The field index of a byte record in which UTF-8 validation failed.
pub fn field(&self) -> usize {
self.field
}
/// The index into the given field up to which valid UTF-8 was verified.
pub fn valid_up_to(&self) -> usize {
self.valid_up_to
}
}
impl StdError for Utf8Error {}
impl fmt::Display for Utf8Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"invalid utf-8: invalid UTF-8 in field {} near byte index {}",
self.field, self.valid_up_to
)
}
}
/// `IntoInnerError` occurs when consuming a `Writer` fails.
///
/// Consuming the `Writer` causes a flush to happen. If the flush fails, then
/// this error is returned, which contains both the original `Writer` and
/// the error that occurred.
///
/// The type parameter `W` is the unconsumed writer.
pub struct IntoInnerError<W> {
wtr: W,
err: io::Error,
}
impl<W> IntoInnerError<W> {
/// Creates a new `IntoInnerError`.
///
/// (This is a visibility hack. It's public in this module, but not in the
/// crate.)
pub(crate) fn new(wtr: W, err: io::Error) -> IntoInnerError<W> {
IntoInnerError { wtr, err }
}
/// Returns the error which caused the call to `into_inner` to fail.
///
/// This error was returned when attempting to flush the internal buffer.
pub fn error(&self) -> &io::Error {
&self.err
}
/// Returns the underlying writer which generated the error.
///
/// The returned value can be used for error recovery, such as
/// re-inspecting the buffer.
pub fn into_inner(self) -> W {
self.wtr
}
}
impl<W: std::any::Any> StdError for IntoInnerError<W> {}
impl<W> fmt::Display for IntoInnerError<W> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.err.fmt(f)
}
}
impl<W> fmt::Debug for IntoInnerError<W> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.err.fmt(f)
}
}