error_ex/
lib.rs

1/// Defining an error with set of reason.
2/// # Usage
3/// ```
4/// use error_ex::{create_error};
5/// create_error!(ErrorType => ErrorReason1, ErrorReason2, ErrorReason3);
6/// ```
7/// ## Examples
8///
9/// ```
10/// use error_ex::{create_error};
11///
12/// create_error!(InputError => IllegalArgument, InvalidInput, MissingArgument);
13/// //Now, you can use the following code to instantiate this error
14/// InputError::illegal_argument(format!("Your message here"));
15///
16/// ```
17///
18/// ## Error Mapping
19///
20/// The explicit way
21/// ```
22/// use std::fs;
23/// use error_ex::{create_error};
24///
25/// create_error!(FileError => IoError);
26/// create_error!(SchemaError => ParseError);
27///
28/// let error: Result<(), FileError> = Err(FileError::io_error("".to_string()));
29///
30/// let mapped = error.map_err(|error| {
31///     SchemaError::parse_error(format!("SchemaError::ParseError error {error}"))
32/// });
33///
34/// ```
35/// ## Function wrapper
36/// The above code can be simplified using `map_to__error!`
37/// macro using the build in lower order function
38/// ```
39///
40/// use std::fs;
41/// use std::io::Error;
42/// use error_ex::{create_error};
43///
44/// create_error!(FileError => IoError);
45/// create_error!(SchemaError => ParseError);
46///
47/// let error: Result<(), FileError> = Err(FileError::io_error("".to_string()));
48///
49/// let mapped = error.map_err(SchemaError::map_to_parse_error);
50///
51/// ```
52///
53#[macro_export]
54macro_rules! create_error {
55    ( $error:ident => $( $error_reason:ident ),* ) => {
56        paste::paste! {
57
58            #[derive(Debug, Clone, PartialEq, Eq)]
59            pub struct $error {
60                pub reason: [<$error Reason>],
61                pub message: String,
62            }
63
64            #[derive(Debug, Clone, PartialEq, Eq)]
65            #[allow(unused_qualifications)]
66            pub enum [<$error Reason>] {
67                $(
68                    [<$error_reason>],
69                )*
70            }
71
72            impl $error {
73                $(
74                    #[allow(unused_qualifications)]
75                    pub fn [<$error_reason:snake>](message: String) -> $error {
76                        $error {
77                            reason: [<$error Reason>]::$error_reason,
78                            message,
79                        }
80                    }
81                )*
82
83                $(
84                    #[allow(unused_qualifications)]
85                    pub fn [<map_to_ $error_reason:snake>]<E>(error: E) -> $error
86                    where
87                        E: std::error::Error,
88                    {
89                        let error_name = stringify!($error);
90                        let error_reason_name = stringify!($error_reason);
91                        let error_string =
92                            format!("{}::{} caused by {}", error_name, error_reason_name, error);
93                        $error {
94                            reason: [<$error Reason>]::$error_reason,
95                            message: error_string,
96                        }
97                    }
98                )*
99            }
100
101
102            impl std::error::Error for $error {}
103
104            impl std::fmt::Display for $error {
105                fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
106                    let error_name = stringify!([<$error:camel>]);
107                    write!(
108                        f,
109                        "{:#?} error, reason: {:#?}, message {:#?}",
110                        error_name,
111                        self.reason,
112                        self.message
113                    )
114                }
115            }
116        }
117    };
118}