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
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
//! Error related functionality of wasm3.
use core::cmp;
use core::fmt;

use crate::utils::cstr_to_str;

/// Result alias that uses [`Error`].
pub type Result<T> = core::result::Result<T, Error>;
/// Result alias that uses [`Trap`].
pub type TrappedResult<T> = core::result::Result<T, Trap>;

/// A wasm trap.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Trap {
    /// Out of bounds memory access
    OutOfBoundsMemoryAccess,
    /// Division by zero
    DivisionByZero,
    /// Integer overflow
    IntegerOverflow,
    /// Integer conversion
    IntegerConversion,
    /// Indirect call type mismatch
    IndirectCallTypeMismatch,
    /// Table index out of range
    TableIndexOutOfRange,
    /// Exit
    Exit,
    /// Abort
    Abort,
    /// Unreachable
    Unreachable,
    /// Stack overflow
    StackOverflow,
}

impl Trap {
    #[doc(hidden)]
    pub fn as_ptr(self) -> ffi::M3Result {
        unsafe {
            match self {
                Trap::OutOfBoundsMemoryAccess => ffi::m3Err_trapOutOfBoundsMemoryAccess,
                Trap::DivisionByZero => ffi::m3Err_trapDivisionByZero,
                Trap::IntegerOverflow => ffi::m3Err_trapIntegerOverflow,
                Trap::IntegerConversion => ffi::m3Err_trapIntegerConversion,
                Trap::IndirectCallTypeMismatch => ffi::m3Err_trapIndirectCallTypeMismatch,
                Trap::TableIndexOutOfRange => ffi::m3Err_trapTableIndexOutOfRange,
                Trap::Exit => ffi::m3Err_trapExit,
                Trap::Abort => ffi::m3Err_trapAbort,
                Trap::Unreachable => ffi::m3Err_trapUnreachable,
                Trap::StackOverflow => ffi::m3Err_trapStackOverflow,
            }
        }
    }
}

impl cmp::PartialEq<Wasm3Error> for Trap {
    fn eq(&self, &Wasm3Error(err): &Wasm3Error) -> bool {
        self.as_ptr() == err
    }
}

#[cfg(feature = "std")]
impl std::error::Error for Trap {}
impl fmt::Display for Trap {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(unsafe { cstr_to_str(self.as_ptr()) }, f)
    }
}

/// Error returned by wasm3.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Wasm3Error(*const cty::c_char);

impl Wasm3Error {
    /// Check whether this error is the specified trap.
    pub fn is_trap(self, trap: Trap) -> bool {
        trap.as_ptr() == self.0
    }
}

impl cmp::PartialEq<Trap> for Wasm3Error {
    fn eq(&self, trap: &Trap) -> bool {
        trap.as_ptr() == self.0
    }
}

#[cfg(feature = "std")]
impl std::error::Error for Wasm3Error {}
impl fmt::Display for Wasm3Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(unsafe { cstr_to_str(self.0) }, f)
    }
}

/// Error returned by wasm3-rs.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Error {
    /// An error originating from wasm3 itself may or may not be a trap.
    Wasm3(Wasm3Error),
    /// A function has been found but its signature didn't match.
    InvalidFunctionSignature,
    /// The specified function could not be found.
    FunctionNotFound,
    /// The specified module could not be found.
    ModuleNotFound,
    /// The modules environment did not match the runtime's environment.
    ModuleLoadEnvMismatch,
}

impl Error {
    pub(crate) fn from_ffi_res(ptr: ffi::M3Result) -> Result<()> {
        if ptr.is_null() {
            Ok(())
        } else {
            Err(Error::Wasm3(Wasm3Error(ptr)))
        }
    }

    pub(crate) fn malloc_error() -> Self {
        Error::Wasm3(Wasm3Error(unsafe { ffi::m3Err_mallocFailed }))
    }
}

#[cfg(feature = "std")]
impl std::error::Error for Error {}
impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Error::Wasm3(err) => fmt::Display::fmt(err, f),
            Error::InvalidFunctionSignature => {
                write!(f, "the found function had an unexpected signature")
            }
            Error::FunctionNotFound => write!(f, "the function could not be found"),
            Error::ModuleNotFound => write!(f, "the module could not be found"),
            Error::ModuleLoadEnvMismatch => {
                write!(f, "the module and runtime environments were not the same")
            }
        }
    }
}