inner/
lib.rs

1//! The `inner!` macro makes descending into an enum variant
2//! more ergonomic.
3//!
4//! The `some!` and `ok!` macros turn your enum into an `Option` and `Result`, respectively.
5//!
6//! # Helpful unwrap
7//! The simplest case for `inner!` is almost like unwrap:
8//!
9//! ```
10//! # #[macro_use] extern crate inner;
11//! # fn main() {
12//! let x = Some(1);
13//! let y: Result<_, ()> = Ok(2);
14//! assert_eq!(inner!(x), 1);
15//! assert_eq!(inner!(y), 2);
16//! # }
17//! ```
18//!
19//! ...but if you instead use it on a `None` or `Err` value:
20//!
21//! ```ignore
22//! let z = None;
23//! let y = inner!(z);
24//! ```
25//!
26//! ...it will panic, with an error message that points you to a more
27//! helpful location than some line number inside libcore:
28//!
29//! ```ignore
30//! thread "test" panicked at "Unexpected value found inside "z"", src/lib.rs:23
31//! ```
32//!
33//! # Error handling
34//! If panic isn't an option - and it usually isn't - just add an `else` clause:
35//!
36//! ```
37//! # #[macro_use] extern crate inner;
38//! # fn main() {
39//! let x: Result<String, i32> = Err(7);
40//! let y = inner!(x, else { return });
41//! // Since x is an Err, we'll never get here.
42//! println!("The string length is: {}", y.len());
43//! # }
44//! ```
45//!
46//! You can use the else clause to compute a default value, or use flow control
47//! (e g `break`, `continue`, or `return`).
48//!
49//! Want access to what's inside the `Err` value in your `else` clause?
50//! No problem, just add a `|variable|` after `else`, like this:
51//!
52//! ```
53//! # #[macro_use] extern crate inner;
54//! # fn main() {
55//! let x: Result<String, i32> = Err(7);
56//! let y = inner!(x, else |e| {
57//!     assert_eq!(e, 7);
58//!     (e + 2).to_string()
59//! });
60//! assert_eq!(&y, "9");
61//! # }
62//! ```
63//!
64//! Note: This does not turn your else clause into a closure, so you can still use
65//! (e g) `return` the same way as before.
66//!
67//! # It works with your enums too
68//! It does not work only with `Option` and `Result`. Just add an `if` clause:
69//!
70//! ```
71//! # #[macro_use] extern crate inner;
72//! # fn main() {
73//! enum Fruit {
74//!     Apple(i32),
75//!     Orange(i16),
76//! }
77//! 
78//! let z = Fruit::Apple(15);
79//! let y = inner!(z, if Fruit::Apple, else {
80//!     println!("I wanted an apple and I didn't get one!");
81//!     0
82//! });
83//! assert_eq!(y, 15);
84//! # }
85//! ```
86//!
87//! You can skip the `else` clause to panic in case the enum is not
88//! the expected variant.
89//!
90//! Note that in this case, the entire item (instead of the contents inside
91//! `Err`) is passed on to the `else` clause:
92//!
93//! ```
94//! # #[macro_use] extern crate inner;
95//! # fn main() {
96//! #[derive(Eq, PartialEq, Debug)]
97//! enum Fruit {
98//!     Apple(i32),
99//!     Orange(i16),
100//! }
101//! 
102//! let z = Fruit::Orange(15);
103//! inner!(z, if Fruit::Apple, else |e| {
104//!     assert_eq!(e, Fruit::Orange(15));
105//!     return;
106//! });
107//! # }
108//! ```
109//!
110//! Another option is to implement this crate's `IntoResult` trait for
111//! your enum. Then you don't have to write an `if` clause to tell what
112//! enum variant you want to descend into, and you can choose more than
113//! one enum variant to be `Ok`:
114//!
115//! ```ignore
116//! enum Fruit {
117//!     Apple(i32),
118//!     Orange(i16),
119//!     Rotten,
120//! }
121//!
122//! impl IntoResult<i32, ()> for Fruit {
123//!     fn into_result(self) -> Result<i32, ()> {
124//!         match self {
125//!             Fruit::Apple(i) => Ok(i),
126//!             Fruit::Orange(i) => Ok(i as i32),
127//!             Fruit::Rotten => Err(()),
128//!         }
129//!     }
130//! }
131//!
132//! assert_eq!(9, inner!(Fruit::Apple(9)));
133//! ```
134//!
135//! # License
136//! Apache2.0/MIT
137
138/// Converts a value into a Result.
139/// You can implement this for your own types if you want
140/// to use the `inner!` macro in more ergonomic ways.
141pub trait IntoResult<T, E> {
142    fn into_result(self) -> Result<T, E>;
143}
144
145
146/* 
147// Impossible due to conflicting impls :-(
148impl<T, E, Z> IntoResult<T, E> for Z where Z: Into<Result<T, E>> {
149    fn into_result(self) -> Result<T, E> { self.into() }
150}
151*/
152
153impl<T, E> IntoResult<T, E> for Result<T, E> {
154    #[inline]
155    fn into_result(self) -> Result<T, E> { self }
156}
157
158impl<T> IntoResult<T, ()> for Option<T> {
159    #[inline]
160    fn into_result(self) -> Result<T, ()> { self.ok_or(()) }
161}
162
163/// The `inner!` macro - see module level documentation for details.
164#[macro_export]
165macro_rules! inner {
166    ($x:expr, if $i:path, else |$e:ident| $b:block) => {
167        {
168            match $x {
169                $i(q) => q,
170                $e @ _ => $b,
171            }
172        }
173    };
174
175    ($x:expr, if $i:path, else $b:block) => {
176        {
177            match $x {
178                $i(q) => q,
179                _ => $b,
180            }
181        }
182    };
183
184    ($x:expr, else |$e:ident| $b:block) => {
185        {
186            use $crate::IntoResult;
187            match $x.into_result() {
188                Ok(q) => q,
189                Err($e) => $b,
190            }
191        }
192    };
193
194    ($x:expr, else $b:block) => {
195        {
196            use $crate::IntoResult;
197            match $x.into_result() {
198                Ok(q) => q,
199                _ => $b,
200            }
201        }
202    };
203
204    ($x:expr, if $i:path) => {
205        {
206            match $x {
207                $i(q) => q,
208                _ => panic!("Unexpected value found inside '{}'", stringify!($x)),
209            }
210        }
211    };
212
213    ($x:expr) => {
214        {
215            use $crate::IntoResult;
216            match $x.into_result() {
217                Ok(q) => q,
218                _ => panic!("Unexpected value found inside '{}'", stringify!($x)),
219            }
220        }
221    };
222}
223
224/// Converts your enum to an Option.
225///
226/// # Examples
227///
228/// ```ignore
229/// assert_eq!(some!(Fruit::Apple(15), if Fruit::Apple), Some(15));
230/// assert_eq!(some!(Fruit::Orange(5), if Fruit::Apple), None);
231/// ```
232#[macro_export]
233macro_rules! some {
234    ($x:expr, if $i:path, else |$e:ident| $b:block) => {
235        {
236            match $x {
237                $i(q) => Some(q),
238                $e @ _ => $b,
239            }
240        }
241    };
242
243    ($x:expr, if $i:path, else $b:block) => {
244        {
245            match $x {
246                $i(q) => Some(q),
247                _ => $b,
248            }
249        }
250    };
251
252    ($x:expr, if $i:path) => {
253        {
254            match $x {
255                $i(q) => Some(q),
256                _ => None,
257            }
258        }
259    };
260}
261
262/// Converts your enum to an Result.
263///
264/// # Examples
265///
266/// ```ignore
267/// assert_eq!(ok!(Fruit::Apple(15), if Fruit::Apple), Ok(15));
268/// assert_eq!(ok!(Fruit::Orange(5), if Fruit::Apple), Err(Fruit::Orange(5)));
269///
270/// assert_eq!(ok!(Fruit::Orange(5), if Fruit::Apple, or {75}), Err(75));
271/// assert_eq!(ok!(Fruit::Orange(5), if Fruit::Apple, else {Err(75)}), Err(75));
272/// ```
273#[macro_export]
274macro_rules! ok {
275    ($x:expr, if $i:path, else |$e:ident| $b:block) => {
276        {
277            match $x {
278                $i(q) => Ok(q),
279                $e @ _ => $b,
280            }
281        }
282    };
283
284    ($x:expr, if $i:path, else $b:block) => {
285        {
286            match $x {
287                $i(q) => Ok(q),
288                _ => $b,
289            }
290        }
291    };
292
293    ($x:expr, if $i:path, or |$e:ident| $b:block) => {
294        {
295            match $x {
296                $i(q) => Ok(q),
297                $e @ _ => Err($b),
298            }
299        }
300    };
301
302    ($x:expr, if $i:path, or $b:block) => {
303        {
304            match $x {
305                $i(q) => Ok(q),
306                _ => Err($b),
307            }
308        }
309    };
310
311    ($x:expr, if $i:path) => {
312        {
313            match $x {
314                $i(q) => Ok(q),
315                n @ _ => Err(n),
316            }
317        }
318    };
319}
320
321
322#[test]
323fn simple_opt() {
324    assert_eq!(inner!(Some(7)), 7);
325}
326
327#[test]
328#[should_panic]
329fn simple_opt_fail() {
330    let z: Option<i32> = None;
331    inner!(z);
332}
333
334#[test]
335fn else_clause() {
336    let x: Result<String, i32> = Err(7);
337    let _ = inner!(x, else { return });
338    panic!();
339}
340
341#[test]
342fn else_clause_2() {
343    let x: Result<String, i32> = Err(7);
344    let y = inner!(x, else |e| {
345        assert_eq!(e, 7);
346        (e + 2).to_string()
347    });
348    assert_eq!(&y, "9");
349}
350
351#[test]
352fn apple() {
353    enum Fruit {
354        Apple(i32),
355        _Orange(i16),
356    }
357    let z = Fruit::Apple(15);
358    assert_eq!(15, inner!(z, if Fruit::Apple));
359}
360
361#[test]
362fn if_else() {
363    enum Fruit {
364        Apple(i32),
365        _Orange(i16),
366    }
367    let z = Fruit::Apple(15);
368    assert_eq!(15, inner!(z, if Fruit::Apple, else {
369        panic!("Not an apple");
370    }));
371}
372
373#[test]
374fn own_enum() {
375    #[derive(Debug, PartialEq, Eq)]
376    enum Fruit {
377        Apple(i32),
378        Orange(i16),
379    }
380
381    impl IntoResult<i32, i16> for Fruit {
382        fn into_result(self) -> Result<i32, i16> {
383            match self {
384                Fruit::Apple(i) => Ok(i),
385                Fruit::Orange(i) => Err(i),
386            }
387        }
388    }
389    let z = Fruit::Orange(15);
390    assert_eq!(7, inner!(z, else |e| { (e - 8) as i32 }));
391
392    let z = Fruit::Apple(15);
393    assert_eq!(9, inner!(z, if Fruit::Orange, else |e| {
394        assert_eq!(e, Fruit::Apple(15));
395        9
396    }));
397
398}
399
400#[test]
401fn some() {
402
403    #[derive(Debug, PartialEq, Eq)]
404    enum Fruit {
405        Apple(i32),
406        Orange(i16),
407    }
408
409    assert_eq!(some!(Fruit::Apple(15), if Fruit::Apple), Some(15));
410    assert_eq!(some!(Fruit::Orange(15), if Fruit::Apple), None);
411    assert_eq!(some!(Fruit::Orange(15), if Fruit::Apple, else |e| {
412        assert_eq!(e, Fruit::Orange(15));
413        Some(30)
414    }), Some(30));
415}
416
417#[test]
418fn ok() {
419
420    #[derive(Debug, PartialEq, Eq)]
421    enum Fruit {
422        Apple(i32),
423        Orange(i16),
424    }
425
426    assert_eq!(ok!(Fruit::Apple(15), if Fruit::Apple), Ok(15));
427
428    assert_eq!(ok!(Fruit::Orange(15), if Fruit::Apple), Err(Fruit::Orange(15)));
429    assert_eq!(ok!(Fruit::Orange(15), if Fruit::Apple, else |e| {
430        assert_eq!(e, Fruit::Orange(15));
431        Err(3)
432    }), Err(3));
433
434    assert_eq!(ok!(Fruit::Apple(15), if Fruit::Orange, or {67}), Err(67));
435    assert_eq!(ok!(Fruit::Apple(15), if Fruit::Apple, or {67}), Ok(15));
436}
437