Skip to main content

wasmtime_internal_error/
macros.rs

1//! Macro definitions and the private runtime functions used in their generated
2//! code.
3
4// Items used by macro-generated code.
5pub use core::format_args;
6pub use core::result::Result::Err;
7
8use super::{Error, OutOfMemory};
9use alloc::string::String;
10use core::fmt::{self, write};
11
12/// Construct an [`Error`](crate::Error) via string formatting or another error.
13///
14/// Like `anyhow::anyhow!` but for [`wasmtime::Error`][crate::Error].
15///
16/// # String Formatting
17///
18/// When a string literal is the first argument, it is interpreted as a format
19/// string template and the rest of the arguments are format arguments:
20///
21/// ```
22/// # use wasmtime_internal_error as wasmtime;
23/// use wasmtime::{anyhow, Error};
24///
25/// let x = 42;
26/// let error: Error = anyhow!("x is {x}");
27/// assert_eq!(error.to_string(), "x is 42");
28///
29/// let error: Error = anyhow!("x / 2 is {}", x / 2);
30/// assert_eq!(error.to_string(), "x / 2 is 21");
31///
32/// let error: Error = anyhow!("x + 1 is {y}", y = x + 1);
33/// assert_eq!(error.to_string(), "x + 1 is 43");
34/// ```
35///
36/// # From Another Error
37///
38/// When a string literal is not the first argument, then it is treated as a
39/// foreign error and is converted into an [`Error`][crate::Error]. The argument
40/// must be of a type that can be passed to either
41/// [`Error::new`][crate::Error::new] or [`Error::msg`][crate::Error::msg]:
42///
43/// ```
44/// # fn _foo() {
45/// #![cfg(feature = "std")]
46/// # use wasmtime_internal_error as wasmtime;
47/// use std::fmt;
48/// use wasmtime::{anyhow, Error};
49///
50/// #[derive(Debug)]
51/// struct SomeOtherError(u32);
52///
53/// impl fmt::Display for SomeOtherError {
54///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55///         write!(f, "some other error (code {})", self.0)
56///     }
57/// }
58///
59/// impl std::error::Error for SomeOtherError {}
60///
61/// let error: Error = anyhow!(SomeOtherError(36));
62/// assert!(error.is::<SomeOtherError>());
63/// assert_eq!(error.to_string(), "some other error (code 36)");
64/// # }
65/// ```
66#[macro_export]
67macro_rules! anyhow {
68    // Format-style invocation without explicit format arguments.
69    ( $message:literal $(,)? ) => {
70        $crate::Error::from_format_args($crate::macros::format_args!($message))
71    };
72
73    // Format-style invocation with explicit format arguments.
74    ( $message:literal , $( $args:tt )* ) => {
75        $crate::Error::from_format_args($crate::macros::format_args!($message , $( $args )* ))
76    };
77
78    // Do either `Error::new($error)` or `Error::msg($error)` depending on
79    // whether `$error` implements `core::error::Error` or not.
80    ( $error:expr $(,)? ) => {{
81        use $crate::macros::ctor_specialization::*;
82        let error = $error;
83        (&&error).wasmtime_error_choose_ctor().construct(error)
84    }};
85}
86
87/// Identical to the [`anyhow!`][crate::anyhow] macro.
88///
89/// Provided for compatibility.
90#[macro_export]
91macro_rules! format_err {
92    ( $( $args:tt )* ) => {
93        anyhow!( $( $args )* )
94    };
95}
96
97/// Early exit from the current function with an error.
98///
99/// This helper is equivalent to `return Err(anyhow!(...))`.
100///
101/// See the docs for the [`anyhow!`][crate::anyhow] macro for details on the
102/// kinds of errors that can be constructed.
103///
104/// Like `anyhow::bail!` but for [`wasmtime::Error`][crate::Error].
105///
106/// # Example
107///
108/// ```
109/// # use wasmtime_internal_error as wasmtime;
110/// use wasmtime::{bail, Result};
111///
112/// fn error_on_none(option: Option<u32>) -> Result<u32> {
113///     match option {
114///         None => bail!("`error_on_none` got `None`!"),
115///         Some(x) => Ok(x),
116///     }
117/// }
118///
119/// let x = error_on_none(Some(42)).unwrap();
120/// assert_eq!(x, 42);
121///
122/// let error = error_on_none(None).unwrap_err();
123/// assert_eq!(
124///     error.to_string(),
125///     "`error_on_none` got `None`!",
126/// );
127/// ```
128#[macro_export]
129macro_rules! bail {
130    ( $($args:tt)* ) => {{
131        return $crate::macros::Err($crate::anyhow!( $( $args )* ));
132    }};
133}
134
135/// Ensure that a condition holds true, or else early exit from the current
136/// function with an error.
137///
138/// `ensure!(condition, ...)` is equivalent to the following:
139///
140/// ```ignore
141/// if !condition {
142///     return Err(anyhow!(...));
143/// }
144/// ```
145///
146/// Like `anyhow::ensure!` but for [`wasmtime::Error`][crate::Error].
147///
148/// # Example
149///
150/// ```rust
151/// # use wasmtime_internal_error as wasmtime;
152/// use wasmtime::{ensure, Result};
153///
154/// fn checked_div(a: u32, b: u32) -> Result<u32> {
155///     ensure!(b != 0, "cannot divide by zero: {a} / {b}");
156///     Ok(a / b)
157/// }
158///
159/// let x = checked_div(6, 2).unwrap();
160/// assert_eq!(x, 3);
161///
162/// let error = checked_div(9, 0).unwrap_err();
163/// assert_eq!(
164///     error.to_string(),
165///     "cannot divide by zero: 9 / 0",
166/// );
167/// ```
168#[macro_export]
169macro_rules! ensure {
170    ( $condition:expr , $( $args:tt )* ) => {{
171        if $crate::macros::ensure::not($condition) {
172            $crate::bail!( $( $args )* );
173        }
174    }};
175}
176
177/// We don't have specialization in stable Rust, so do a poor-person's
178/// equivalent by hacking Rust's method name resolution and auto-deref. Given
179/// that we have `n` versions of the "same" method, we do the following:
180///
181/// * We define `n` different traits, which each define the same trait method
182///   name. The method need not have the same type across traits, but each must
183///   type-check when chosen by method resolution at a particular call site.
184///
185/// * We implement each trait for an `i`-deep borrow of the type(s) we want to
186///   specialize the `i`th implementation on, for example:
187///
188///   ```ignore
189///   impl Specialization1 for &MyType { ... }
190///   impl Specialization2 for &&OtherType { ... }
191///   impl Specialization3 for &&&AnotherType { ... }
192///   ```
193///
194/// * Call sites must have all specialization traits in scope and must borrow
195///   the receiver `n` times before calling the method. Rust's method name
196///   resolution will choose the method with the least number of references that
197///   is well-typed. Therefore, specialization implementations for lower numbers
198///   of borrows are preferred over those with higher numbers of borrows when
199///   specializations overlap. For example, if both `<&&&T as
200///   Specialization3>::method` and `<&T as Specialization1>::method` are
201///   well-typed at the trait method call site `(&&&&&t).method()`, then
202///   `Specialization1` will be prioritized over `Specialization3`.
203///
204/// In our specific case here of choosing an `Error` constructor, we only have
205/// two specializations:
206///
207/// 1. When the type implements `core::error::Error`, we want to use the
208///    `Error::new` constructor, which will preserve
209///    `core::error::Error::source` chains.
210///
211/// 2. Otherwise, we want to use the `Error::msg` constructor.
212///
213/// The `*CtorTrait`s are our `n` specialization traits. Their
214/// `wasmtime_error_choose_ctor` methods will return different types, each of
215/// which is a dispatcher to their associated constructor. Those dispatchers
216/// each have a constructor signature that is syntactically identical, but only
217/// guaranteed to be well-typed based on the specialization that we did by
218/// getting the dispatcher in the first place.
219pub mod ctor_specialization {
220    use super::*;
221
222    pub trait NewCtorTrait {
223        #[inline]
224        fn wasmtime_error_choose_ctor(&self) -> NewCtor {
225            NewCtor
226        }
227    }
228
229    impl<E: core::error::Error + Send + Sync + 'static> NewCtorTrait for &E {}
230
231    pub struct NewCtor;
232
233    impl NewCtor {
234        #[inline]
235        pub fn construct<E>(&self, error: E) -> Error
236        where
237            E: core::error::Error + Send + Sync + 'static,
238        {
239            Error::new(error)
240        }
241    }
242
243    pub trait MsgCtorTrait {
244        #[inline]
245        fn wasmtime_error_choose_ctor(&self) -> MsgCtor {
246            MsgCtor
247        }
248    }
249
250    impl<M: fmt::Debug + fmt::Display + Send + Sync + 'static> MsgCtorTrait for &&M {}
251
252    pub struct MsgCtor;
253
254    impl MsgCtor {
255        #[inline]
256        pub fn construct<M>(&self, message: M) -> Error
257        where
258            M: fmt::Debug + fmt::Display + Send + Sync + 'static,
259        {
260            Error::msg(message)
261        }
262    }
263}
264
265/// Runtime code for creating an `Error` from format arguments, handling OOM in
266/// the process.
267pub mod formatting {
268    use super::*;
269
270    #[derive(Default)]
271    struct Formatter {
272        message: String,
273        oom: Option<OutOfMemory>,
274    }
275
276    impl fmt::Write for Formatter {
277        fn write_str(&mut self, s: &str) -> fmt::Result {
278            match self.message.try_reserve(s.len()) {
279                Ok(()) => {
280                    self.message.push_str(s);
281                    Ok(())
282                }
283                Err(_) => {
284                    self.oom = Some(OutOfMemory::new());
285                    Err(fmt::Error)
286                }
287            }
288        }
289    }
290
291    impl Error {
292        /// Construct an `Error` from format arguments.
293        ///
294        /// Only for use by the `anyhow!` macro.
295        #[doc(hidden)]
296        pub fn from_format_args(args: fmt::Arguments<'_>) -> Self {
297            if let Some(s) = args.as_str() {
298                return Self::msg(s);
299            }
300
301            let mut f = Formatter::default();
302            match write(&mut f, args) {
303                Ok(()) => {
304                    debug_assert!(f.oom.is_none());
305                    Error::msg(f.message)
306                }
307                Err(fmt_error) => match f.oom {
308                    Some(oom) => Error::new(oom),
309                    None => Error::new(fmt_error),
310                },
311            }
312        }
313    }
314}
315
316pub mod ensure {
317    /// Convenience trait to enable `ensure!(cond, ...)` to work when `cond` is of
318    /// type `&bool`, not just `bool`. Saves useless rewrite-to-`*cond` busywork and
319    /// matches `anyhow`'s behavior.
320    pub trait ToBool {
321        fn to_bool(self) -> bool;
322    }
323
324    impl ToBool for bool {
325        #[inline]
326        fn to_bool(self) -> bool {
327            self
328        }
329    }
330
331    impl ToBool for &bool {
332        #[inline]
333        fn to_bool(self) -> bool {
334            *self
335        }
336    }
337
338    #[inline]
339    pub fn not(b: impl ToBool) -> bool {
340        !b.to_bool()
341    }
342}