1use super::errors::{
2 EnforcedLimitsError,
3 FuelError,
4 FuncError,
5 GlobalError,
6 InstantiationError,
7 IrError,
8 LinkerError,
9 MemoryError,
10 TableError,
11};
12use crate::{
13 core::{HostError, TrapCode},
14 engine::{ResumableHostError, TranslationError},
15 module::ReadError,
16};
17use alloc::{boxed::Box, string::String};
18use core::{fmt, fmt::Display};
19use wasmparser::BinaryReaderError as WasmError;
20
21#[cfg(feature = "wat")]
22use wat::Error as WatError;
23
24#[derive(Debug)]
26pub struct Error {
27 kind: Box<ErrorKind>,
29}
30
31#[test]
32fn error_size() {
33 use core::mem;
34 assert_eq!(mem::size_of::<Error>(), 8);
35}
36
37impl Error {
38 fn from_kind(kind: ErrorKind) -> Self {
40 Self {
41 kind: Box::new(kind),
42 }
43 }
44
45 #[inline]
47 #[cold]
48 pub fn new<T>(message: T) -> Self
49 where
50 T: Into<String>,
51 {
52 Self::from_kind(ErrorKind::Message(message.into().into_boxed_str()))
53 }
54
55 #[inline]
57 #[cold]
58 pub fn host<E>(host_error: E) -> Self
59 where
60 E: HostError,
61 {
62 Self::from_kind(ErrorKind::Host(Box::new(host_error)))
63 }
64
65 #[inline]
71 #[cold]
72 pub fn i32_exit(status: i32) -> Self {
73 Self::from_kind(ErrorKind::I32ExitStatus(status))
74 }
75
76 pub fn kind(&self) -> &ErrorKind {
78 &self.kind
79 }
80
81 pub fn as_trap_code(&self) -> Option<TrapCode> {
83 self.kind().as_trap_code()
84 }
85
86 pub fn i32_exit_status(&self) -> Option<i32> {
90 self.kind().as_i32_exit_status()
91 }
92
93 #[inline]
97 pub fn downcast_ref<T>(&self) -> Option<&T>
98 where
99 T: HostError,
100 {
101 self.kind
102 .as_host()
103 .and_then(<(dyn HostError + 'static)>::downcast_ref)
104 }
105
106 #[inline]
110 pub fn downcast_mut<T>(&mut self) -> Option<&mut T>
111 where
112 T: HostError,
113 {
114 self.kind
115 .as_host_mut()
116 .and_then(<(dyn HostError + 'static)>::downcast_mut)
117 }
118
119 #[inline]
123 pub fn downcast<T>(self) -> Option<T>
124 where
125 T: HostError,
126 {
127 self.kind
128 .into_host()
129 .and_then(|error| error.downcast().ok())
130 .map(|boxed| *boxed)
131 }
132
133 pub(crate) fn into_resumable(self) -> Result<ResumableHostError, Error> {
134 if matches!(&*self.kind, ErrorKind::ResumableHost(_)) {
135 let ErrorKind::ResumableHost(error) = *self.kind else {
136 unreachable!("asserted that host error is resumable")
137 };
138 return Ok(error);
139 }
140 Err(self)
141 }
142}
143
144#[cfg(feature = "std")]
145impl std::error::Error for Error {}
146
147impl Display for Error {
148 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
149 Display::fmt(&self.kind, f)
150 }
151}
152
153#[derive(Debug)]
155#[non_exhaustive]
156pub enum ErrorKind {
157 TrapCode(TrapCode),
159 Message(Box<str>),
161 I32ExitStatus(i32),
163 Host(Box<dyn HostError>),
165 #[doc(hidden)]
173 ResumableHost(ResumableHostError),
174 Global(GlobalError),
176 Memory(MemoryError),
178 Table(TableError),
180 Linker(LinkerError),
182 Instantiation(InstantiationError),
184 Fuel(FuelError),
186 Func(FuncError),
188 Read(ReadError),
190 Wasm(WasmError),
192 Translation(TranslationError),
194 Limits(EnforcedLimitsError),
196 Ir(IrError),
198 #[cfg(feature = "wat")]
200 Wat(WatError),
201}
202
203impl ErrorKind {
204 pub fn as_trap_code(&self) -> Option<TrapCode> {
206 match self {
207 Self::TrapCode(trap_code) => Some(*trap_code),
208 _ => None,
209 }
210 }
211
212 pub fn as_i32_exit_status(&self) -> Option<i32> {
214 match self {
215 Self::I32ExitStatus(exit_status) => Some(*exit_status),
216 _ => None,
217 }
218 }
219
220 pub fn as_host(&self) -> Option<&dyn HostError> {
222 match self {
223 Self::Host(error) => Some(error.as_ref()),
224 _ => None,
225 }
226 }
227
228 pub fn as_host_mut(&mut self) -> Option<&mut dyn HostError> {
230 match self {
231 Self::Host(error) => Some(error.as_mut()),
232 _ => None,
233 }
234 }
235
236 pub fn into_host(self) -> Option<Box<dyn HostError>> {
238 match self {
239 Self::Host(error) => Some(error),
240 _ => None,
241 }
242 }
243}
244
245#[cfg(feature = "std")]
246impl std::error::Error for ErrorKind {}
247
248impl Display for ErrorKind {
249 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
250 match self {
251 Self::TrapCode(error) => Display::fmt(error, f),
252 Self::I32ExitStatus(status) => writeln!(f, "Exited with i32 exit status {status}"),
253 Self::Message(message) => Display::fmt(message, f),
254 Self::Host(error) => Display::fmt(error, f),
255 Self::Global(error) => Display::fmt(error, f),
256 Self::Memory(error) => Display::fmt(error, f),
257 Self::Table(error) => Display::fmt(error, f),
258 Self::Linker(error) => Display::fmt(error, f),
259 Self::Func(error) => Display::fmt(error, f),
260 Self::Instantiation(error) => Display::fmt(error, f),
261 Self::Fuel(error) => Display::fmt(error, f),
262 Self::Read(error) => Display::fmt(error, f),
263 Self::Wasm(error) => Display::fmt(error, f),
264 Self::Translation(error) => Display::fmt(error, f),
265 Self::Limits(error) => Display::fmt(error, f),
266 Self::ResumableHost(error) => Display::fmt(error, f),
267 Self::Ir(error) => Display::fmt(error, f),
268 #[cfg(feature = "wat")]
269 Self::Wat(error) => Display::fmt(error, f),
270 }
271 }
272}
273
274macro_rules! impl_from {
275 ( $( impl From<$from:ident> for Error::$name:ident );* $(;)? ) => {
276 $(
277 impl From<$from> for Error {
278 #[inline]
279 #[cold]
280 fn from(error: $from) -> Self {
281 Self::from_kind(ErrorKind::$name(error))
282 }
283 }
284 )*
285 }
286}
287impl_from! {
288 impl From<TrapCode> for Error::TrapCode;
289 impl From<GlobalError> for Error::Global;
290 impl From<MemoryError> for Error::Memory;
291 impl From<TableError> for Error::Table;
292 impl From<LinkerError> for Error::Linker;
293 impl From<InstantiationError> for Error::Instantiation;
294 impl From<TranslationError> for Error::Translation;
295 impl From<WasmError> for Error::Wasm;
296 impl From<ReadError> for Error::Read;
297 impl From<FuelError> for Error::Fuel;
298 impl From<FuncError> for Error::Func;
299 impl From<EnforcedLimitsError> for Error::Limits;
300 impl From<ResumableHostError> for Error::ResumableHost;
301 impl From<IrError> for Error::Ir;
302}
303#[cfg(feature = "wat")]
304impl_from! {
305 impl From<WatError> for Error::Wat;
306}
307
308#[derive(Copy, Clone)]
310pub enum EntityGrowError {
311 TrapCode(TrapCode),
313 InvalidGrow,
315}
316
317impl EntityGrowError {
318 pub const ERROR_CODE_32: u64 = u32::MAX as u64;
322
323 pub const ERROR_CODE_64: u64 = u64::MAX;
327}
328
329impl From<TrapCode> for EntityGrowError {
330 fn from(trap_code: TrapCode) -> Self {
331 Self::TrapCode(trap_code)
332 }
333}