use std::error::Error as StdError;
use std::fmt;
use std::io;
use std::result;
use crate::byte_record::{ByteRecord, Position};
#[cfg(feature = "with_serde")]
use crate::deserializer::DeserializeError;
pub type Result<T> = result::Result<T, Error>;
#[derive(Debug)]
pub struct Error(Box<ErrorKind>);
impl Error {
pub(crate) fn new(kind: ErrorKind) -> Error {
Error(Box::new(kind))
}
pub fn kind(&self) -> &ErrorKind {
&self.0
}
pub fn into_kind(self) -> ErrorKind {
*self.0
}
pub fn is_io_error(&self) -> bool {
matches!(*self.0, ErrorKind::Io(_))
}
pub fn position(&self) -> Option<&Position> {
self.0.position()
}
}
#[derive(Debug)]
#[non_exhaustive]
pub enum ErrorKind {
Io(io::Error),
Utf8 {
pos: Option<Position>,
err: Utf8Error,
},
UnequalLengths {
pos: Option<Position>,
expected_len: u64,
len: u64,
},
Seek,
#[cfg(feature = "with_serde")]
Serialize(String),
#[cfg(feature = "with_serde")]
Deserialize {
pos: Option<Position>,
err: DeserializeError,
}
}
impl ErrorKind {
pub fn position(&self) -> Option<&Position> {
match *self {
ErrorKind::Utf8 { ref pos, .. } => pos.as_ref(),
ErrorKind::UnequalLengths { ref pos, .. } => pos.as_ref(),
#[cfg(feature = "with_serde")]
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 {
#[allow(unreachable_patterns)]
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}", err.field() + 1)
}
ErrorKind::Utf8 { pos: Some(ref pos), ref err } => write!(
f,
"CSV parse error: record {} \
(line {}, field: {}, byte: {}): {err}",
pos.record(),
pos.line(),
err.field() + 1,
pos.byte(),
),
ErrorKind::UnequalLengths { pos: None, expected_len, len } => {
write!(
f,
"CSV error: \
found record with {len} fields, but the previous record \
has {expected_len} fields"
)
}
ErrorKind::UnequalLengths {
pos: Some(ref pos),
expected_len,
len,
} => write!(
f,
"CSV error: record {} (line: {}, byte: {}): \
found record with {len} fields, but the previous record \
has {expected_len} fields",
pos.record(),
pos.line(),
pos.byte(),
),
ErrorKind::Seek => write!(
f,
"CSV error: cannot access headers of CSV data \
when the parser was seeked before the first record \
could be read"
),
#[cfg(feature = "with_serde")]
ErrorKind::Serialize(ref msg) => {
write!(f, "CSV serialize error: {msg}")
}
#[cfg(feature = "with_serde")]
ErrorKind::Deserialize { pos: None, ref err } => {
write!(f, "CSV deserialize error: {err}")
}
#[cfg(feature = "with_serde")]
ErrorKind::Deserialize {
pos: Some(ref pos),
ref err,
} => write!(
f,
"CSV deserialize error: record {} \
(line {}, byte: {}): {err}",
pos.record(),
pos.line(),
pos.byte(),
),
_ => write!(f,"CSV other error")
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FromUtf8Error {
record: ByteRecord,
err: Utf8Error,
}
impl FromUtf8Error {
pub(crate) fn new(record: ByteRecord, err: Utf8Error) -> FromUtf8Error {
FromUtf8Error { record, err }
}
pub fn into_byte_record(self) -> ByteRecord {
self.record
}
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)
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Utf8Error {
field: usize,
valid_up_to: usize,
}
pub fn new_utf8_error(field: usize, valid_up_to: usize) -> Utf8Error {
Utf8Error { field, valid_up_to }
}
impl Utf8Error {
pub fn field(&self) -> usize {
self.field
}
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 + 1, self.valid_up_to
)
}
}
pub struct IntoInnerError<W> {
wtr: W,
err: io::Error,
}
impl<W> IntoInnerError<W> {
#[allow(dead_code)]
pub(crate) fn new(wtr: W, err: io::Error) -> IntoInnerError<W> {
IntoInnerError { wtr, err }
}
pub fn error(&self) -> &io::Error {
&self.err
}
pub fn into_error(self) -> io::Error {
self.err
}
pub fn into_writer(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)
}
}