1use core::fmt::{self, Display, Formatter};
7use core::str::FromStr;
8use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
9#[cfg(feature = "enable-serde")]
10use serde::{Deserialize, Serialize};
11use thiserror::Error;
12
13#[derive(
17 Clone, Copy, PartialEq, Eq, Debug, Hash, Error, RkyvSerialize, RkyvDeserialize, Archive,
18)]
19#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
20#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
21#[rkyv(derive(Debug), compare(PartialEq))]
22#[repr(u32)]
23pub enum TrapCode {
24 StackOverflow = 0,
29
30 HeapAccessOutOfBounds = 1,
36
37 HeapMisaligned = 2,
39
40 TableAccessOutOfBounds = 3,
42
43 IndirectCallToNull = 4,
45
46 BadSignature = 5,
48
49 IntegerOverflow = 6,
51
52 IntegerDivisionByZero = 7,
54
55 BadConversionToInteger = 8,
57
58 UnreachableCodeReached = 9,
60
61 UnalignedAtomic = 10,
63}
64
65impl TrapCode {
66 pub fn message(&self) -> &str {
68 match self {
69 Self::StackOverflow => "call stack exhausted",
70 Self::HeapAccessOutOfBounds => "out of bounds memory access",
71 Self::HeapMisaligned => "misaligned heap",
72 Self::TableAccessOutOfBounds => "undefined element: out of bounds table access",
73 Self::IndirectCallToNull => "uninitialized element",
74 Self::BadSignature => "indirect call type mismatch",
75 Self::IntegerOverflow => "integer overflow",
76 Self::IntegerDivisionByZero => "integer divide by zero",
77 Self::BadConversionToInteger => "invalid conversion to integer",
78 Self::UnreachableCodeReached => "unreachable",
79 Self::UnalignedAtomic => "unaligned atomic access",
80 }
81 }
82}
83
84impl Display for TrapCode {
85 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
86 let identifier = match *self {
87 Self::StackOverflow => "stk_ovf",
88 Self::HeapAccessOutOfBounds => "heap_get_oob",
89 Self::HeapMisaligned => "heap_misaligned",
90 Self::TableAccessOutOfBounds => "table_get_oob",
91 Self::IndirectCallToNull => "icall_null",
92 Self::BadSignature => "bad_sig",
93 Self::IntegerOverflow => "int_ovf",
94 Self::IntegerDivisionByZero => "int_divz",
95 Self::BadConversionToInteger => "bad_toint",
96 Self::UnreachableCodeReached => "unreachable",
97 Self::UnalignedAtomic => "unalign_atom",
98 };
99 f.write_str(identifier)
100 }
101}
102
103impl FromStr for TrapCode {
104 type Err = ();
105
106 fn from_str(s: &str) -> Result<Self, Self::Err> {
107 match s {
108 "stk_ovf" => Ok(Self::StackOverflow),
109 "heap_get_oob" => Ok(Self::HeapAccessOutOfBounds),
110 "heap_misaligned" => Ok(Self::HeapMisaligned),
111 "table_get_oob" => Ok(Self::TableAccessOutOfBounds),
112 "icall_null" => Ok(Self::IndirectCallToNull),
113 "bad_sig" => Ok(Self::BadSignature),
114 "int_ovf" => Ok(Self::IntegerOverflow),
115 "int_divz" => Ok(Self::IntegerDivisionByZero),
116 "bad_toint" => Ok(Self::BadConversionToInteger),
117 "unreachable" => Ok(Self::UnreachableCodeReached),
118 "unalign_atom" => Ok(Self::UnalignedAtomic),
119 _ => Err(()),
120 }
121 }
122}
123
124#[derive(Debug)]
128pub enum OnCalledAction {
129 InvokeAgain,
131 Finish,
133 Trap(Box<dyn std::error::Error + Send + Sync>),
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140
141 const CODES: [TrapCode; 11] = [
143 TrapCode::StackOverflow,
144 TrapCode::HeapAccessOutOfBounds,
145 TrapCode::HeapMisaligned,
146 TrapCode::TableAccessOutOfBounds,
147 TrapCode::IndirectCallToNull,
148 TrapCode::BadSignature,
149 TrapCode::IntegerOverflow,
150 TrapCode::IntegerDivisionByZero,
151 TrapCode::BadConversionToInteger,
152 TrapCode::UnreachableCodeReached,
153 TrapCode::UnalignedAtomic,
154 ];
155
156 #[test]
157 fn display() {
158 for r in &CODES {
159 let tc = *r;
160 assert_eq!(tc.to_string().parse(), Ok(tc));
161 }
162 assert_eq!("bogus".parse::<TrapCode>(), Err(()));
163
164 assert_eq!("user".parse::<TrapCode>(), Err(()));
167 assert_eq!("user-1".parse::<TrapCode>(), Err(()));
168 assert_eq!("users".parse::<TrapCode>(), Err(()));
169 }
170}