wasmer-interface-types-fl 0.17.16

WebAssembly Interface Types library for Wasmer
Documentation
//! The error module contains all the data structures that represent
//! an error.

use crate::values::InterfaceValue;
use crate::{ast::TypeKind, interpreter::Instruction, types::InterfaceType};
use std::{
    error::Error,
    fmt::{self, Display, Formatter},
    num::TryFromIntError,
    result::Result,
    string::{self, ToString},
};

/// A type alias for instruction's results.
pub type InstructionResult<T> = Result<T, InstructionError>;

/// A type alias for the interpreter result.
pub type InterpreterResult<T> = Result<T, InstructionError>;

/// Structure to represent errors when casting from an `InterfaceType`
/// to a native value.
#[derive(Debug)]
pub struct WasmValueNativeCastError {
    /// The initial type.
    pub from: InterfaceValue,

    /// The targeted type.
    ///
    /// `InterfaceType` is used to represent the native type by
    /// associativity.
    pub to: InterfaceType,
}

impl Error for WasmValueNativeCastError {}

impl Display for WasmValueNativeCastError {
    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
        write!(formatter, "{:?}", self)
    }
}

/// Structure to represent the errors for instructions.
#[derive(Debug)]
pub struct InstructionError {
    /// The instruction that raises the error.
    pub instruction: Instruction,

    /// The error kind.
    pub error_kind: InstructionErrorKind,
}

impl InstructionError {
    pub(crate) fn new(instruction: Instruction, error_kind: InstructionErrorKind) -> Self {
        Self {
            instruction,
            error_kind,
        }
    }
}

impl Error for InstructionError {}

impl Display for InstructionError {
    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
        write!(
            formatter,
            "`{}` {}",
            (&self.instruction).to_string(),
            self.error_kind
        )
    }
}

/// The kind of instruction errors.
#[derive(Debug)]
pub enum InstructionErrorKind {
    /// The instruction needs to read an invocation input at index `index`, but it's missing.
    InvocationInputIsMissing {
        /// The invocation input index.
        index: u32,
    },

    /// Failed to cast from a WIT value to a native value.
    ToNative(WasmValueNativeCastError),

    /// Failed to cast from `from` to `to`.
    LoweringLifting {
        /// The initial type.
        from: InterfaceType,

        /// The targeted type.
        to: InterfaceType,
    },

    /// Read a value from the stack, but it doesn't have the expected
    /// type.
    InvalidValueOnTheStack {
        /// The expected type.
        expected_type: InterfaceType,

        /// The received type.
        received_value: InterfaceValue,
    },

    /// Need to read some values from the stack, but it doesn't
    /// contain enough data.
    StackIsTooSmall {
        /// The number of values that were needed.
        needed: usize,
    },

    /// The local or import function doesn't exist.
    LocalOrImportIsMissing {
        /// The local or import function index.
        function_index: u32,
    },

    /// Values given to a local or import function doesn't match the
    /// function signature.
    LocalOrImportSignatureMismatch {
        /// The local or import function index.
        function_index: u32,

        /// The expected signature.
        expected: (Vec<InterfaceType>, Vec<InterfaceType>),

        /// The received signature.
        received: (Vec<InterfaceType>, Vec<InterfaceType>),
    },

    /// Failed to call a local or import function.
    LocalOrImportCall {
        /// The local or import function name that has been called.
        function_name: String,
    },

    /// The memory doesn't exist.
    MemoryIsMissing {
        /// The memory indeX.
        memory_index: u32,
    },

    /// Tried to read out of bounds of the memory.
    MemoryOutOfBoundsAccess {
        /// The access index.
        index: usize,

        /// The memory length.
        length: usize,
    },

    /// The string contains invalid UTF-8 encoding.
    String(string::FromUtf8Error),

    /// Out of range integral type conversion attempted.
    NegativeValue {
        /// The variable name that triggered the error.
        subject: &'static str,
    },

    /// The type doesn't exist.
    TypeIsMissing {
        /// The type index.
        type_index: u32,
    },

    /// The searched by name type doesn't exist.
    RecordTypeByNameIsMissing {
        /// The record type name.
        record_type_id: u64,
    },

    /// Corrupted array's been popped from the stack.
    CorruptedArray(String),

    /// Corrupted record's been popped from the stack.
    CorruptedRecord(String),

    /// Read a type that has an unexpected type.
    InvalidTypeKind {
        /// The expected kind.
        expected_kind: TypeKind,

        /// The received kind.
        received_kind: TypeKind,
    },

    /// Errors related to Serialization/deserialization of record.
    SerdeError(String),
}

impl Error for InstructionErrorKind {}

impl Display for InstructionErrorKind {
    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
        match self {
            Self::InvocationInputIsMissing { index } => write!(
                formatter,
                "cannot access invocation inputs #{} because it doesn't exist",
                index
            ),

            Self::ToNative(WasmValueNativeCastError { from, .. }) => write!(
                formatter,
                "failed to cast the WIT value `{:?}` to its native type",
                from,
            ),

            Self::LoweringLifting { from, to } => {
                write!(formatter, "failed to cast `{:?}` to `{:?}`", from, to)
            }

            Self::InvalidValueOnTheStack {
                expected_type,
                received_value,
            } => write!(
                formatter,
                "read a value `{:?}` from the stack, that can't be converted to `{:?}`",
                received_value, expected_type,
            ),

            Self::StackIsTooSmall { needed } => write!(
                formatter,
                "needed to read `{}` value(s) from the stack, but it doesn't contain enough data",
                needed
            ),

            Self::LocalOrImportIsMissing { function_index } => write!(
                formatter,
                "the local or import function `{}` doesn't exist",
                function_index
            ),

            Self::LocalOrImportSignatureMismatch { function_index, expected, received } => write!(
                formatter,
                "the local or import function `{}` has the signature `{:?} -> {:?}` but it received values of kind `{:?} -> {:?}`",
                function_index, expected.0, expected.1, received.0, received.1,
            ),

            Self::LocalOrImportCall  { function_name } => write!(
                formatter,
                "failed while calling the local or import function `{}`",
                function_name
            ),

            Self::MemoryIsMissing { memory_index } => write!(
                formatter,
                "memory `{}` does not exist",
                memory_index,
            ),

            Self::MemoryOutOfBoundsAccess { index, length } => write!(
                formatter,
                "read out of the memory bounds (index {} > memory length {})",
                index, length,
            ),

            Self::String(error) => write!(formatter, "{}", error),

            Self::NegativeValue { subject } => write!(
                formatter,
                "attempted to convert `{}` but it appears to be a negative value",
                subject
            ),

            Self::TypeIsMissing { type_index } => write!(
                formatter,
                "the type `{}` doesn't exist",
                type_index
            ),

            Self::InvalidTypeKind { expected_kind, received_kind } => write!(
                formatter,
                "read a type of kind `{:?}`, but the kind `{:?}` was expected",
                received_kind, expected_kind
            ),

            Self::RecordTypeByNameIsMissing  { record_type_id: type_name } => write!(
                formatter,
                "type with `{}` is missing in a Wasm binary",
                type_name
            ),

            Self::CorruptedArray(err) => write!(
                formatter,
                "{}",
                err
            ),

            Self::CorruptedRecord(err) => write!(
                formatter,
                "{}",
                err
            ),

            Self::SerdeError(err) => write!(
                formatter,
                "serde error: {}", err,
            ),
        }
    }
}

impl From<(TryFromIntError, &'static str)> for InstructionErrorKind {
    fn from((_, subject): (TryFromIntError, &'static str)) -> Self {
        InstructionErrorKind::NegativeValue { subject }
    }
}