1use super::errors::{
2 EnforcedLimitsError,
3 FuelError,
4 FuncError,
5 GlobalError,
6 InstantiationError,
7 LinkerError,
8 MemoryError,
9 TableError,
10};
11use crate::{
12 core::{HostError, TrapCode},
13 engine::{ResumableHostError, TranslationError},
14 module::ReadError,
15};
16use core::{fmt, fmt::Display};
17use std::{boxed::Box, string::String};
18use wasmparser::BinaryReaderError as WasmError;
19
20#[derive(Debug)]
22pub struct Error {
23 kind: Box<ErrorKind>,
25}
26
27#[test]
28fn error_size() {
29 use core::mem;
30 assert_eq!(mem::size_of::<Error>(), 8);
31}
32
33impl Error {
34 fn from_kind(kind: ErrorKind) -> Self {
36 Self {
37 kind: Box::new(kind),
38 }
39 }
40
41 #[inline]
43 #[cold]
44 pub fn new<T>(message: T) -> Self
45 where
46 T: Into<String>,
47 {
48 Self::from_kind(ErrorKind::Message(message.into().into_boxed_str()))
49 }
50
51 #[inline]
53 #[cold]
54 pub fn host<E>(host_error: E) -> Self
55 where
56 E: HostError,
57 {
58 Self::from_kind(ErrorKind::Host(Box::new(host_error)))
59 }
60
61 #[inline]
67 #[cold]
68 pub fn i32_exit(status: i32) -> Self {
69 Self::from_kind(ErrorKind::I32ExitStatus(status))
70 }
71
72 pub fn kind(&self) -> &ErrorKind {
74 &self.kind
75 }
76
77 pub fn as_trap_code(&self) -> Option<TrapCode> {
79 self.kind().as_trap_code()
80 }
81
82 pub fn i32_exit_status(&self) -> Option<i32> {
86 self.kind().as_i32_exit_status()
87 }
88
89 #[inline]
93 pub fn downcast_ref<T>(&self) -> Option<&T>
94 where
95 T: HostError,
96 {
97 self.kind
98 .as_host()
99 .and_then(<(dyn HostError + 'static)>::downcast_ref)
100 }
101
102 #[inline]
106 pub fn downcast_mut<T>(&mut self) -> Option<&mut T>
107 where
108 T: HostError,
109 {
110 self.kind
111 .as_host_mut()
112 .and_then(<(dyn HostError + 'static)>::downcast_mut)
113 }
114
115 #[inline]
119 pub fn downcast<T>(self) -> Option<T>
120 where
121 T: HostError,
122 {
123 self.kind
124 .into_host()
125 .and_then(|error| error.downcast().ok())
126 .map(|boxed| *boxed)
127 }
128
129 pub(crate) fn into_resumable(self) -> Result<ResumableHostError, Error> {
130 if matches!(&*self.kind, ErrorKind::ResumableHost(_)) {
131 let ErrorKind::ResumableHost(error) = *self.kind else {
132 unreachable!("asserted that host error is resumable")
133 };
134 return Ok(error);
135 }
136 Err(self)
137 }
138}
139
140#[cfg(feature = "std")]
141impl std::error::Error for Error {}
142
143impl Display for Error {
144 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
145 Display::fmt(&self.kind, f)
146 }
147}
148
149#[derive(Debug)]
151#[non_exhaustive]
152pub enum ErrorKind {
153 TrapCode(TrapCode),
155 Message(Box<str>),
157 I32ExitStatus(i32),
159 Host(Box<dyn HostError>),
161 #[doc(hidden)]
169 ResumableHost(ResumableHostError),
170 Global(GlobalError),
172 Memory(MemoryError),
174 Table(TableError),
176 Linker(LinkerError),
178 Instantiation(InstantiationError),
180 Fuel(FuelError),
182 Func(FuncError),
184 Read(ReadError),
186 Wasm(WasmError),
188 Translation(TranslationError),
190 Limits(EnforcedLimitsError),
192}
193
194impl ErrorKind {
195 pub fn as_trap_code(&self) -> Option<TrapCode> {
197 match self {
198 Self::TrapCode(trap_code) => Some(*trap_code),
199 _ => None,
200 }
201 }
202
203 pub fn as_i32_exit_status(&self) -> Option<i32> {
205 match self {
206 Self::I32ExitStatus(exit_status) => Some(*exit_status),
207 _ => None,
208 }
209 }
210
211 pub fn as_host(&self) -> Option<&dyn HostError> {
213 match self {
214 Self::Host(error) => Some(error.as_ref()),
215 _ => None,
216 }
217 }
218
219 pub fn as_host_mut(&mut self) -> Option<&mut dyn HostError> {
221 match self {
222 Self::Host(error) => Some(error.as_mut()),
223 _ => None,
224 }
225 }
226
227 pub fn into_host(self) -> Option<Box<dyn HostError>> {
229 match self {
230 Self::Host(error) => Some(error),
231 _ => None,
232 }
233 }
234}
235
236#[cfg(feature = "std")]
237impl std::error::Error for ErrorKind {}
238
239impl Display for ErrorKind {
240 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
241 match self {
242 Self::TrapCode(error) => Display::fmt(error, f),
243 Self::I32ExitStatus(status) => writeln!(f, "Exited with i32 exit status {status}"),
244 Self::Message(message) => Display::fmt(message, f),
245 Self::Host(error) => Display::fmt(error, f),
246 Self::Global(error) => Display::fmt(error, f),
247 Self::Memory(error) => Display::fmt(error, f),
248 Self::Table(error) => Display::fmt(error, f),
249 Self::Linker(error) => Display::fmt(error, f),
250 Self::Func(error) => Display::fmt(error, f),
251 Self::Instantiation(error) => Display::fmt(error, f),
252 Self::Fuel(error) => Display::fmt(error, f),
253 Self::Read(error) => Display::fmt(error, f),
254 Self::Wasm(error) => Display::fmt(error, f),
255 Self::Translation(error) => Display::fmt(error, f),
256 Self::Limits(error) => Display::fmt(error, f),
257 Self::ResumableHost(error) => Display::fmt(error, f),
258 }
259 }
260}
261
262macro_rules! impl_from {
263 ( $( impl From<$from:ident> for Error::$name:ident );* $(;)? ) => {
264 $(
265 impl From<$from> for Error {
266 #[inline]
267 #[cold]
268 fn from(error: $from) -> Self {
269 Self::from_kind(ErrorKind::$name(error))
270 }
271 }
272 )*
273 }
274}
275impl_from! {
276 impl From<TrapCode> for Error::TrapCode;
277 impl From<GlobalError> for Error::Global;
278 impl From<MemoryError> for Error::Memory;
279 impl From<TableError> for Error::Table;
280 impl From<LinkerError> for Error::Linker;
281 impl From<InstantiationError> for Error::Instantiation;
282 impl From<TranslationError> for Error::Translation;
283 impl From<WasmError> for Error::Wasm;
284 impl From<ReadError> for Error::Read;
285 impl From<FuelError> for Error::Fuel;
286 impl From<FuncError> for Error::Func;
287 impl From<EnforcedLimitsError> for Error::Limits;
288 impl From<ResumableHostError> for Error::ResumableHost;
289}
290
291#[derive(Copy, Clone)]
293pub enum EntityGrowError {
294 TrapCode(TrapCode),
296 InvalidGrow,
298}
299
300impl EntityGrowError {
301 pub const ERROR_CODE: u32 = u32::MAX;
304}
305
306impl From<TrapCode> for EntityGrowError {
307 fn from(trap_code: TrapCode) -> Self {
308 Self::TrapCode(trap_code)
309 }
310}