1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
//! Error and result types.
use core::fmt;
use fizzyx_sys as sys;
/// A specialized [`Result`](core::result::Result) type for `fizzyx` operations.
pub type Result<T> = core::result::Result<T, Error>;
/// An error returned by the `fizzyx` API.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Error {
/// The Wasm binary is malformed and could not be parsed.
Malformed(String),
/// The Wasm module is well-formed but failed validation.
Invalid(String),
/// Instantiation of the module failed (e.g. an unresolved or mistyped import).
Instantiation(String),
/// A function or export with the given name was not found.
ExportNotFound(String),
/// Execution of a function trapped.
Trap,
/// The number of provided arguments or results did not match the signature.
ArityMismatch {
/// The number of values the signature expects.
expected: usize,
/// The number of values that were provided.
provided: usize,
},
/// A provided value's type did not match the expected type.
TypeMismatch {
/// The position of the mismatched value.
index: usize,
/// A human-readable description of the expected type.
expected: &'static str,
/// A human-readable description of the provided type.
found: &'static str,
},
/// A value or global used a type outside the WebAssembly 1.0 numeric types.
UnsupportedType,
/// An attempt was made to write to an immutable global.
GlobalImmutable,
/// A memory access was out of bounds.
MemoryOutOfBounds {
/// The byte offset of the attempted access.
offset: usize,
/// The length in bytes of the attempted access.
length: usize,
/// The current size of the memory in bytes.
size: usize,
},
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Malformed(msg) => write!(f, "malformed Wasm module: {msg}"),
Self::Invalid(msg) => write!(f, "invalid Wasm module: {msg}"),
Self::Instantiation(msg) => write!(f, "failed to instantiate module: {msg}"),
Self::ExportNotFound(name) => write!(f, "export `{name}` not found"),
Self::Trap => write!(f, "execution trapped"),
Self::ArityMismatch { expected, provided } => write!(
f,
"arity mismatch: expected {expected} values, got {provided}"
),
Self::TypeMismatch {
index,
expected,
found,
} => write!(
f,
"type mismatch at index {index}: expected {expected}, got {found}"
),
Self::UnsupportedType => {
write!(f, "unsupported value type (only i32, i64, f32, f64 exist)")
}
Self::GlobalImmutable => write!(f, "cannot write to an immutable global"),
Self::MemoryOutOfBounds {
offset,
length,
size,
} => write!(
f,
"memory access out of bounds: [{offset}, {offset}+{length}) exceeds size {size}"
),
}
}
}
impl std::error::Error for Error {}
/// Reads the message out of a [`sys::FizzyError`] as a Rust [`String`].
pub(crate) fn error_message(error: &sys::FizzyError) -> String {
// SAFETY: Fizzy always writes a NUL-terminated string into `message`.
let cstr = unsafe { core::ffi::CStr::from_ptr(error.message.as_ptr()) };
cstr.to_string_lossy().into_owned()
}