use std::error::Error as StdError;
use std::fmt;
use std::io;
use std::result;
use std::str;
use byte_record::{ByteRecord, Position};
use deserializer::DeserializeError;
pub fn new_error(kind: ErrorKind) -> Error {
Error(Box::new(kind))
}
pub type Result<T> = result::Result<T, Error>;
#[derive(Debug)]
pub struct Error(Box<ErrorKind>);
impl Error {
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,
}
}
}
#[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 From<io::Error> for Error {
fn from(err: io::Error) -> Error {
new_error(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 description(&self) -> &str {
match *self.0 {
ErrorKind::Io(ref err) => err.description(),
ErrorKind::Utf8 { ref err, .. } => err.description(),
ErrorKind::UnequalLengths{..} => {
"record of different length found"
}
ErrorKind::Seek => "headers unavailable on seeked CSV reader",
ErrorKind::Serialize(ref err) => err,
ErrorKind::Deserialize { ref err, .. } => err.description(),
_ => unreachable!(),
}
}
fn cause(&self) -> Option<&StdError> {
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,
}
pub fn new_from_utf8_error(rec: ByteRecord, err: Utf8Error) -> FromUtf8Error {
FromUtf8Error { record: rec, err: err }
}
impl FromUtf8Error {
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 description(&self) -> &str { self.err.description() }
fn cause(&self) -> Option<&StdError> { 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 {
fn description(&self) -> &str { "invalid utf-8 in CSV record" }
}
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,
}
pub fn new_into_inner_error<W>(wtr: W, err: io::Error) -> IntoInnerError<W> {
IntoInnerError { wtr: wtr, err: err }
}
impl<W> IntoInnerError<W> {
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 description(&self) -> &str {
self.err.description()
}
#[allow(deprecated)]
fn cause(&self) -> Option<&StdError> {
self.err.cause()
}
}
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)
}
}