use backtrace::Backtrace;
use std::error::Error;
use std::fmt;
use wasmer_types::TrapCode;
use crate::{StoreObjects, VMExceptionRef};
#[derive(Debug)]
pub enum Trap {
User(Box<dyn Error + Send + Sync>),
Wasm {
pc: usize,
backtrace: Backtrace,
signal_trap: Option<TrapCode>,
},
Lib {
trap_code: TrapCode,
backtrace: Backtrace,
},
OOM {
backtrace: Backtrace,
},
UncaughtException {
exnref: VMExceptionRef,
backtrace: Backtrace,
},
}
fn _assert_trap_is_sync_and_send(t: &Trap) -> (&dyn Sync, &dyn Send) {
(t, t)
}
impl Trap {
pub fn user(err: Box<dyn Error + Send + Sync>) -> Self {
Self::User(err)
}
pub fn wasm(pc: usize, backtrace: Backtrace, signal_trap: Option<TrapCode>) -> Self {
Self::Wasm {
pc,
backtrace,
signal_trap,
}
}
pub fn to_trap(self) -> Option<TrapCode> {
unimplemented!()
}
pub fn lib(trap_code: TrapCode) -> Self {
let backtrace = Backtrace::new_unresolved();
Self::Lib {
trap_code,
backtrace,
}
}
pub fn oom() -> Self {
let backtrace = Backtrace::new_unresolved();
Self::OOM { backtrace }
}
pub fn uncaught_exception(exnref: VMExceptionRef, ctx: &StoreObjects) -> Self {
Self::UncaughtException {
backtrace: exnref.0.get(ctx).backtrace().clone(),
exnref,
}
}
pub fn downcast<T: Error + 'static>(self) -> Result<T, Self> {
match self {
Self::User(err) if err.is::<T>() => Ok(*err.downcast::<T>().unwrap()),
_ => Err(self),
}
}
pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
match &self {
Self::User(err) if err.is::<T>() => err.downcast_ref::<T>(),
_ => None,
}
}
pub fn is<T: Error + 'static>(&self) -> bool {
match self {
Self::User(err) => err.is::<T>(),
_ => false,
}
}
pub fn is_exception(&self) -> bool {
matches!(self, Self::UncaughtException { .. })
}
pub fn to_exception_ref(&self) -> Option<VMExceptionRef> {
match self {
Self::UncaughtException { exnref, .. } => Some(exnref.clone()),
_ => None,
}
}
}
impl std::error::Error for Trap {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match &self {
Self::User(err) => Some(&**err),
_ => None,
}
}
}
impl fmt::Display for Trap {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::User(e) => write!(f, "{e}"),
Self::Lib { .. } => write!(f, "lib"),
Self::Wasm { .. } => write!(f, "wasm"),
Self::OOM { .. } => write!(f, "Wasmer VM out of memory"),
Self::UncaughtException { .. } => write!(f, "Uncaught wasm exception"),
}
}
}