//! Macro definitions and the private runtime functions used in their generated //! code. // Items used by macro-generated code. pub use core::format_args; pub use core::result::Result::Err; use super::{Error, OutOfMemory}; use core::fmt::{self, write}; use std_alloc::string::String; /// Construct an [`Error`] via string formatting or another error. /// /// Like `anyhow::format_err!` or `anyhow::anyhow!` but for /// [`wasmtime::Error`](Error). /// /// # String Formatting /// /// When a string literal is the first argument, it is interpreted as a format /// string template and the rest of the arguments are format arguments: /// /// ``` /// # use wasmtime_internal_core::error as wasmtime; /// use wasmtime::{format_err, Error}; /// /// let x = 42; /// let error: Error = format_err!("x is {x}"); /// assert_eq!(error.to_string(), "x is 42"); /// /// let error: Error = format_err!("x / 2 is {}", x / 2); /// assert_eq!(error.to_string(), "x / 2 is 21"); /// /// let error: Error = format_err!("x + 1 is {y}", y = x + 1); /// assert_eq!(error.to_string(), "x + 1 is 43"); /// ``` /// /// # From Another Error /// /// When a string literal is not the first argument, then it is treated as a /// foreign error and is converted into an [`Error`]. The argument /// must be of a type that can be passed to either [`Error::new`] or /// [`Error::msg`]. /// /// ``` /// # fn _foo() { /// #![cfg(feature = "std")] /// # use wasmtime_internal_core::error as wasmtime; /// use std::fmt; /// use wasmtime::{format_err, Error}; /// /// #[derive(Debug)] /// struct SomeOtherError(u32); /// /// impl fmt::Display for SomeOtherError { /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// write!(f, "some other error (code {})", self.0) /// } /// } /// /// impl std::error::Error for SomeOtherError {} /// /// let error: Error = format_err!(SomeOtherError(36)); /// assert!(error.is::()); /// assert_eq!(error.to_string(), "some other error (code 36)"); /// # } /// ``` /// /// # From an `anyhow::Error` /// /// The `format_err!` macro can always convert an `anyhow::Error` into a /// `wasmtime::Error`, but when the `"anyhow"` cargo feature is enabled the /// resulting error will also return true for /// [`error.is::()`](Error::is) invocations. /// /// ``` /// # fn _foo() { /// #![cfg(feature = "anyhow")] /// # use wasmtime_internal_core::error as wasmtime; /// use wasmtime::format_err; /// /// let anyhow_error: anyhow::Error = anyhow::anyhow!("aw crap"); /// let wasmtime_error: wasmtime::Error = format_err!(anyhow_error); /// assert!(wasmtime_error.is::()); /// # } /// ``` #[macro_export] macro_rules! format_err { // Format-style invocation without explicit format arguments. ( $message:literal $(,)? ) => { $crate::error::Error::from_format_args($crate::error::macros::format_args!($message)) }; // Format-style invocation with explicit format arguments. ( $message:literal , $( $args:tt )* ) => { $crate::error::Error::from_format_args($crate::error::macros::format_args!($message , $( $args )* )) }; // Do either `Error::new($error)` or `Error::msg($error)` depending on // whether `$error` implements `core::error::Error` or not. ( $error:expr $(,)? ) => {{ use $crate::error::macros::ctor_specialization::*; let error = $error; (&&&error).wasmtime_error_choose_ctor().construct(error) }}; } /// Identical to the [`format_err!`] macro. /// /// This is provided for API compatibility with the `anyhow` crate, but you /// should prefer using `format_err!` instead. #[macro_export] #[deprecated = "Use `format_err!(...)` instead"] macro_rules! anyhow { ( $( $args:tt )* ) => { $crate::error::format_err!( $( $args )* ) }; } /// Early exit from the current function with an error. /// /// This helper is equivalent to `return Err(format_err!(...))`. /// /// See the docs for the [`format_err!`] macro for details on /// the kinds of errors that can be constructed. /// /// Like `anyhow::bail!` but for [`wasmtime::Error`](Error). /// /// # Example /// /// ``` /// # use wasmtime_internal_core::error as wasmtime; /// use wasmtime::{bail, Result}; /// /// fn error_on_none(option: Option) -> Result { /// match option { /// None => bail!("`error_on_none` got `None`!"), /// Some(x) => Ok(x), /// } /// } /// /// let x = error_on_none(Some(42)).unwrap(); /// assert_eq!(x, 42); /// /// let error = error_on_none(None).unwrap_err(); /// assert_eq!( /// error.to_string(), /// "`error_on_none` got `None`!", /// ); /// ``` #[macro_export] macro_rules! bail { ( $($args:tt)* ) => {{ return $crate::error::macros::Err($crate::error::format_err!( $( $args )* )); }}; } /// Ensure that a condition holds true, or else early exit from the current /// function with an error. /// /// `ensure!(condition, ...)` is equivalent to the following: /// /// ```ignore /// if !condition { /// return Err(format_err!(...)); /// } /// ``` /// /// Like `anyhow::ensure!` but for [`wasmtime::Error`](Error). /// /// # Example /// /// ```rust /// # use wasmtime_internal_core::error as wasmtime; /// use wasmtime::{ensure, Result}; /// /// fn checked_div(a: u32, b: u32) -> Result { /// ensure!(b != 0, "cannot divide by zero: {a} / {b}"); /// Ok(a / b) /// } /// /// let x = checked_div(6, 2).unwrap(); /// assert_eq!(x, 3); /// /// let error = checked_div(9, 0).unwrap_err(); /// assert_eq!( /// error.to_string(), /// "cannot divide by zero: 9 / 0", /// ); /// ``` #[macro_export] macro_rules! ensure { ( $condition:expr ) => {{ $crate::error::ensure!($condition, concat!("Condition failed: `", stringify!($condition), "`")) }}; ( $condition:expr , $( $args:tt )* ) => {{ if $crate::error::macros::ensure::not($condition) { $crate::error::bail!( $( $args )* ); } }}; } /// We don't have specialization in stable Rust, so do a poor-person's /// equivalent by hacking Rust's method name resolution and auto-deref. Given /// that we have `n` versions of the "same" method, we do the following: /// /// * We define `n` different traits, which each define the same trait method /// name. The method need not have the same type across traits, but each must /// type-check when chosen by method resolution at a particular call site. /// /// * We implement each trait for an `i`-deep borrow of the type(s) we want to /// specialize the `i`th implementation on, for example: /// /// ```ignore /// impl Specialization1 for &MyType { ... } /// impl Specialization2 for &&OtherType { ... } /// impl Specialization3 for &&&AnotherType { ... } /// ``` /// /// * Call sites must have all specialization traits in scope and must borrow /// the receiver `n` times before calling the method. Rust's method name /// resolution will choose the method with the least number of references that /// is well-typed. Therefore, specialization implementations for lower numbers /// of borrows are preferred over those with higher numbers of borrows when /// specializations overlap. For example, if both `<&&&T as /// Specialization3>::method` and `<&T as Specialization1>::method` are /// well-typed at the trait method call site `(&&&&&t).method()`, then /// `Specialization1` will be prioritized over `Specialization3`. /// /// In our specific case here of choosing an `Error` constructor, we have /// three specializations: /// /// 1. For `anyhow::Error`, we want to use the `Error::from_anyhow` constructor. /// /// 2. When the type implements `core::error::Error`, we want to use the /// `Error::new` constructor, which will preserve /// `core::error::Error::source` chains. /// /// 3. Otherwise, we want to use the `Error::msg` constructor. /// /// The `*CtorTrait`s are our `n` specialization traits. Their /// `wasmtime_error_choose_ctor` methods will return different types, each of /// which is a dispatcher to their associated constructor. Those dispatchers /// each have a constructor signature that is syntactically identical, but only /// guaranteed to be well-typed based on the specialization that we did by /// getting the dispatcher in the first place. pub mod ctor_specialization { use super::*; #[cfg(feature = "anyhow")] pub use anyhow::*; #[cfg(feature = "anyhow")] mod anyhow { use super::*; pub trait AnyhowCtorTrait { #[inline] fn wasmtime_error_choose_ctor(&self) -> AnyhowCtor { AnyhowCtor } } impl AnyhowCtorTrait for &anyhow::Error {} pub struct AnyhowCtor; impl AnyhowCtor { #[inline] pub fn construct(&self, anyhow_error: ::anyhow::Error) -> Error { Error::from_anyhow(anyhow_error) } } } pub trait NewCtorTrait { #[inline] fn wasmtime_error_choose_ctor(&self) -> NewCtor { NewCtor } } impl NewCtorTrait for &&E {} pub struct NewCtor; impl NewCtor { #[inline] pub fn construct(&self, error: E) -> Error where E: core::error::Error + Send + Sync + 'static, { Error::new(error) } } pub trait MsgCtorTrait { #[inline] fn wasmtime_error_choose_ctor(&self) -> MsgCtor { MsgCtor } } impl MsgCtorTrait for &&&M {} pub struct MsgCtor; impl MsgCtor { #[inline] pub fn construct(&self, message: M) -> Error where M: fmt::Debug + fmt::Display + Send + Sync + 'static, { Error::msg(message) } } } /// Runtime code for creating an `Error` from format arguments, handling OOM in /// the process. pub mod formatting { use super::*; #[derive(Default)] struct Formatter { message: String, oom: Option, } impl fmt::Write for Formatter { fn write_str(&mut self, s: &str) -> fmt::Result { match self.message.try_reserve(s.len()) { Ok(()) => { self.message.push_str(s); Ok(()) } Err(_) => { self.oom = Some(OutOfMemory::new(self.message.len() + s.len())); Err(fmt::Error) } } } } impl Error { /// Construct an `Error` from format arguments. /// /// Only for use by the `format_err!` macro. #[doc(hidden)] pub fn from_format_args(args: fmt::Arguments<'_>) -> Self { if let Some(s) = args.as_str() { return Self::msg(s); } let mut f = Formatter::default(); match write(&mut f, args) { Ok(()) => { debug_assert!(f.oom.is_none()); Error::msg(f.message) } Err(fmt_error) => match f.oom { Some(oom) => Error::new(oom), None => Error::new(fmt_error), }, } } } } pub mod ensure { /// Convenience trait to enable `ensure!(cond, ...)` to work when `cond` is of /// type `&bool`, not just `bool`. Saves useless rewrite-to-`*cond` busywork and /// matches `anyhow`'s behavior. pub trait ToBool { fn to_bool(self) -> bool; } impl ToBool for bool { #[inline] fn to_bool(self) -> bool { self } } impl ToBool for &bool { #[inline] fn to_bool(self) -> bool { *self } } #[inline] pub fn not(b: impl ToBool) -> bool { !b.to_bool() } }