Skip to main content

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