macro_map/lib.rs
1//! A small toolbelt of macros that implement the [`Option::ok_or_else`] and
2//! [`Result::map_err`] with macros instead of functions taking callbacks.
3//!
4//! This reduces the boilerplate when you can't use the abovementioned functions
5//! because the error condition handling logic you need requires you that
6//! you move certain values into the closures which you can't affort.
7//!
8//! People would normally work around it by `.clone()`-ing the value
9//! to be passed into the closure, but that's bad because:
10//!
11//! - you need to `.clone()` the item, and that's not always possible;
12//! - the `.clone()` is not really necessary, you can rewrite the code with
13//! a manual `match` that would not require and ownership transfers.
14//!
15//! But writing a match is vebose, and who wants that?!
16//! This is where this crate comes to help.
17//!
18//! For best look and feel, combine with
19//! [`postfix-macros`](https://docs.rs/postfix-macros) crate.
20
21/// An analog to [`Result::map_err`] but without a closure.
22///
23/// ```
24/// use macro_map::map_err;
25///
26/// let myresult: Result<&str, &str> = Err("hello");
27///
28/// let mapped = map_err!(myresult, |myerr| 123);
29///
30/// assert_eq!(mapped, Err(123));
31/// ```
32///
33/// Or with [`postfix-macros`](https://docs.rs/postfix-macros):
34///
35/// ```
36/// use macro_map::map_err;
37/// use postfix_macros::postfix_macros;
38///
39/// let myresult: Result<&str, &str> = Err("hello");
40///
41/// postfix_macros! {
42/// let mapped = myresult.map_err!(|myerr| 123);
43/// }
44///
45/// assert_eq!(mapped, Err(123));
46/// ```
47#[macro_export]
48macro_rules! map_err {
49 ($result:expr, |$err:pat_param| $closure:expr) => {
50 match $result {
51 Ok(val) => Ok(val),
52 Err($err) => Err($closure),
53 }
54 };
55}
56
57/// An analog to [`Option::ok_or_else`] but without a closure.
58///
59/// ```
60/// use macro_map::ok_or_else;
61///
62/// let myoption: Option<&str> = None;
63///
64/// let mapped = ok_or_else!(myoption, || 123);
65///
66/// assert_eq!(mapped, Err(123));
67/// ```
68///
69/// Or with [`postfix-macros`](https://docs.rs/postfix-macros):
70///
71/// ```
72/// use macro_map::ok_or_else;
73/// use postfix_macros::postfix_macros;
74///
75/// let myoption: Option<&str> = None;
76///
77/// postfix_macros! {
78/// let mapped = ok_or_else!(myoption, || 123);
79/// }
80///
81/// assert_eq!(mapped, Err(123));
82/// ```
83#[macro_export]
84macro_rules! ok_or_else {
85 ($result:expr, || $closure:expr) => {
86 match $result {
87 Some(val) => Ok(val),
88 None => Err($closure),
89 }
90 };
91}
92
93/// An analog to [`Result::map_err`] followed by a `?` but without a closure.
94///
95/// ```
96/// use macro_map::try_map_err;
97///
98/// fn myfn() -> Result<(), i64> {
99/// let myresult: Result<&str, &str> = Err("hello");
100/// try_map_err!(myresult, |myerr| 123);
101/// Ok(())
102/// }
103///
104/// let mapped = myfn();
105///
106/// assert_eq!(mapped, Err(123));
107/// ```
108///
109/// Or with [`postfix-macros`](https://docs.rs/postfix-macros):
110///
111/// ```
112/// use macro_map::try_map_err;
113/// use postfix_macros::postfix_macros;
114///
115/// fn myfn() -> Result<(), i64> {
116/// postfix_macros! {
117/// let myresult: Result<&str, &str> = Err("hello");
118/// myresult.try_map_err!(|myerr| 123);
119/// Ok(())
120/// }
121/// }
122///
123///
124/// let mapped = myfn();
125///
126/// assert_eq!(mapped, Err(123));
127/// ```
128#[macro_export]
129macro_rules! try_map_err {
130 ($result:expr, |$err:pat_param| $closure:expr) => {
131 match $result {
132 Ok(val) => val,
133 Err($err) => return Err($closure.into()),
134 }
135 };
136}
137
138/// An analog to [`Result::map_err`] followed by a `?` but without a closure.
139///
140/// ```
141/// use macro_map::try_ok_or_else;
142///
143/// fn myfn() -> Result<(), i64> {
144/// let myoption: Option<&str> = None;
145/// try_ok_or_else!(myoption, || 123);
146/// Ok(())
147/// }
148///
149/// let mapped = myfn();
150///
151/// assert_eq!(mapped, Err(123));
152/// ```
153///
154/// Or with [`postfix-macros`](https://docs.rs/postfix-macros):
155///
156/// ```
157/// use macro_map::try_ok_or_else;
158/// use postfix_macros::postfix_macros;
159///
160/// fn myfn() -> Result<(), i64> {
161/// postfix_macros! {
162/// let myoption: Option<&str> = None;
163/// myoption.try_ok_or_else!(|| 123);
164/// Ok(())
165/// }
166/// }
167///
168///
169/// let mapped = myfn();
170///
171/// assert_eq!(mapped, Err(123));
172/// ```
173#[macro_export]
174macro_rules! try_ok_or_else {
175 ($result:expr, || $closure:expr) => {
176 match $result {
177 Some(val) => val,
178 None => return Err($closure.into()),
179 }
180 };
181}
182
183#[cfg(test)]
184mod tests {
185 use super::*;
186
187 use postfix_macros::postfix_macros;
188
189 #[derive(Debug)]
190 struct MyNonCopy;
191
192 fn result(a: MyNonCopy, cond: Result<(), ()>) -> Result<MyNonCopy, (MyNonCopy,)> {
193 postfix_macros! {
194 cond.try_map_err!(|_| (a,));
195 Ok(a)
196 }
197 }
198
199 fn option(a: MyNonCopy, cond: Option<()>) -> Result<MyNonCopy, (MyNonCopy,)> {
200 postfix_macros! {
201 cond.try_ok_or_else!(|| (a,));
202 Ok(a)
203 }
204 }
205
206 #[test]
207 fn test_result() {
208 result(MyNonCopy, Ok(())).unwrap();
209 result(MyNonCopy, Err(())).unwrap_err();
210 }
211
212 #[test]
213 fn test_option() {
214 option(MyNonCopy, Some(())).unwrap();
215 option(MyNonCopy, None).unwrap_err();
216 }
217}