konst/macros/unwrapping.rs
1/// `?`-like macro, which allows optionally mapping errors.
2///
3/// `?` currently doesn't work in `const fn`s because as of Rust 1.65.0
4/// trait methods don't work in `const fn`s.
5///
6/// # Examples
7///
8/// ### Basic
9///
10/// ```rust
11/// use konst::try_;
12///
13/// const OK: Result<&str, u8> = expect_no_whitespace("hello");
14/// assert_eq!(OK, Ok("hello"));
15///
16/// const ERR: Result<&str, u8> = expect_no_whitespace("hello world");
17/// assert_eq!(ERR, Err(b' '));
18///
19///
20/// const fn expect_no_whitespace(string: &str) -> Result<&str, u8> {
21/// let bytes = string.as_bytes();
22/// konst::for_range!{i in 0..bytes.len() =>
23/// try_!(assert_not_whitespace(bytes[i]));
24/// }
25/// Ok(string)
26/// }
27///
28/// const fn assert_not_whitespace(byte: u8) -> Result<(), u8> {
29/// if matches!(byte, b'\t' | b'\n' | b'\r' | b' ') {
30/// Err(byte)
31/// } else {
32/// Ok(())
33/// }
34/// }
35///
36/// ```
37///
38/// ### Mapping errors
39///
40/// ```rust
41/// use konst::try_;
42///
43/// const EVENS: Result<[Even; 4], u32> =
44/// array_to_even([0, 2, 4, 6]);
45///
46/// let new = |n| Even::new(n).unwrap();
47/// assert_eq!(EVENS, Ok([new(0), new(2), new(4), new(6)]));
48///
49///
50/// const UNEVEN: Result<[Even; 4], u32> =
51/// array_to_even([0, 2, 5, 6]);
52///
53/// assert_eq!(UNEVEN, Err(5));
54///
55///
56/// const fn array_to_even(arr: [u32; 4]) -> Result<[Even; 4], u32> {
57/// let mut ret = [Even::ZERO; 4];
58///
59/// konst::for_range!{i in 0..4 =>
60/// ret[i] = try_!(Even::new(arr[i]), map_err = |e| e.get() );
61/// }
62///
63/// Ok(ret)
64/// }
65///
66/// #[derive(Debug, PartialEq)]
67/// pub struct Even(u32);
68///
69/// impl Even {
70/// const ZERO: Even = Even(0);
71///
72/// pub const fn new(number: u32) -> Result<Self, NotEven> {
73/// if number % 2 == 0 {
74/// Ok(Even(number))
75/// } else {
76/// Err(NotEven(number))
77/// }
78/// }
79/// }
80///
81/// #[derive(Debug, PartialEq)]
82/// pub struct NotEven(u32);
83///
84/// impl NotEven {
85/// pub const fn get(&self) -> u32 {
86/// self.0
87/// }
88/// }
89///
90/// use std::fmt::{self, Display};
91///
92/// impl Display for NotEven {
93/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
94/// fmt::Debug::fmt(self, f)
95/// }
96/// }
97///
98/// impl std::error::Error for NotEven {}
99///
100/// ```
101///
102#[macro_export]
103macro_rules! try_ {
104 ($e:expr, map_err = |$($pati:pat_param)?| $v:expr $(,)*) => {
105 match $e {
106 $crate::__::Ok(x) => x,
107 $crate::__::Err{$(0: $pati,)? ..} => return $crate::__::Err($v),
108 }
109 };
110 ($e:expr $(,)*) => {{
111 match $e {
112 $crate::__::Ok(x) => x,
113 $crate::__::Err(e) => return $crate::__::Err(e),
114 }
115 }};
116}
117
118/// `?`-like macro for `Option`s.
119///
120/// # Example
121///
122/// ```rust
123/// use konst::try_opt;
124///
125/// const SOME: Option<u8> = sum_u8s(&[3, 5, 8, 13]);
126/// assert_eq!(SOME, Some(29));
127///
128/// const NONE: Option<u8> = sum_u8s(&[3, 5, 8, 13, 240]);
129/// assert_eq!(NONE, None);
130///
131/// const fn sum_u8s(mut nums: &[u8]) -> Option<u8> {
132/// let mut sum = 0_u8;
133/// while let [first, rem @ ..] = nums {
134/// nums = rem;
135/// # sum = try_opt!(checked_add(sum, *first));
136/// # /*
137/// sum = try_opt!(sum.checked_add(*first));
138/// # */
139/// }
140/// Some(sum)
141/// }
142///
143/// # const fn checked_add(l: u8, r: u8) -> Option<u8> {
144/// # let (res, overflowed) = l.overflowing_add(r);
145/// # if overflowed { None } else { Some(res) }
146/// # }
147/// ```
148///
149#[macro_export]
150macro_rules! try_opt {
151 ($opt:expr $(,)*) => {
152 match $opt {
153 $crate::__::Some(x) => x,
154 $crate::__::None => return $crate::__::None,
155 }
156 };
157}