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