use std::error::Error as StdError;
use std::fmt;
use std::io;
use std::result;
use crate::byte_record::{ByteRecord, Position};
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 {
match *self.0 {
ErrorKind::Io(_) => true,
_ => false,
}
}
pub fn position(&self) -> Option<&Position> {
self.0.position()
}
}
#[derive(Debug)]
pub enum ErrorKind {
Io(io::Error),
Utf8 {
pos: Option<Position>,
err: Utf8Error,
},
UnequalLengths {
pos: Option<Position>,
expected_len: u64,
len: u64,
},
Seek,
Serialize(String),
Deserialize {
pos: Option<Position>,
err: DeserializeError,
},
#[doc(hidden)]
__Nonexhaustive,
}
impl 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 {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match *self.0 {
ErrorKind::Io(ref err) => Some(err),
ErrorKind::Utf8 { ref err, .. } => Some(err),
ErrorKind::UnequalLengths { .. } => None,
ErrorKind::Seek => None,
ErrorKind::Serialize(_) => None,
ErrorKind::Deserialize { ref err, .. } => Some(err),
_ => unreachable!(),
}
}
}
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!(),
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FromUtf8Error {
record: ByteRecord,
err: Utf8Error,
}
impl FromUtf8Error {
pub(crate) fn new(rec: ByteRecord, err: Utf8Error) -> FromUtf8Error {
FromUtf8Error { record: rec, err: 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: field, valid_up_to: 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, self.valid_up_to
)
}
}
pub struct IntoInnerError<W> {
wtr: W,
err: io::Error,
}
impl<W> IntoInnerError<W> {
pub(crate) fn new(wtr: W, err: io::Error) -> IntoInnerError<W> {
IntoInnerError { wtr: wtr, err: err }
}
pub fn error(&self) -> &io::Error {
&self.err
}
pub fn into_inner(self) -> W {
self.wtr
}
}
impl<W: std::any::Any> StdError for IntoInnerError<W> {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
self.err.source()
}
}
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)
}
}