diff --git a/crates/core/src/trap.rs b/crates/core/src/trap.rs index e4b69cd15d..e0390b001d 100644 --- a/crates/core/src/trap.rs +++ b/crates/core/src/trap.rs @@ -1,5 +1,5 @@ use crate::HostError; -use alloc::{boxed::Box, string::String, sync::Arc}; +use alloc::{boxed::Box, string::String}; use core::fmt::{self, Display}; #[cfg(feature = "std")] @@ -11,10 +11,10 @@ use std::error::Error as StdError; /// which immediately aborts execution. /// Traps cannot be handled by WebAssembly code, but are reported to the /// host embedder. -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct Trap { /// The cloneable reason of a [`Trap`]. - reason: Arc, + reason: Box, } #[test] @@ -62,6 +62,24 @@ impl TrapReason { None } + /// Returns an exclusive reference to the [`HostError`] if any. + #[inline] + pub fn as_host_mut(&mut self) -> Option<&mut dyn HostError> { + if let Self::Host(host_error) = self { + return Some(&mut **host_error); + } + None + } + + /// Consumes `self` to return the [`HostError`] if any. + #[inline] + pub fn into_host(self) -> Option> { + if let Self::Host(host_error) = self { + return Some(host_error); + } + None + } + /// Returns the [`TrapCode`] traps originating from Wasm execution. #[inline] pub fn trap_code(&self) -> Option { @@ -76,7 +94,7 @@ impl Trap { /// Create a new [`Trap`] from the [`TrapReason`]. fn with_reason(reason: TrapReason) -> Self { Self { - reason: Arc::new(reason), + reason: Box::new(reason), } } @@ -102,6 +120,33 @@ impl Trap { .and_then(<(dyn HostError + 'static)>::downcast_ref) } + /// Downcasts the [`Trap`] into the `T: HostError` if possible. + /// + /// Returns `None` otherwise. + #[inline] + pub fn downcast_mut(&mut self) -> Option<&mut T> + where + T: HostError, + { + self.reason + .as_host_mut() + .and_then(<(dyn HostError + 'static)>::downcast_mut) + } + + /// Consumes `self` to downcast the [`Trap`] into the `T: HostError` if possible. + /// + /// Returns `None` otherwise. + #[inline] + pub fn downcast(self) -> Option + where + T: HostError, + { + self.reason + .into_host() + .and_then(|error| error.downcast().ok()) + .map(|boxed| *boxed) + } + /// Creates a new `Trap` representing an explicit program exit with a classic `i32` /// exit status value. #[cold] // see Trap::new