wasmi 2.0.0-beta.2

WebAssembly interpreter
Documentation
use crate::{
    ExternRef,
    F32,
    F64,
    Func,
    Nullable,
    Ref,
    V128,
    ValType,
    core::{RawRef, RawVal},
    store::AsStoreId,
};

/// Runtime representation of a Wasm value.
///
/// Wasm code manipulate values of the four basic value types:
/// integers and floating-point (IEEE 754-2008) data of 32 or 64 bit width each, respectively.
///
/// There is no distinction between signed and unsigned integer types. Instead, integers are
/// interpreted by respective operations as either unsigned or signed in two’s complement representation.
#[derive(Clone, Debug)]
pub enum Val {
    /// Value of 32-bit signed or unsigned integer.
    I32(i32),
    /// Value of 64-bit signed or unsigned integer.
    I64(i64),
    /// Value of 32-bit IEEE 754-2008 floating point number.
    F32(F32),
    /// Value of 64-bit IEEE 754-2008 floating point number.
    F64(F64),
    /// 128-bit Wasm `simd` proposal vector.
    V128(V128),
    /// A nullable [`Func`] reference.
    FuncRef(Nullable<Func>),
    /// A nullable [`ExternRef`] reference.
    ExternRef(Nullable<ExternRef>),
}

impl Val {
    /// Create a [`Val`] from its raw parts.
    pub(crate) fn from_raw_parts(val: RawVal, ty: ValType, store: impl AsStoreId) -> Self {
        match ty {
            ValType::I32 => Self::I32(val.into()),
            ValType::I64 => Self::I64(val.into()),
            ValType::F32 => Self::F32(val.into()),
            ValType::F64 => Self::F64(val.into()),
            #[cfg(feature = "simd")]
            ValType::V128 => Self::V128(val.into()),
            #[cfg(not(feature = "simd"))]
            ValType::V128 => {
                panic!("Val::from_raw_parts does not work for `v128` values without `simd`")
            }
            ValType::FuncRef => Self::FuncRef(<Nullable<Func>>::from_raw_parts(val.into(), store)),
            ValType::ExternRef => {
                Self::ExternRef(<Nullable<ExternRef>>::from_raw_parts(val.into(), store))
            }
        }
    }

    /// Unwraps [`Val`] into its underlying [`RawVal`].
    ///
    /// Returns `None` if `self` does not originate from `store`.
    pub(crate) fn unwrap_raw_val(&self, store: impl AsStoreId) -> Option<RawVal> {
        let value = match *self {
            Self::I32(value) => value.into(),
            Self::I64(value) => value.into(),
            Self::F32(value) => value.into(),
            Self::F64(value) => value.into(),
            #[cfg(feature = "simd")]
            Self::V128(value) => value.into(),
            #[cfg(not(feature = "simd"))]
            Self::V128(_) => {
                unimplemented!("must enable `simd` crate feature to use `V128` values")
            }
            Self::FuncRef(value) => <Nullable<Func>>::unwrap_raw(&value, store)?.into(),
            Self::ExternRef(value) => <Nullable<ExternRef>>::unwrap_raw(&value, store)?.into(),
        };
        Some(value)
    }

    /// Unwraps [`Val`] into its underlying [`RawRef`] if possible.
    ///
    /// # Note
    ///
    /// - Returns `None` if `self` is not a reference value.
    /// - Returns `None` if `self` does not originate from `store`.
    pub(crate) fn unwrap_raw_ref(&self, store: impl AsStoreId) -> Option<RawRef> {
        let value = match *self {
            Self::FuncRef(value) => <Nullable<Func>>::unwrap_raw(&value, store)?,
            Self::ExternRef(value) => <Nullable<ExternRef>>::unwrap_raw(&value, store)?,
            _ => return None,
        };
        Some(value)
    }

    /// Returns the underlying [`RawVal`] of `self` or `None`.
    ///
    /// Returns `None` if `self` is a non-null reference value.
    pub(crate) fn as_raw_or_none(&self) -> Option<RawVal> {
        let raw = match *self {
            Self::I32(value) => value.into(),
            Self::I64(value) => value.into(),
            Self::F32(value) => value.into(),
            Self::F64(value) => value.into(),
            #[cfg(feature = "simd")]
            Self::V128(value) => value.into(),
            Self::FuncRef(Nullable::Null) => RawRef::null().into(),
            Self::ExternRef(Nullable::Null) => RawRef::null().into(),
            _ => return None,
        };
        Some(raw)
    }

