cranelift_codegen/ir/
trapcode.rs1use core::fmt::{self, Display, Formatter};
4use core::num::NonZeroU8;
5use core::str::FromStr;
6#[cfg(feature = "enable-serde")]
7use serde_derive::{Deserialize, Serialize};
8
9#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
13#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
14pub struct TrapCode(NonZeroU8);
15
16impl TrapCode {
17 const RESERVED: u8 = 5;
21 const RESERVED_START: u8 = u8::MAX - Self::RESERVED + 1;
22
23 const fn reserved(byte: u8) -> TrapCode {
25 if let Some(code) = byte.checked_add(Self::RESERVED_START) {
26 if let Some(nz) = NonZeroU8::new(code) {
27 return TrapCode(nz);
28 }
29 }
30 panic!("invalid reserved opcode")
31 }
32
33 pub const STACK_OVERFLOW: TrapCode = TrapCode::reserved(0);
35 pub const INTEGER_OVERFLOW: TrapCode = TrapCode::reserved(1);
37 pub const HEAP_OUT_OF_BOUNDS: TrapCode = TrapCode::reserved(2);
43
44 pub const INTEGER_DIVISION_BY_ZERO: TrapCode = TrapCode::reserved(3);
46
47 pub const BAD_CONVERSION_TO_INTEGER: TrapCode = TrapCode::reserved(4);
49
50 pub const fn user(code: u8) -> Option<TrapCode> {
55 if code >= Self::RESERVED_START {
56 return None;
57 }
58 match NonZeroU8::new(code) {
59 Some(nz) => Some(TrapCode(nz)),
60 None => None,
61 }
62 }
63
64 pub const fn unwrap_user(code: u8) -> TrapCode {
66 match TrapCode::user(code) {
67 Some(code) => code,
68 None => panic!("invalid user trap code"),
69 }
70 }
71
72 pub const fn as_raw(&self) -> NonZeroU8 {
74 self.0
75 }
76
77 pub const fn from_raw(byte: NonZeroU8) -> TrapCode {
80 TrapCode(byte)
81 }
82
83 pub const fn non_user_traps() -> &'static [TrapCode] {
85 &[
86 TrapCode::STACK_OVERFLOW,
87 TrapCode::HEAP_OUT_OF_BOUNDS,
88 TrapCode::INTEGER_OVERFLOW,
89 TrapCode::INTEGER_DIVISION_BY_ZERO,
90 TrapCode::BAD_CONVERSION_TO_INTEGER,
91 ]
92 }
93}
94
95impl Display for TrapCode {
96 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
97 let identifier = match *self {
98 Self::STACK_OVERFLOW => "stk_ovf",
99 Self::HEAP_OUT_OF_BOUNDS => "heap_oob",
100 Self::INTEGER_OVERFLOW => "int_ovf",
101 Self::INTEGER_DIVISION_BY_ZERO => "int_divz",
102 Self::BAD_CONVERSION_TO_INTEGER => "bad_toint",
103 TrapCode(x) => return write!(f, "user{x}"),
104 };
105 f.write_str(identifier)
106 }
107}
108
109impl FromStr for TrapCode {
110 type Err = ();
111
112 fn from_str(s: &str) -> Result<Self, Self::Err> {
113 match s {
114 "stk_ovf" => Ok(Self::STACK_OVERFLOW),
115 "heap_oob" => Ok(Self::HEAP_OUT_OF_BOUNDS),
116 "int_ovf" => Ok(Self::INTEGER_OVERFLOW),
117 "int_divz" => Ok(Self::INTEGER_DIVISION_BY_ZERO),
118 "bad_toint" => Ok(Self::BAD_CONVERSION_TO_INTEGER),
119 _ if s.starts_with("user") => {
120 let num = s[4..].parse().map_err(|_| ())?;
121 TrapCode::user(num).ok_or(())
122 }
123 _ => Err(()),
124 }
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131 use alloc::string::ToString;
132
133 #[test]
134 fn display() {
135 for r in TrapCode::non_user_traps() {
136 let tc = *r;
137 assert_eq!(tc.to_string().parse(), Ok(tc));
138 }
139 assert_eq!("bogus".parse::<TrapCode>(), Err(()));
140
141 assert_eq!(TrapCode::unwrap_user(17).to_string(), "user17");
142 assert_eq!("user22".parse(), Ok(TrapCode::unwrap_user(22)));
143 assert_eq!("user".parse::<TrapCode>(), Err(()));
144 assert_eq!("user-1".parse::<TrapCode>(), Err(()));
145 assert_eq!("users".parse::<TrapCode>(), Err(()));
146 }
147}