af_core_macros/
fail.rs

1// Copyright © 2020 Alexandra Frydl
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7/// Returns an `Err` containing a new `fail::Error` from format args.
8#[macro_export]
9macro_rules! fail {
10  ($($args:tt)*) => {
11    return Err(fail::err!($($args)*))
12  };
13}
14
15/// Creates a new `fail::Error` from format args.
16#[macro_export]
17macro_rules! fail_err {
18  ($expr:expr) => {
19    fail::Error::new($expr)
20  };
21
22  ($($args:tt)*) => {
23    fail::Error::new(format!($($args)*))
24  };
25}
26
27/// Returns a closure for using [`Result::map_err`] to wrap an error in a
28/// `fail::Error`.
29#[macro_export]
30macro_rules! fail_wrap {
31  ($($args:tt)*) => {
32    |err| fail::err!($($args)*).with_cause(err)
33  };
34}
35
36/// Returns a `fail::Error` if a condition is `true`.
37///
38/// Some simple patterns have default error messages.
39#[macro_export]
40macro_rules! fail_when {
41  (let Err($err:ident) = $value:ident, $($args:tt)+) => {
42    let $value = match $value {
43      Ok($value) => $value,
44      Err($err) => fail!($($args)+),
45    };
46  };
47
48  (let $pattern:pat = $expr:expr) => {
49    if let $pattern = $expr {
50      fail!("Pattern match failed on line {} of `{}`.", line!(), file!());
51    }
52  };
53
54  (let $pattern:pat = $expr:expr, $($args:tt)+) => {
55    if let $pattern = $expr {
56      fail!($($args)+);
57    }
58  };
59
60  ($left:tt == $right:tt) => {
61    if $left == $right {
62      fail!(
63        "`{}` equals `{}` on line {} of `{}`.",
64        stringify!($left),
65        stringify!($right),
66        line!(),
67        file!(),
68      );
69    }
70  };
71
72  ($actual:tt != $expected:expr) => {{
73    let actual = $actual;
74    let expected = $expected;
75
76    if actual != expected {
77      fail!(
78        "Expected `{}` to equal `{:?}` on line {} of `{}`, but got `{:?}`.",
79        stringify!($actual),
80        expected,
81        line!(),
82        file!(),
83        actual
84      );
85    }
86  }};
87
88  ($actual:tt . $method:ident () != $expected:expr) => {{
89    let actual = $actual.$method();
90    let expected = $expected;
91
92    if actual != expected {
93      fail!(
94        "Expected `{}.{}()` to equal `{:?}` on line {} of `{}`, but got `{:?}`.",
95        stringify!($actual),
96        stringify!($method),
97        expected,
98        line!(),
99        file!(),
100        actual
101      );
102    }
103  }};
104
105  ($left:tt > $right:tt) => {
106    if $left > $right {
107      fail!(
108        "`{}` is greater than `{}` on line {} of `{}`.",
109        stringify!($left),
110        stringify!($right),
111        line!(),
112        file!(),
113      );
114    }
115  };
116
117  ($left:tt < $right:tt) => {
118    if $left < $right {
119      fail!(
120        "`{}` is less than `{}` on line {} of `{}`.",
121        stringify!($left),
122        stringify!($right),
123        line!(),
124        file!(),
125      );
126    }
127  };
128
129  ($left:tt >= $right:tt) => {
130    match $left.partial_cmp(&$right) {
131      Some(std::cmp::Ordering::Greater) => {
132        fail!(
133          "`{}` is greater than `{}` on line {} of `{}`.",
134          stringify!($left),
135          stringify!($right),
136          line!(),
137          file!(),
138        );
139      }
140
141      Some(std::cmp::Ordering::Equal) => {
142        fail!(
143          "`{}` is equal to `{}` on line {} of `{}`.",
144          stringify!($left),
145          stringify!($right),
146          line!(),
147          file!(),
148        );
149      }
150
151      _ => {}
152    }
153  };
154
155  ($left:tt <= $right:tt) => {
156    match $left.partial_cmp(&$right) {
157      Some(std::cmp::Ordering::Less) => {
158        fail!(
159          "`{}` is less than `{}` on line {} of `{}`.",
160          stringify!($left),
161          stringify!($right),
162          line!(),
163          file!(),
164        );
165      }
166
167      Some(std::cmp::Ordering::Equal) => {
168        fail!(
169          "`{}` is equal to `{}` on line {} of `{}`.",
170          stringify!($left),
171          stringify!($right),
172          line!(),
173          file!(),
174        );
175      }
176
177      _ => {}
178    }
179  };
180
181  ($value:tt.is_some()) => {
182    if $value.is_some() {
183      fail!("`{}` is `Some` on line {} of `{}`.", stringify!($value), line!(), file!());
184    }
185  };
186
187  ($value:ident.is_none()) => {
188    let $value = match $value {
189      Some($value) => $value,
190      None => fail!("`{}` is `None` on line {} of `{}`.", stringify!($value), line!(), file!()),
191    };
192  };
193
194  ($value:tt.is_none()) => {
195    if $value.is_none() {
196      fail!("`{}` is `None` on line {} of `{}`.", stringify!($value), line!(), file!());
197    }
198  };
199
200  ($value:ident.is_ok()) => {
201    let $value = match $value {
202      Ok(_) => fail!("`{}` is `Ok` on line {} of `{}`.", stringify!($value), line!(), file!()),
203      Err(err) => err,
204    };
205  };
206
207  ($value:ident.is_ok(), $($args:tt)+) => {
208    let $value = match $value {
209      Ok(_) => fail!($($args)+),
210      Err(err) => err,
211    };
212  };
213
214  ($value:tt.is_ok()) => {
215    if $value.is_ok() {
216      fail!("`{}` is `Ok` on line {} of `{}`.", stringify!($value), line!(), file!());
217    }
218  };
219
220  ($value:tt.is_empty()) => {
221    if $value.is_empty() {
222      fail!("`{}` is empty on line {} of `{}`.", stringify!($value), line!(), file!());
223    }
224  };
225
226  (!$value:tt.is_empty()) => {
227    if !$value.is_empty() {
228      fail!("`{}` is not empty on line {} of `{}`.", stringify!($value), line!(), file!());
229    }
230  };
231
232  (!$value:tt) => {
233    if !$value {
234      fail!("`{}` is `true` on line {} of `{}`.", stringify!($value), line!(), file!());
235    }
236  };
237
238  ($value:tt) => {
239    if $value {
240      fail!("`{}` is `true` on line {} of `{}`.", stringify!($value), line!(), file!());
241    }
242  };
243
244  ($condition:expr, $($args:tt)+) => {
245    if $condition {
246      fail!($($args)*);
247    }
248  };
249
250  ($($condition:tt)*) => {
251    if $($condition)* {
252      fail!("Failure on line {} of `{}`.", line!(), file!());
253    }
254  };
255}