Skip to main content

wasmi_core/
host_error.rs

1use alloc::boxed::Box;
2use core::{
3    any::{type_name, Any},
4    fmt::{Debug, Display},
5};
6
7/// Trait that allows the host to return custom error.
8///
9/// It should be useful for representing custom traps,
10/// troubles at instantiation time or other host specific conditions.
11///
12/// Types that implement this trait can automatically be converted to `wasmi::Error` and `wasmi::Trap`
13/// and will be represented as a boxed `HostError`. You can then use the various methods on `wasmi::Error`
14/// to get your custom error type back
15///
16/// # Examples
17///
18/// ```rust
19/// use std::fmt;
20/// use wasmi_core::{Trap, HostError};
21///
22/// #[derive(Debug, Copy, Clone)]
23/// struct MyError {
24///     code: u32,
25/// }
26///
27/// impl fmt::Display for MyError {
28///     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
29///         write!(f, "MyError, code={}", self.code)
30///     }
31/// }
32///
33/// impl HostError for MyError { }
34///
35/// fn failable_fn() -> Result<(), Trap> {
36///     let my_error = MyError { code: 42 };
37///     // Note how you can just convert your errors to `wasmi::Error`
38///     Err(my_error.into())
39/// }
40///
41/// // Get a reference to the concrete error
42/// match failable_fn() {
43///     Err(trap) => {
44///         let my_error: &MyError = trap.downcast_ref().unwrap();
45///         assert_eq!(my_error.code, 42);
46///     }
47///     _ => panic!(),
48/// }
49///
50/// // get the concrete error itself
51/// match failable_fn() {
52///     Err(err) => {
53///         let my_error = match err.downcast_ref::<MyError>() {
54///             Some(host_error) => host_error.clone(),
55///             None => panic!("expected host error `MyError` but found: {}", err),
56///         };
57///         assert_eq!(my_error.code, 42);
58///     }
59///     _ => panic!(),
60/// }
61/// ```
62pub trait HostError: 'static + Display + Debug + Any + Send + Sync {}
63
64impl dyn HostError {
65    /// Returns `true` if `self` is of type `T`.
66    pub fn is<T: HostError>(&self) -> bool {
67        (self as &dyn Any).is::<T>()
68    }
69
70    /// Downcasts the [`HostError`] into a shared reference to a `T` if possible.
71    ///
72    /// Returns `None` otherwise.
73    #[inline]
74    pub fn downcast_ref<T: HostError>(&self) -> Option<&T> {
75        (self as &dyn Any).downcast_ref::<T>()
76    }
77
78    /// Downcasts the [`HostError`] into an exclusive reference to a `T` if possible.
79    ///
80    /// Returns `None` otherwise.
81    #[inline]
82    pub fn downcast_mut<T: HostError>(&mut self) -> Option<&mut T> {
83        (self as &mut dyn Any).downcast_mut::<T>()
84    }
85
86    /// Consumes `self` to downcast the [`HostError`] into the `T` if possible.
87    ///
88    /// # Errors
89    ///
90    /// If `self` cannot be downcast to `T`.
91    #[inline]
92    pub fn downcast<T: HostError>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
93        if self.is::<T>() {
94            let Ok(value) = (self as Box<dyn Any>).downcast::<T>() else {
95                unreachable!(
96                    "failed to downcast `HostError` to T (= {})",
97                    type_name::<T>()
98                );
99            };
100            Ok(value)
101        } else {
102            Err(self)
103        }
104    }
105}