utils_results/macros/
errbang.rs

1/*
2    .. + errbang.rs + ..
3    Copyright 2021 Hwakyeom Kim(=just-do-halee)
4*/
5
6// #[doc = include_str!("../../README.md")]
7
8/// make some error. floating Err(..)
9/// ```ignore
10/// errbang!("error.");
11/// errbang!(err::MyError1);
12/// errbang!(err::MyError2, "cannot find.");
13/// errbang!(err::MyError3, "{} is {}", "bar", 2);
14/// ```
15#[macro_export]
16macro_rules! errbang {
17    (@create $kind:ty$(, $format_str:expr$(, $val:expr )* )?$(, @stamp: $flcb:expr$(, $flc:expr)+)?$(, @chain: $eb:expr$(, $e:expr)+)?) => {
18        $crate::private::Error::msg(<$kind>::new($crate::private::format!(concat!($($eb ,)?"\n"$(, $flcb)?, " {} " $(, $format_str)?, " <{}>") $($(, $e)+)?$($(, $flc)+)?, <$kind>::message() $($(, $val)*)?, stringify!($kind))))
19    };
20    ($format_str:literal$(, $val:expr )*) => {
21        Err(errbang!(@create err::__, $format_str$(, $val )*, @stamp: "  [{} {}:{}]", file!(), line!(), column!()).into())
22    };
23    ($kind:ty$(, $format_str:literal$(, $val:expr )* )?) => {
24        Err(errbang!(@create $kind$(, $format_str$(, $val )* )?, @stamp: "  [{} {}:{}]", file!(), line!(), column!()).into())
25    };
26}
27
28/// Any type of error can be converted into our Master Error. **(non panic unwraping)**
29/// ```ignore
30/// // example
31/// // <Unwraped Ok> = errcast!(<Any Result>, <Master Err>, <Optional,..>);
32/// let num_read = errcast!(file.read(&mut buf), err::ReadErr, "this is {} data.", "meta");
33/// ```
34/// also can
35/// ```ignore
36/// let num_read = errcast!(file.read(&mut buf));
37/// let num_read = errcast!(file.read(&mut buf), "some error.");
38/// ```
39#[macro_export]
40macro_rules! errcast {
41    ($result:expr) => {
42        match $result {
43            Ok(v) => v,
44            Err(e) => return Err(errbang!(@create err::__, @stamp: "  [{} {}:{}]", file!(), line!(), column!(), @chain: "{} {}\n {:>20}⎺↴", e, stringify!($result), " ").into()),
45        }
46    };
47    ($result:expr, $format_str:literal$(, $val:expr )*) => {
48        match $result {
49            Ok(v) => v,
50            Err(e) => return Err(errbang!(@create err::__, $format_str $(, $val )*, @stamp: "  [{} {}:{}]", file!(), line!(), column!(), @chain: "{} {}\n {:>20}⎺↴", e, stringify!($result), " ").into()),
51        }
52    };
53    ($result:expr, $kind:ty$(, $format_str:expr$(, $val:expr )* )?) => {
54        match $result {
55            Ok(v) => v,
56            Err(e) => return Err(errbang!(@create $kind$(, $format_str $(, $val )*)?, @stamp: "  [{} {}:{}]", file!(), line!(), column!(), @chain: "{} {}\n {:>20}⎺↴", e, stringify!($result), " ").into()),
57        }
58    };
59}
60
61/// any type of inside Err() can match this
62/// ```ignore
63/// if let Err(e) = some_result() {
64///     // errmatch!(<Unwraped Err>, <Any Type>)
65///     if errmatch!(e, err::MyError0) {
66///         // ...   
67///     }
68/// }
69/// ```
70/// returns boolean
71#[macro_export]
72macro_rules! errmatch {
73    ($err:expr, $kind:ty) => {
74        match $err.downcast_ref::<$kind>() {
75            Some(_) => true,
76            None => false,
77        }
78    };
79}
80
81/// non panic unwraping and specific error can return matching block<br>
82/// other errors will go out -> Result\<T\>
83/// ```ignore
84/// fn exe(path: &str) -> Result<usize> {
85///     let file = errcast!(File::open("test"), err::FileOpenError);
86///     // .....
87///     // ...
88///     Ok(num)
89/// }
90///
91/// fn main() -> Result<()> {
92///     /// non panic unwraping
93///     /// and specific error can return
94///     /// matching block
95///     let num = errextract!(exe(path),
96///         err::FileOpenError => 0);
97///     /// other errors will go out -> Result<T>
98///
99///     Ok(())
100/// }
101/// ```
102#[macro_export]
103macro_rules! errextract {
104    ($result:expr, $kind:ty => $match:expr) => {
105        match $result {
106            Ok(v) => v,
107            Err(e) if errmatch!(e, $kind) => $match,
108            Err(e) => return Err(e),
109        }
110    };
111}
112
113/// create custom error list
114/// ```ignore
115/// err! {
116///      BrokenHeader => "broken header."
117///      AnotherHeader => "not matched header."
118///      FileNotFound => "file not found."
119///      EmptyArgument => "empty argument."
120///      UnexpectedEof => "unexpected eof."
121///      OutOfBounds => "index out of bounds."
122///      NotMatched => "btw not matched."
123/// }
124///
125/// errbang!(err::BrokenHeader);
126/// ```
127#[macro_export]
128macro_rules! err {
129    (
130        @create errstruct $kind:ident $message:tt
131    ) => {
132        pub struct $kind {
133            chain: $crate::private::String
134        }
135
136        impl $kind {
137            pub fn new(chain: $crate::private::String) -> Self {
138                Self { chain }
139            }
140            pub fn message() -> &'static str {
141                $message
142            }
143            pub fn input_data<'a>(&'a self) -> &'a str {
144                let start = self.chain.find(']').unwrap() + $message.len() + 3;
145                let end = self.chain.rfind('<').unwrap() - 1;
146                self.chain.get(start..end).unwrap()
147            }
148        }
149
150        impl $crate::private::fmt::Display for $kind {
151            fn fmt(&self, f: &mut $crate::private::fmt::Formatter<'_>) -> $crate::private::fmt::Result {
152                write!(f, " {}", self.chain)
153            }
154        }
155        impl $crate::private::fmt::Debug for $kind {
156            fn fmt(&self, f: &mut $crate::private::fmt::Formatter<'_>) -> $crate::private::fmt::Result {
157                write!(f, "{0}{1}{0}", "\n".repeat(2), self.chain)
158            }
159        }
160
161    };
162    (
163            $($kind:ident => $message:tt$(,)?)*
164    ) => {
165
166        pub mod err {
167            use super::*;
168
169            #[doc(hidden)]
170            err!(@create errstruct __ "external error");
171
172
173            $(
174                err!(@create errstruct $kind $message);
175            )*
176
177        }
178
179    };
180}
181
182/// unwrapping error input data.
183/// ```ignore
184/// fn foo() -> Result<()> {
185///     return errbang!(err::Bar, "this is input.");
186/// }
187///
188/// assert_eq!(
189///    errunwrap!(foo(), err::Bar), "this is input."
190/// );
191///
192/// ```
193/// this is equal to
194/// ```ignore
195/// $result.unwrap_err()
196///     .downcast_ref::<$kind>()
197///     .unwrap()
198///     .input_data()
199/// ```
200/// returns boolean
201#[macro_export]
202macro_rules! errunwrap {
203    ($result:expr, $kind:ty) => {
204        $result
205            .unwrap_err()
206            .downcast_ref::<$kind>()
207            .unwrap()
208            .input_data()
209    };
210}
211
212/// panic! with Master Error
213/// ```ignore
214/// errpanic!(err::MyError1);
215/// errpanic!(err::MyError2, "cannot find.");
216/// errpanic!(err::MyError3, "{} is {}", "bar", 2);
217/// ```
218#[macro_export]
219macro_rules! errpanic {
220    ($kind:ty$(, $format_str:expr$(, $val:expr )* )?) => {
221        panic!("{0}{1}{0}\n", "\n".repeat(5), errbang!(@create $kind$(, $format_str$(, $val )* )?, @stamp: "  [{} {}:{}]", file!(), line!(), column!()))
222    };
223}
224
225/// println! with Master Error
226/// ```ignore
227/// errprint!(err::MyError1);
228/// errprint!(err::MyError2, "cannot find.");
229/// errprint!(err::MyError3, "{} is {}", "bar", 2);
230/// ```
231#[macro_export]
232macro_rules! errprint {
233    ($kind:ty$(, $format_str:expr$(, $val:expr )* )?) => {
234        println!("{0}{1}{0}\n", "\n".repeat(5), errbang!(@create $kind$(, $format_str$(, $val )* )?, @stamp: "  [{} {}:{}]", file!(), line!(), column!()))
235    };
236}
237
238/// Any type of error can be converted into our Master Error. **(and unwraping)**<br>
239/// `And then panic!`
240/// ```ignore
241/// // example
242/// // <Unwraped Ok> = errcast!(<Any Result>, <Master Err>, <Optional,..>);
243/// let num_read = errcast_panic!(file.read(&mut buf), err::ReadErr, "this is {} data.", "meta");
244/// ```
245/// also can
246/// ```ignore
247/// let num_read = errcast_panic!(file.read(&mut buf));
248/// ```
249#[macro_export]
250macro_rules! errcast_panic {
251    ($result:expr) => {
252        match $result {
253            Ok(v) => v,
254            Err(e) => panic!("{0}{1}{0}\n", "\n".repeat(5), errbang!(@create err::__, @stamp: "  [{} {}:{}]", file!(), line!(), column!(), @chain: "{} {}\n {:>20}⎺↴", e, stringify!($result), " ")),
255        }
256    };
257    ($result:expr, $kind:ty$(, $format_str:expr$(, $val:expr )* )?) => {
258        match $result {
259            Ok(v) => v,
260            Err(e) => panic!("{0}{1}{0}\n", "\n".repeat(5), errbang!(@create $kind$(, $format_str $(, $val )*)?, @stamp: "  [{} {}:{}]", file!(), line!(), column!(), @chain: "{} {}\n {:>20}⎺↴", e, stringify!($result), " ")),
261        }
262    };
263}
264
265/// matching io::Error and Master Error to use casting error macros<br>
266///```ignore
267/// io_to_err!(file.seek(SeekFrom::End(0)))?; // <- io::Error to err
268/// err_to_io!(my_seek(0))?; // <- err to io::Error
269///```
270///```ignore
271/// io_err! {
272///     // std::io::ErrorKind => err::MyError
273///     UnexpectedEof => err::MyError1
274///     Interrupted => err::MyError2
275/// }
276///```
277#[cfg(feature = "std")]
278#[macro_export]
279macro_rules! io_err {
280    (
281        $($kind:ident => $errkind:ty$(,)?)*
282    ) => {
283        #[doc(hidden)]
284        pub fn fn_handle_io_to_err<T>(io_error: std::io::Result<T>, file: &str, line :u32, column: u32) -> $crate::private::Result<T> {
285            match io_error {
286                Err(e) => match e.kind() {
287                    $(
288                        std::io::ErrorKind::$kind => Err(errbang!(@create $errkind, "* io to err.", @stamp: "  [{} {}:{}]", file, line, column).into()),
289                    )*
290                    _ => Err(e.into()),
291                },
292                Ok(t) => Ok(t),
293            }
294        }
295        #[doc(hidden)]
296        pub fn fn_handle_err_to_io<T>(m_error: $crate::private::Result<T>, file: &str, line :u32, column: u32) -> std::io::Result<T> {
297            match m_error {
298                Err(e) => match e {
299                    $(
300                        e if errmatch!(e, $errkind) => std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::$kind, format!("  [{} {}:{}] io::Error {:-<20} {}", file, line, column, "<", e))),
301                    )*
302                    _ => std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::Other, format!("  [{} {}:{}] io::Error {:-<20} {}", file, line, column, "<", e))),
303                },
304                Ok(t) => std::io::Result::Ok(t),
305            }
306        }
307    };
308}
309
310/// casting core::io Error to Master Error matched by `io_err`
311///```ignore
312/// io_to_err!(file.seek(SeekFrom::End(0)))?
313///```
314#[cfg(feature = "std")]
315#[macro_export]
316macro_rules! io_to_err {
317    (
318        $ioe:expr
319    ) => {
320        fn_handle_io_to_err($ioe, file!(), line!(), column!())
321    };
322}
323
324/// casting Master Error to core::io Error matched by `io_err`
325///```ignore
326/// err_to_io!(my_seek(0))?
327///```
328#[cfg(feature = "std")]
329#[macro_export]
330macro_rules! err_to_io {
331    (
332        $err:expr
333    ) => {
334        fn_handle_err_to_io($err, file!(), line!(), column!())
335    };
336}