use core::fmt::{self, Display, Formatter};
use core::str::FromStr;
use serde::{Deserialize, Serialize};
use thiserror::Error;
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize, Deserialize, Error)]
#[repr(u32)]
pub enum TrapCode {
StackOverflow = 0,
HeapSetterOutOfBounds = 1,
HeapAccessOutOfBounds = 2,
HeapMisaligned = 3,
TableSetterOutOfBounds = 4,
TableAccessOutOfBounds = 5,
OutOfBounds = 6,
IndirectCallToNull = 7,
BadSignature = 8,
IntegerOverflow = 9,
IntegerDivisionByZero = 10,
BadConversionToInteger = 11,
UnreachableCodeReached = 12,
Interrupt = 13,
UnalignedAtomic = 14,
VMOutOfMemory = 15,
}
impl TrapCode {
pub fn message(&self) -> &str {
match self {
Self::StackOverflow => "call stack exhausted",
Self::HeapSetterOutOfBounds => "memory out of bounds: data segment does not fit",
Self::HeapAccessOutOfBounds => "out of bounds memory access",
Self::HeapMisaligned => "misaligned heap",
Self::TableSetterOutOfBounds => "table out of bounds: elements segment does not fit",
Self::TableAccessOutOfBounds => "undefined element: out of bounds table access",
Self::OutOfBounds => "out of bounds",
Self::IndirectCallToNull => "uninitialized element",
Self::BadSignature => "indirect call type mismatch",
Self::IntegerOverflow => "integer overflow",
Self::IntegerDivisionByZero => "integer divide by zero",
Self::BadConversionToInteger => "invalid conversion to integer",
Self::UnreachableCodeReached => "unreachable",
Self::Interrupt => "interrupt",
Self::UnalignedAtomic => "unaligned atomic access",
Self::VMOutOfMemory => "out of memory",
}
}
}
impl Display for TrapCode {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
let identifier = match *self {
Self::StackOverflow => "stk_ovf",
Self::HeapSetterOutOfBounds => "heap_set_oob",
Self::HeapAccessOutOfBounds => "heap_get_oob",
Self::HeapMisaligned => "heap_misaligned",
Self::TableSetterOutOfBounds => "table_set_oob",
Self::TableAccessOutOfBounds => "table_get_oob",
Self::OutOfBounds => "oob",
Self::IndirectCallToNull => "icall_null",
Self::BadSignature => "bad_sig",
Self::IntegerOverflow => "int_ovf",
Self::IntegerDivisionByZero => "int_divz",
Self::BadConversionToInteger => "bad_toint",
Self::UnreachableCodeReached => "unreachable",
Self::Interrupt => "interrupt",
Self::UnalignedAtomic => "unalign_atom",
Self::VMOutOfMemory => "oom",
};
f.write_str(identifier)
}
}
impl FromStr for TrapCode {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
use self::TrapCode::*;
match s {
"stk_ovf" => Ok(StackOverflow),
"heap_set_oob" => Ok(HeapSetterOutOfBounds),
"heap_get_oob" => Ok(HeapAccessOutOfBounds),
"heap_misaligned" => Ok(HeapMisaligned),
"table_set_oob" => Ok(TableSetterOutOfBounds),
"table_get_oob" => Ok(TableAccessOutOfBounds),
"oob" => Ok(OutOfBounds),
"icall_null" => Ok(IndirectCallToNull),
"bad_sig" => Ok(BadSignature),
"int_ovf" => Ok(IntegerOverflow),
"int_divz" => Ok(IntegerDivisionByZero),
"bad_toint" => Ok(BadConversionToInteger),
"unreachable" => Ok(UnreachableCodeReached),
"interrupt" => Ok(Interrupt),
"unalign_atom" => Ok(UnalignedAtomic),
"oom" => Ok(VMOutOfMemory),
_ => Err(()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
const CODES: [TrapCode; 15] = [
TrapCode::StackOverflow,
TrapCode::HeapSetterOutOfBounds,
TrapCode::HeapAccessOutOfBounds,
TrapCode::HeapMisaligned,
TrapCode::TableSetterOutOfBounds,
TrapCode::TableAccessOutOfBounds,
TrapCode::OutOfBounds,
TrapCode::IndirectCallToNull,
TrapCode::BadSignature,
TrapCode::IntegerOverflow,
TrapCode::IntegerDivisionByZero,
TrapCode::BadConversionToInteger,
TrapCode::UnreachableCodeReached,
TrapCode::Interrupt,
TrapCode::UnalignedAtomic,
];
#[test]
fn display() {
for r in &CODES {
let tc = *r;
assert_eq!(tc.to_string().parse(), Ok(tc));
}
assert_eq!("bogus".parse::<TrapCode>(), Err(()));
assert_eq!("user".parse::<TrapCode>(), Err(()));
assert_eq!("user-1".parse::<TrapCode>(), Err(()));
assert_eq!("users".parse::<TrapCode>(), Err(()));
}
}