1use thiserror::Error;
3
4#[derive(Debug, Error)]
6#[non_exhaustive]
7pub enum Error {
8 #[error("IO error: {source:?} while {context}")]
10 Io {
11 #[source]
13 source: std::io::Error,
14 context: String,
16 },
17 #[error("decoding error: {0}")]
19 Decode(String),
20 #[error("encoding error: {0}")]
22 Encode(String),
23 #[error("couldn't convert {input} to {desired_type}")]
25 Conversion {
26 input: String,
28 desired_type: &'static str,
30 },
31 #[error("UTF-8 error: {source:?} while {context}")]
33 Utf8 {
34 #[source]
36 source: std::str::Utf8Error,
37 context: String,
39 },
40 #[error("bad argument {param_name}: {desc}")]
42 BadArgument {
43 param_name: String,
45 desc: String,
47 },
48}
49pub 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 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 pub fn decode(msg: impl ToString) -> Self {
83 Self::Decode(msg.to_string())
84 }
85
86 pub fn encode(msg: impl ToString) -> Self {
88 Self::Encode(msg.to_string())
89 }
90
91 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 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}