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