dbn/
error.rs

1//! Types for errors that can occur while working with DBN.
2use thiserror::Error;
3
4/// An error that can occur while processing DBN data.
5#[derive(Debug, Error)]
6#[non_exhaustive]
7pub enum Error {
8    /// An I/O error while reading or writing DBN or another encoding.
9    #[error("IO error: {source:?} while {context}")]
10    Io {
11        /// The original error.
12        #[source]
13        source: std::io::Error,
14        /// The context in which the error occurred.
15        context: String,
16    },
17    /// An error while decoding from DBN.
18    #[error("decoding error: {0}")]
19    Decode(String),
20    /// An error with text encoding.
21    #[error("encoding error: {0}")]
22    Encode(String),
23    /// An conversion error between types or encodings.
24    #[error("couldn't convert {input} to {desired_type}")]
25    Conversion {
26        /// The input to the conversion.
27        input: String,
28        /// The desired type or encoding.
29        desired_type: &'static str,
30    },
31    /// An error with conversion of bytes to UTF-8.
32    #[error("UTF-8 error: {source:?} while {context}")]
33    Utf8 {
34        /// The original error.
35        #[source]
36        source: std::str::Utf8Error,
37        /// The context in which the error occurred.
38        context: String,
39    },
40    /// An invalid argument was passed to a function.
41    #[error("bad argument {param_name}: {desc}")]
42    BadArgument {
43        /// The name of the parameter to which the bad argument was passed.
44        param_name: String,
45        /// The description of why the argument was invalid.
46        desc: String,
47    },
48}
49/// An alias for a `Result` with [`dbn::Error`](crate::Error) as the error type.
50pub type Result<T> = std::result::Result<T, Error>;
51
52impl From<csv::Error> for Error {
53    fn from(value: csv::Error) -> Self {
54        match value.into_kind() {
55            csv::ErrorKind::Io(io) => Self::io(io, "while writing CSV"),
56            csv::ErrorKind::Utf8 { pos, err } => {
57                Self::Encode(format!("UTF-8 error {err:?}{}", Self::opt_pos(&pos)))
58            }
59            csv::ErrorKind::UnequalLengths {
60                pos,
61                expected_len,
62                len,
63            } => Self::Encode(format!(
64                "unequal CSV row lengths{}: expected {expected_len}, found {len}",
65                Self::opt_pos(&pos)
66            )),
67            e => Self::Encode(format!("{e:?}")),
68        }
69    }
70}
71
72impl Error {
73    /// Creates a new I/O [`dbn::Error`](crate::Error).
74    pub fn io(error: std::io::Error, context: impl ToString) -> Self {
75        Self::Io {
76            source: error,
77            context: context.to_string(),
78        }
79    }
80
81    /// Creates a new decode [`dbn::Error`](crate::Error).
82    pub fn decode(msg: impl ToString) -> Self {
83        Self::Decode(msg.to_string())
84    }
85
86    /// Creates a new encode [`dbn::Error`](crate::Error).
87    pub fn encode(msg: impl ToString) -> Self {
88        Self::Encode(msg.to_string())
89    }
90
91    /// Creates a new conversion [`dbn::Error`](crate::Error) where `desired_type` is `T`.
92    pub fn conversion<T>(input: impl ToString) -> Self {
93        Self::Conversion {
94            input: input.to_string(),
95            desired_type: std::any::type_name::<T>(),
96        }
97    }
98
99    /// Creates a new UTF-8 [`dbn::Error`](crate::Error).
100    pub fn utf8(error: std::str::Utf8Error, context: impl ToString) -> Self {
101        Self::Utf8 {
102            source: error,
103            context: context.to_string(),
104        }
105    }
106
107    fn opt_pos(pos: &Option<csv::Position>) -> String {
108        if let Some(pos) = pos.as_ref() {
109            format!(" at {pos:?}")
110        } else {
111            String::default()
112        }
113    }
114}