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}