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
//! Types for errors that can occur while working with DBN.
use thiserror::Error;
/// An error that can occur while processing DBN data.
#[derive(Debug, Error)]
pub enum Error {
/// An I/O error while reading or writing DBN or another encoding.
#[error("IO error: {source:?} while {context}")]
Io {
/// The original error.
#[source]
source: std::io::Error,
/// The context in which the error occurred.
context: String,
},
/// An error while decoding from DBN.
#[error("decoding error: {0}")]
Decode(String),
/// An error with text encoding.
#[error("encoding error: {0}")]
Encode(String),
/// An conversion error between types or encodings.
#[error("couldn't convert {input} to {desired_type}")]
Conversion {
/// The input to the conversion.
input: String,
/// The desired type or encoding.
desired_type: &'static str,
},
/// An error with conversion of bytes to UTF-8.
#[error("UTF-8 error: {source:?} while {context}")]
Utf8 {
/// The original error.
#[source]
source: std::str::Utf8Error,
/// The context in which the error occurred.
context: String,
},
}
/// An alias for a `Result` with [`dbn::Error`](crate::Error) as the error type.
pub type Result<T> = std::result::Result<T, Error>;
impl From<csv::Error> for Error {
fn from(value: csv::Error) -> Self {
match value.into_kind() {
csv::ErrorKind::Io(io) => Self::io(io, "While writing CSV"),
csv::ErrorKind::Utf8 { pos, err } => {
Self::Encode(format!("UTF-8 error {err:?}{}", Self::opt_pos(&pos)))
}
csv::ErrorKind::UnequalLengths {
pos,
expected_len,
len,
} => Self::Encode(format!(
"unequal CSV row lengths{}: expected {expected_len}, found {len}",
Self::opt_pos(&pos)
)),
e => Self::Encode(format!("{e:?}")),
}
}
}
impl Error {
/// Creates a new I/O [`dbn::Error`](crate::Error).
pub fn io(error: std::io::Error, context: impl ToString) -> Self {
Self::Io {
source: error,
context: context.to_string(),
}
}
/// Creates a new decode [`dbn::Error`](crate::Error).
pub fn decode(msg: impl ToString) -> Self {
Self::Decode(msg.to_string())
}
/// Creates a new encode [`dbn::Error`](crate::Error).
pub fn encode(msg: impl ToString) -> Self {
Self::Encode(msg.to_string())
}
/// Creates a new conversion [`dbn::Error`](crate::Error) where `desired_type` is `T`.
pub fn conversion<T>(input: impl ToString) -> Self {
Self::Conversion {
input: input.to_string(),
desired_type: std::any::type_name::<T>(),
}
}
/// Creates a new UTF-8 [`dbn::Error`](crate::Error).
pub fn utf8(error: std::str::Utf8Error, context: impl ToString) -> Self {
Self::Utf8 {
source: error,
context: context.to_string(),
}
}
fn opt_pos(pos: &Option<csv::Position>) -> String {
if let Some(pos) = pos.as_ref() {
format!(" at {pos:?}")
} else {
String::default()
}
}
}
pub(crate) fn silence_eof_error<T>(err: std::io::Error) -> std::io::Result<Option<T>> {
if err.kind() == std::io::ErrorKind::UnexpectedEof {
Ok(None)
} else {
Err(err)
}
}