use crate::HostError;
use alloc::boxed::Box;
use core::fmt::{self, Display};
#[cfg(feature = "std")]
use std::error::Error as StdError;
#[derive(Debug)]
pub enum Trap {
Code(TrapCode),
Host(Box<dyn HostError>),
}
impl Trap {
#[inline]
pub fn host<U>(host_error: U) -> Self
where
U: HostError + Sized,
{
Self::Host(Box::new(host_error))
}
#[inline]
pub fn is_host(&self) -> bool {
matches!(self, Self::Host(_))
}
#[inline]
pub fn code(&self) -> Option<TrapCode> {
if let Self::Code(trap_code) = self {
return Some(*trap_code);
}
None
}
}
impl From<TrapCode> for Trap {
#[inline]
fn from(error: TrapCode) -> Self {
Self::Code(error)
}
}
impl<U> From<U> for Trap
where
U: HostError + Sized,
{
#[inline]
fn from(e: U) -> Self {
Trap::host(e)
}
}
impl Display for Trap {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Trap::Code(trap_code) => Display::fmt(trap_code, f),
Trap::Host(host_error) => Display::fmt(host_error, f),
}
}
}
#[cfg(feature = "std")]
impl StdError for Trap {
fn description(&self) -> &str {
self.code().map(|code| code.trap_message()).unwrap_or("")
}
}
#[derive(Debug, Copy, Clone)]
pub enum TrapCode {
Unreachable,
MemoryAccessOutOfBounds,
TableAccessOutOfBounds,
ElemUninitialized,
DivisionByZero,
IntegerOverflow,
InvalidConversionToInt,
StackOverflow,
UnexpectedSignature,
}
impl TrapCode {
pub fn trap_message(&self) -> &'static str {
match self {
TrapCode::Unreachable => "unreachable",
TrapCode::MemoryAccessOutOfBounds => "out of bounds memory access",
TrapCode::TableAccessOutOfBounds => "undefined element",
TrapCode::ElemUninitialized => "uninitialized element",
TrapCode::DivisionByZero => "integer divide by zero",
TrapCode::IntegerOverflow => "integer overflow",
TrapCode::InvalidConversionToInt => "invalid conversion to integer",
TrapCode::StackOverflow => "call stack exhausted",
TrapCode::UnexpectedSignature => "indirect call type mismatch",
}
}
}
impl Display for TrapCode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.trap_message())
}
}