rdcl_aoc_helpers/
error.rs

1//! Error handling.
2use std::char::ParseCharError;
3use std::fmt;
4use std::process::exit;
5
6/// Trait that adds the `or_exit_with`  method to a struct. To be used to create a way to retrieve a
7/// value, or exit with a specified error code.
8pub trait WithOrExit<T> {
9    fn or_exit_with(self, exit_code: i32) -> T;
10}
11
12impl<T, E: fmt::Debug> WithOrExit<T> for Result<T, E> {
13    /// Unwraps the value from a Result, or terminates the process with the specified exit code.
14    fn or_exit_with(self, exit_code: i32) -> T {
15        match self {
16            Ok(v) => v,
17            Err(e) => {
18                eprintln!("{:?}", e);
19                exit(exit_code);
20            }
21        }
22    }
23}
24
25impl<T> WithOrExit<T> for Option<T> {
26    fn or_exit_with(self, exit_code: i32) -> T {
27        match self {
28            Some(v) => v,
29            None => {
30                eprintln!("Empty option");
31                exit(exit_code);
32            }
33        }
34    }
35}
36
37/// Generic parsing error.
38#[derive(Debug, Clone, Eq, PartialEq)]
39pub struct ParseError(pub String);
40
41impl ParseError {
42    /// Produces a `ParseError` from a `&str`.
43    #[deprecated(since = "0.6.1", note = "Please use the parse_error! macro instead.")]
44    pub fn of(s: &str) -> ParseError {
45        ParseError(s.to_string())
46    }
47}
48
49impl fmt::Display for ParseError {
50    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51        write!(f, "{}", self.0)
52    }
53}
54
55impl From<std::io::Error> for ParseError {
56    fn from(err: std::io::Error) -> Self {
57        ParseError(format!("{:?}", err))
58    }
59}
60
61impl From<std::num::ParseIntError> for ParseError {
62    fn from(err: std::num::ParseIntError) -> Self {
63        ParseError(format!("{:?}", err))
64    }
65}
66
67impl From<std::char::ParseCharError> for ParseError {
68    fn from(err: ParseCharError) -> Self {
69        ParseError(format!("{:?}", err))
70    }
71}
72
73// TODO:
74// impl From<std::option::NoneError> for ParseError {
75//     fn from(err: std::option::NoneError) -> Self {
76//         ParseError(format!("{:?}", err))
77//     }
78// }
79
80/// Macro to produce a ParseError, with optional interpolation (using format!).
81#[macro_export]
82macro_rules! parse_error {
83    ($err:expr) => {{
84        $crate::error::ParseError($err.to_string())
85    }};
86    ($err:expr, $($args:tt)*) => {{
87        $crate::error::ParseError(format!($err, $($args)*))
88    }};
89}
90
91/// Macro to produce a ParseError wrapped in an Err, with optional interpolation (using format!).
92#[macro_export]
93macro_rules! err_parse_error {
94    ($err:expr) => {{
95        Err($crate::parse_error!($err))
96    }};
97    ($err:expr, $($args:tt)*) => {{
98        Err($crate::parse_error!($err, $($args)*))
99    }};
100}
101
102#[cfg(test)]
103mod tests {
104    use super::*;
105
106    #[test]
107    fn test_macro_parse_error_simple() {
108        let err = parse_error!["This is a simple error."];
109        assert_eq!(err, ParseError("This is a simple error.".to_string()));
110    }
111
112    #[test]
113    fn test_macro_parse_error_with_formatting() {
114        let err = parse_error!["This is an error with {}.", "formatting"];
115        assert_eq!(
116            err,
117            ParseError("This is an error with formatting.".to_string())
118        );
119    }
120
121    #[test]
122    fn test_macro_err_parse_error_simple() {
123        let err: Result<(), ParseError> = err_parse_error!["This is a simple error."];
124        assert_eq!(err, Err(ParseError("This is a simple error.".to_string())));
125    }
126
127    #[test]
128    fn test_macro_err_parse_error_with_formatting() {
129        let err: Result<(), ParseError> =
130            err_parse_error!["This is an error with {}.", "formatting"];
131
132        assert_eq!(
133            err,
134            Err(ParseError("This is an error with formatting.".to_string()))
135        );
136    }
137}