Path: blob/main/crates/core/src/error/macros.rs
3071 views
//! Macro definitions and the private runtime functions used in their generated1//! code.23// Items used by macro-generated code.4pub use core::format_args;5pub use core::result::Result::Err;67use super::{Error, OutOfMemory};8use core::fmt::{self, write};9use std_alloc::string::String;1011/// Construct an [`Error`] via string formatting or another error.12///13/// Like `anyhow::format_err!` or `anyhow::anyhow!` but for14/// [`wasmtime::Error`](Error).15///16/// # String Formatting17///18/// When a string literal is the first argument, it is interpreted as a format19/// string template and the rest of the arguments are format arguments:20///21/// ```22/// # use wasmtime_internal_core::error as wasmtime;23/// use wasmtime::{format_err, Error};24///25/// let x = 42;26/// let error: Error = format_err!("x is {x}");27/// assert_eq!(error.to_string(), "x is 42");28///29/// let error: Error = format_err!("x / 2 is {}", x / 2);30/// assert_eq!(error.to_string(), "x / 2 is 21");31///32/// let error: Error = format_err!("x + 1 is {y}", y = x + 1);33/// assert_eq!(error.to_string(), "x + 1 is 43");34/// ```35///36/// # From Another Error37///38/// When a string literal is not the first argument, then it is treated as a39/// foreign error and is converted into an [`Error`]. The argument40/// must be of a type that can be passed to either [`Error::new`] or41/// [`Error::msg`].42///43/// ```44/// # fn _foo() {45/// #![cfg(feature = "std")]46/// # use wasmtime_internal_core::error as wasmtime;47/// use std::fmt;48/// use wasmtime::{format_err, 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 = format_err!(SomeOtherError(36));62/// assert!(error.is::<SomeOtherError>());63/// assert_eq!(error.to_string(), "some other error (code 36)");64/// # }65/// ```66///67/// # From an `anyhow::Error`68///69/// The `format_err!` macro can always convert an `anyhow::Error` into a70/// `wasmtime::Error`, but when the `"anyhow"` cargo feature is enabled the71/// resulting error will also return true for72/// [`error.is::<anyhow::Error>()`](Error::is) invocations.73///74/// ```75/// # fn _foo() {76/// #![cfg(feature = "anyhow")]77/// # use wasmtime_internal_core::error as wasmtime;78/// use wasmtime::format_err;79///80/// let anyhow_error: anyhow::Error = anyhow::anyhow!("aw crap");81/// let wasmtime_error: wasmtime::Error = format_err!(anyhow_error);82/// assert!(wasmtime_error.is::<anyhow::Error>());83/// # }84/// ```85#[macro_export]86macro_rules! format_err {87// Format-style invocation without explicit format arguments.88( $message:literal $(,)? ) => {89$crate::error::Error::from_format_args($crate::error::macros::format_args!($message))90};9192// Format-style invocation with explicit format arguments.93( $message:literal , $( $args:tt )* ) => {94$crate::error::Error::from_format_args($crate::error::macros::format_args!($message , $( $args )* ))95};9697// Do either `Error::new($error)` or `Error::msg($error)` depending on98// whether `$error` implements `core::error::Error` or not.99( $error:expr $(,)? ) => {{100use $crate::error::macros::ctor_specialization::*;101let error = $error;102(&&&error).wasmtime_error_choose_ctor().construct(error)103}};104}105106/// Identical to the [`format_err!`] macro.107///108/// This is provided for API compatibility with the `anyhow` crate, but you109/// should prefer using `format_err!` instead.110#[macro_export]111#[deprecated = "Use `format_err!(...)` instead"]112macro_rules! anyhow {113( $( $args:tt )* ) => {114$crate::error::format_err!( $( $args )* )115};116}117118/// Early exit from the current function with an error.119///120/// This helper is equivalent to `return Err(format_err!(...))`.121///122/// See the docs for the [`format_err!`] macro for details on123/// the kinds of errors that can be constructed.124///125/// Like `anyhow::bail!` but for [`wasmtime::Error`](Error).126///127/// # Example128///129/// ```130/// # use wasmtime_internal_core::error as wasmtime;131/// use wasmtime::{bail, Result};132///133/// fn error_on_none(option: Option<u32>) -> Result<u32> {134/// match option {135/// None => bail!("`error_on_none` got `None`!"),136/// Some(x) => Ok(x),137/// }138/// }139///140/// let x = error_on_none(Some(42)).unwrap();141/// assert_eq!(x, 42);142///143/// let error = error_on_none(None).unwrap_err();144/// assert_eq!(145/// error.to_string(),146/// "`error_on_none` got `None`!",147/// );148/// ```149#[macro_export]150macro_rules! bail {151( $($args:tt)* ) => {{152return $crate::error::macros::Err($crate::error::format_err!( $( $args )* ));153}};154}155156/// Ensure that a condition holds true, or else early exit from the current157/// function with an error.158///159/// `ensure!(condition, ...)` is equivalent to the following:160///161/// ```ignore162/// if !condition {163/// return Err(format_err!(...));164/// }165/// ```166///167/// Like `anyhow::ensure!` but for [`wasmtime::Error`](Error).168///169/// # Example170///171/// ```rust172/// # use wasmtime_internal_core::error as wasmtime;173/// use wasmtime::{ensure, Result};174///175/// fn checked_div(a: u32, b: u32) -> Result<u32> {176/// ensure!(b != 0, "cannot divide by zero: {a} / {b}");177/// Ok(a / b)178/// }179///180/// let x = checked_div(6, 2).unwrap();181/// assert_eq!(x, 3);182///183/// let error = checked_div(9, 0).unwrap_err();184/// assert_eq!(185/// error.to_string(),186/// "cannot divide by zero: 9 / 0",187/// );188/// ```189#[macro_export]190macro_rules! ensure {191( $condition:expr ) => {{192$crate::error::ensure!($condition, concat!("Condition failed: `", stringify!($condition), "`"))193}};194195( $condition:expr , $( $args:tt )* ) => {{196if $crate::error::macros::ensure::not($condition) {197$crate::error::bail!( $( $args )* );198}199}};200}201202/// We don't have specialization in stable Rust, so do a poor-person's203/// equivalent by hacking Rust's method name resolution and auto-deref. Given204/// that we have `n` versions of the "same" method, we do the following:205///206/// * We define `n` different traits, which each define the same trait method207/// name. The method need not have the same type across traits, but each must208/// type-check when chosen by method resolution at a particular call site.209///210/// * We implement each trait for an `i`-deep borrow of the type(s) we want to211/// specialize the `i`th implementation on, for example:212///213/// ```ignore214/// impl Specialization1 for &MyType { ... }215/// impl Specialization2 for &&OtherType { ... }216/// impl Specialization3 for &&&AnotherType { ... }217/// ```218///219/// * Call sites must have all specialization traits in scope and must borrow220/// the receiver `n` times before calling the method. Rust's method name221/// resolution will choose the method with the least number of references that222/// is well-typed. Therefore, specialization implementations for lower numbers223/// of borrows are preferred over those with higher numbers of borrows when224/// specializations overlap. For example, if both `<&&&T as225/// Specialization3>::method` and `<&T as Specialization1>::method` are226/// well-typed at the trait method call site `(&&&&&t).method()`, then227/// `Specialization1` will be prioritized over `Specialization3`.228///229/// In our specific case here of choosing an `Error` constructor, we have230/// three specializations:231///232/// 1. For `anyhow::Error`, we want to use the `Error::from_anyhow` constructor.233///234/// 2. When the type implements `core::error::Error`, we want to use the235/// `Error::new` constructor, which will preserve236/// `core::error::Error::source` chains.237///238/// 3. Otherwise, we want to use the `Error::msg` constructor.239///240/// The `*CtorTrait`s are our `n` specialization traits. Their241/// `wasmtime_error_choose_ctor` methods will return different types, each of242/// which is a dispatcher to their associated constructor. Those dispatchers243/// each have a constructor signature that is syntactically identical, but only244/// guaranteed to be well-typed based on the specialization that we did by245/// getting the dispatcher in the first place.246pub mod ctor_specialization {247use super::*;248249#[cfg(feature = "anyhow")]250pub use anyhow::*;251#[cfg(feature = "anyhow")]252mod anyhow {253use super::*;254255pub trait AnyhowCtorTrait {256#[inline]257fn wasmtime_error_choose_ctor(&self) -> AnyhowCtor {258AnyhowCtor259}260}261262impl AnyhowCtorTrait for &anyhow::Error {}263264pub struct AnyhowCtor;265266impl AnyhowCtor {267#[inline]268pub fn construct(&self, anyhow_error: ::anyhow::Error) -> Error {269Error::from_anyhow(anyhow_error)270}271}272}273274pub trait NewCtorTrait {275#[inline]276fn wasmtime_error_choose_ctor(&self) -> NewCtor {277NewCtor278}279}280281impl<E: core::error::Error + Send + Sync + 'static> NewCtorTrait for &&E {}282283pub struct NewCtor;284285impl NewCtor {286#[inline]287pub fn construct<E>(&self, error: E) -> Error288where289E: core::error::Error + Send + Sync + 'static,290{291Error::new(error)292}293}294295pub trait MsgCtorTrait {296#[inline]297fn wasmtime_error_choose_ctor(&self) -> MsgCtor {298MsgCtor299}300}301302impl<M: fmt::Debug + fmt::Display + Send + Sync + 'static> MsgCtorTrait for &&&M {}303304pub struct MsgCtor;305306impl MsgCtor {307#[inline]308pub fn construct<M>(&self, message: M) -> Error309where310M: fmt::Debug + fmt::Display + Send + Sync + 'static,311{312Error::msg(message)313}314}315}316317/// Runtime code for creating an `Error` from format arguments, handling OOM in318/// the process.319pub mod formatting {320use super::*;321322#[derive(Default)]323struct Formatter {324message: String,325oom: Option<OutOfMemory>,326}327328impl fmt::Write for Formatter {329fn write_str(&mut self, s: &str) -> fmt::Result {330match self.message.try_reserve(s.len()) {331Ok(()) => {332self.message.push_str(s);333Ok(())334}335Err(_) => {336self.oom = Some(OutOfMemory::new(self.message.len() + s.len()));337Err(fmt::Error)338}339}340}341}342343impl Error {344/// Construct an `Error` from format arguments.345///346/// Only for use by the `format_err!` macro.347#[doc(hidden)]348pub fn from_format_args(args: fmt::Arguments<'_>) -> Self {349if let Some(s) = args.as_str() {350return Self::msg(s);351}352353let mut f = Formatter::default();354match write(&mut f, args) {355Ok(()) => {356debug_assert!(f.oom.is_none());357Error::msg(f.message)358}359Err(fmt_error) => match f.oom {360Some(oom) => Error::new(oom),361None => Error::new(fmt_error),362},363}364}365}366}367368pub mod ensure {369/// Convenience trait to enable `ensure!(cond, ...)` to work when `cond` is of370/// type `&bool`, not just `bool`. Saves useless rewrite-to-`*cond` busywork and371/// matches `anyhow`'s behavior.372pub trait ToBool {373fn to_bool(self) -> bool;374}375376impl ToBool for bool {377#[inline]378fn to_bool(self) -> bool {379self380}381}382383impl ToBool for &bool {384#[inline]385fn to_bool(self) -> bool {386*self387}388}389390#[inline]391pub fn not(b: impl ToBool) -> bool {392!b.to_bool()393}394}395396397