    /// Creates new default value of given type.
    #[inline]
    #[deprecated(note = "use `Val::default_for_ty` instead")]
    pub fn default(ty: ValType) -> Self {
        Self::default_for_ty(ty)
    }

    /// Creates new default value of given type.
    #[inline]
    pub fn default_for_ty(ty: ValType) -> Self {
        match ty {
            ValType::I32 => Self::I32(0),
            ValType::I64 => Self::I64(0),
            ValType::F32 => Self::F32(0f32.into()),
            ValType::F64 => Self::F64(0f64.into()),
            ValType::V128 => Self::V128(V128::from(0_u128)),
            ValType::FuncRef => Self::from(<Nullable<Func>>::Null),
            ValType::ExternRef => Self::from(<Nullable<ExternRef>>::Null),
        }
    }

    /// Get variable type for this value.
    #[inline]
    pub fn ty(&self) -> ValType {
        match *self {
            Self::I32(_) => ValType::I32,
            Self::I64(_) => ValType::I64,
            Self::F32(_) => ValType::F32,
            Self::F64(_) => ValType::F64,
            Self::V128(_) => ValType::V128,
            Self::FuncRef(_) => ValType::FuncRef,
            Self::ExternRef(_) => ValType::ExternRef,
        }
    }

    /// Returns the underlying `i32` if the type matches otherwise returns `None`.
    pub fn i32(&self) -> Option<i32> {
        match self {
            Self::I32(value) => Some(*value),
            _ => None,
        }
    }

    /// Returns the underlying `i64` if the type matches otherwise returns `None`.
    pub fn i64(&self) -> Option<i64> {
        match self {
            Self::I64(value) => Some(*value),
            _ => None,
        }
    }

    /// Returns the underlying `f32` if the type matches otherwise returns `None`.
    pub fn f32(&self) -> Option<F32> {
        match self {
            Self::F32(value) => Some(*value),
            _ => None,
        }
    }

    /// Returns the underlying `f64` if the type matches otherwise returns `None`.
    pub fn f64(&self) -> Option<F64> {
        match self {
            Self::F64(value) => Some(*value),
            _ => None,
        }
    }

    /// Returns the underlying `funcref` if the type matches otherwise returns `None`.
    pub fn funcref(&self) -> Option<Nullable<&Func>> {
        match self {
            Self::FuncRef(value) => Some(value.as_ref()),
            _ => None,
        }
    }

    /// Returns the underlying `externref` if the type matches otherwise returns `None`.
    pub fn externref(&self) -> Option<Nullable<&ExternRef>> {
        match self {
            Self::ExternRef(value) => Some(value.as_ref()),
            _ => None,
        }
    }
}

impl From<i32> for Val {
    #[inline]
    fn from(val: i32) -> Self {
        Self::I32(val)
    }
}

impl From<i64> for Val {
    #[inline]
    fn from(val: i64) -> Self {
        Self::I64(val)
    }
}

impl From<f32> for Val {
    #[inline]
    fn from(val: f32) -> Self {
        Self::F32(F32::from_float(val))
    }
}

impl From<f64> for Val {
    #[inline]
    fn from(val: f64) -> Self {
        Self::F64(F64::from_float(val))
    }
}

impl From<F32> for Val {
    #[inline]
    fn from(val: F32) -> Self {
        Self::F32(val)
    }
}

impl From<F64> for Val {
    #[inline]
    fn from(val: F64) -> Self {
        Self::F64(val)
    }
}

impl From<Ref> for Val {
    fn from(value: Ref) -> Self {
        match value {
            Ref::Func(nullable) => Self::FuncRef(nullable),
            Ref::Extern(nullable) => Self::ExternRef(nullable),
        }
    }
}

impl From<Func> for Val {
    #[inline]
    fn from(func: Func) -> Self {
        Self::FuncRef(Nullable::Val(func))
    }
}

impl From<ExternRef> for Val {
    #[inline]
    fn from(externref: ExternRef) -> Self {
        Self::ExternRef(Nullable::Val(externref))
    }
}

impl From<Nullable<Func>> for Val {
    #[inline]
    fn from(funcref: Nullable<Func>) -> Self {
        Self::FuncRef(funcref)
    }
}

impl From<Nullable<ExternRef>> for Val {
    #[inline]
    fn from(externref: Nullable<ExternRef>) -> Self {
        Self::ExternRef(externref)
    }
}

impl From<V128> for Val {
    #[inline]
    fn from(value: V128) -> Self {
        Self::V128(value)
    }
}