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}