1 /// Return early with an error.
2 ///
3 /// This macro is equivalent to `return Err(From::from($err))`.
4 ///
5 /// # Example
6 ///
7 /// ```
8 /// # use miette::{bail, Result};
9 /// #
10 /// # fn has_permission(user: usize, resource: usize) -> bool {
11 /// #     true
12 /// # }
13 /// #
14 /// # fn main() -> Result<()> {
15 /// #     let user = 0;
16 /// #     let resource = 0;
17 /// #
18 /// if !has_permission(user, resource) {
19 #[cfg_attr(
20     not(feature = "no-format-args-capture"),
21     doc = r#"     bail!("permission denied for accessing {resource}");"#
22 )]
23 #[cfg_attr(
24     feature = "no-format-args-capture",
25     doc = r#"     bail!("permission denied for accessing {}", resource);"#
26 )]
27 /// }
28 /// #     Ok(())
29 /// # }
30 /// ```
31 ///
32 /// ```
33 /// # use miette::{bail, Result};
34 /// # use thiserror::Error;
35 /// #
36 /// # const MAX_DEPTH: usize = 1;
37 /// #
38 /// #[derive(Error, Debug)]
39 /// enum ScienceError {
40 ///     #[error("recursion limit exceeded")]
41 ///     RecursionLimitExceeded,
42 ///     # #[error("...")]
43 ///     # More = (stringify! {
44 ///     ...
45 ///     # }, 1).1,
46 /// }
47 ///
48 /// # fn main() -> Result<()> {
49 /// #     let depth = 0;
50 /// #     let err: &'static dyn std::error::Error = &ScienceError::RecursionLimitExceeded;
51 /// #
52 /// if depth > MAX_DEPTH {
53 ///     bail!(ScienceError::RecursionLimitExceeded);
54 /// }
55 /// #     Ok(())
56 /// # }
57 /// ```
58 ///
59 /// ```
60 /// use miette::{bail, Result, Severity};
61 ///
62 /// fn divide(x: f64, y: f64) -> Result<f64> {
63 ///     if y.abs() < 1e-3 {
64 ///         bail!(
65 ///             severity = Severity::Warning,
66 #[cfg_attr(
67     not(feature = "no-format-args-capture"),
68     doc = r#"             "dividing by value ({y}) close to 0""#
69 )]
70 #[cfg_attr(
71     feature = "no-format-args-capture",
72     doc = r#"             "dividing by value ({}) close to 0", y"#
73 )]
74 ///         );
75 ///     }
76 ///     Ok(x / y)
77 /// }
78 /// ```
79 #[macro_export]
80 macro_rules! bail {
81     ($($key:ident = $value:expr,)* $fmt:literal $($arg:tt)*) => {
82         return $crate::private::Err(
83             $crate::miette!($($key = $value,)* $fmt $($arg)*)
84         );
85     };
86     ($err:expr $(,)?) => {
87         return $crate::private::Err($crate::miette!($err));
88     };
89 }
90 
91 /// Return early with an error if a condition is not satisfied.
92 ///
93 /// This macro is equivalent to `if !$cond { return Err(From::from($err)); }`.
94 ///
95 /// Analogously to `assert!`, `ensure!` takes a condition and exits the function
96 /// if the condition fails. Unlike `assert!`, `ensure!` returns an `Error`
97 /// rather than panicking.
98 ///
99 /// # Example
100 ///
101 /// ```
102 /// # use miette::{ensure, Result};
103 /// #
104 /// # fn main() -> Result<()> {
105 /// #     let user = 0;
106 /// #
107 /// ensure!(user == 0, "only user 0 is allowed");
108 /// #     Ok(())
109 /// # }
110 /// ```
111 ///
112 /// ```
113 /// # use miette::{ensure, Result};
114 /// # use thiserror::Error;
115 /// #
116 /// # const MAX_DEPTH: usize = 1;
117 /// #
118 /// #[derive(Error, Debug)]
119 /// enum ScienceError {
120 ///     #[error("recursion limit exceeded")]
121 ///     RecursionLimitExceeded,
122 ///     # #[error("...")]
123 ///     # More = (stringify! {
124 ///     ...
125 ///     # }, 1).1,
126 /// }
127 ///
128 /// # fn main() -> Result<()> {
129 /// #     let depth = 0;
130 /// #
131 /// ensure!(depth <= MAX_DEPTH, ScienceError::RecursionLimitExceeded);
132 /// #     Ok(())
133 /// # }
134 /// ```
135 ///
136 /// ```
137 /// use miette::{ensure, Result, Severity};
138 ///
139 /// fn divide(x: f64, y: f64) -> Result<f64> {
140 ///     ensure!(
141 ///         y.abs() >= 1e-3,
142 ///         severity = Severity::Warning,
143 #[cfg_attr(
144     not(feature = "no-format-args-capture"),
145     doc = r#"             "dividing by value ({y}) close to 0""#
146 )]
147 #[cfg_attr(
148     feature = "no-format-args-capture",
149     doc = r#"             "dividing by value ({}) close to 0", y"#
150 )]
151 ///     );
152 ///     Ok(x / y)
153 /// }
154 /// ```
155 #[macro_export]
156 macro_rules! ensure {
157     ($cond:expr, $($key:ident = $value:expr,)* $fmt:literal $($arg:tt)*) => {
158         if !$cond {
159             return $crate::private::Err(
160                 $crate::miette!($($key = $value,)* $fmt $($arg)*)
161             );
162         }
163     };
164     ($cond:expr, $err:expr $(,)?) => {
165         if !$cond {
166             return $crate::private::Err($crate::miette!($err));
167         }
168     };
169 }
170 
171 /// Construct an ad-hoc [`Report`].
172 ///
173 /// # Examples
174 ///
175 /// With string literal and interpolation:
176 /// ```
177 /// # use miette::miette;
178 /// let x = 1;
179 /// let y = 2;
180 #[cfg_attr(
181     not(feature = "no-format-args-capture"),
182     doc = r#"let report = miette!("{x} + {} = {z}", y, z = x + y);"#
183 )]
184 #[cfg_attr(
185     feature = "no-format-args-capture",
186     doc = r#"let report = miette!("{} + {} = {z}", x, y, z = x + y);"#
187 )]
188 ///
189 /// assert_eq!(report.to_string().as_str(), "1 + 2 = 3");
190 ///
191 /// let z = x + y;
192 #[cfg_attr(
193     not(feature = "no-format-args-capture"),
194     doc = r#"let report = miette!("{x} + {y} = {z}");"#
195 )]
196 #[cfg_attr(
197     feature = "no-format-args-capture",
198     doc = r#"let report = miette!("{} + {} = {}", x, y, z);"#
199 )]
200 /// assert_eq!(report.to_string().as_str(), "1 + 2 = 3");
201 /// ```
202 ///
203 /// With [`diagnostic!`]-like arguments:
204 /// ```
205 /// use miette::{miette, LabeledSpan, Severity};
206 ///
207 /// let source = "(2 + 2".to_string();
208 /// let report = miette!(
209 ///     // Those fields are optional
210 ///     severity = Severity::Error,
211 ///     code = "expected::rparen",
212 ///     help = "always close your parens",
213 ///     labels = vec![LabeledSpan::at_offset(6, "here")],
214 ///     url = "https://example.com",
215 ///     // Rest of the arguments are passed to `format!`
216 ///     // to form diagnostic message
217 ///     "expected closing ')'"
218 /// )
219 /// .with_source_code(source);
220 /// ```
221 ///
222 /// ## `anyhow`/`eyre` Users
223 ///
224 /// You can just replace `use`s of the `anyhow!`/`eyre!` macros with `miette!`.
225 ///
226 /// [`diagnostic!`]: crate::diagnostic!
227 /// [`Report`]: crate::Report
228 #[macro_export]
229 macro_rules! miette {
230     ($($key:ident = $value:expr,)* $fmt:literal $($arg:tt)*) => {
231         $crate::Report::from(
232             $crate::diagnostic!($($key = $value,)* $fmt $($arg)*)
233         )
234     };
235     ($err:expr $(,)?) => ({
236         use $crate::private::kind::*;
237         let error = $err;
238         (&error).miette_kind().new(error)
239     });
240 }
241 
242 /// Construct a [`MietteDiagnostic`] in more user-friendly way.
243 ///
244 /// # Examples
245 /// ```
246 /// use miette::{diagnostic, LabeledSpan, Severity};
247 ///
248 /// let source = "(2 + 2".to_string();
249 /// let diag = diagnostic!(
250 ///     // Those fields are optional
251 ///     severity = Severity::Error,
252 ///     code = "expected::rparen",
253 ///     help = "always close your parens",
254 ///     labels = vec![LabeledSpan::at_offset(6, "here")],
255 ///     url = "https://example.com",
256 ///     // Rest of the arguments are passed to `format!`
257 ///     // to form diagnostic message
258 ///     "expected closing ')'",
259 /// );
260 /// ```
261 /// Diagnostic without any fields:
262 /// ```
263 /// # use miette::diagnostic;
264 /// let x = 1;
265 /// let y = 2;
266 ///
267 #[cfg_attr(
268     not(feature = "no-format-args-capture"),
269     doc = r#" let diag = diagnostic!("{x} + {} = {z}", y, z = x + y);"#
270 )]
271 #[cfg_attr(
272     feature = "no-format-args-capture",
273     doc = r#" let diag = diagnostic!("{} + {} = {z}", x, y, z = x + y);"#
274 )]
275 /// assert_eq!(diag.message, "1 + 2 = 3");
276 ///
277 /// let z = x + y;
278 #[cfg_attr(
279     not(feature = "no-format-args-capture"),
280     doc = r#"let diag = diagnostic!("{x} + {y} = {z}");"#
281 )]
282 #[cfg_attr(
283     feature = "no-format-args-capture",
284     doc = r#"let diag = diagnostic!("{} + {} = {}", x, y, z);"#
285 )]
286 /// assert_eq!(diag.message, "1 + 2 = 3");
287 /// ```
288 ///
289 /// [`MietteDiagnostic`]: crate::MietteDiagnostic
290 #[macro_export]
291 macro_rules! diagnostic {
292     ($fmt:literal $($arg:tt)*) => {{
293         $crate::MietteDiagnostic::new(format!($fmt $($arg)*))
294     }};
295     ($($key:ident = $value:expr,)+ $fmt:literal $($arg:tt)*) => {{
296         let mut diag = $crate::MietteDiagnostic::new(format!($fmt $($arg)*));
297         $(diag.$key = Some($value.into());)*
298         diag
299     }};
300 }
301