summaryrefslogtreecommitdiff
path: root/crates/tinywasm/src/runtime/value.rs
blob: 72308302e37d4aa3cd6fb361c54dc297c52dd225 (plain)
use core::fmt::Debug;

use tinywasm_types::{ValType, WasmValue};

/// A raw wasm value.
///
/// This is the internal representation of all wasm values
///
/// See [`WasmValue`] for the public representation.
#[derive(Clone, Copy, Default, PartialEq, Eq)]
pub struct RawWasmValue(u64);

impl Debug for RawWasmValue {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        write!(f, "RawWasmValue({})", self.0 as i64) // cast to i64 so at least negative numbers for i32 and i64 are printed correctly
    }
}

impl RawWasmValue {
    pub fn raw_value(&self) -> u64 {
        self.0
    }

    pub fn attach_type(self, ty: ValType) -> WasmValue {
        match ty {
            ValType::I32 => WasmValue::I32(self.0 as i32),
            ValType::I64 => WasmValue::I64(self.0 as i64),
            ValType::F32 => WasmValue::F32(f32::from_bits(self.0 as u32)),
            ValType::F64 => WasmValue::F64(f64::from_bits(self.0)),
            ValType::RefExtern => {
                if self.0 == -1i64 as u64 {
                    WasmValue::RefNull(ValType::RefExtern)
                } else {
                    WasmValue::RefExtern(self.0 as u32)
                }
            }
            ValType::RefFunc => {
                if self.0 == -1i64 as u64 {
                    WasmValue::RefNull(ValType::RefFunc)
                } else {
                    WasmValue::RefFunc(self.0 as u32)
                }
            }
        }
    }
}

impl From<WasmValue> for RawWasmValue {
    fn from(v: WasmValue) -> Self {
        match v {
            WasmValue::I32(i) => Self(i as u64),
            WasmValue::I64(i) => Self(i as u64),
            WasmValue::F32(i) => Self(i.to_bits() as u64),
            WasmValue::F64(i) => Self(i.to_bits()),
            WasmValue::RefExtern(v) => Self(v as i64 as u64),
            WasmValue::RefFunc(v) => Self(v as i64 as u64),
            WasmValue::RefNull(_) => Self(-1i64 as u64),
        }
    }
}

macro_rules! impl_from_raw_wasm_value {
    ($type:ty, $to_raw:expr, $from_raw:expr) => {
        // Implement From<$type> for RawWasmValue
        impl From<$type> for RawWasmValue {
            fn from(value: $type) -> Self {
                #[allow(clippy::redundant_closure_call)] // the comiler will figure it out :)
                Self($to_raw(value))
            }
        }

        // Implement From<RawWasmValue> for $type
        impl From<RawWasmValue> for $type {
            fn from(value: RawWasmValue) -> Self {
                #[allow(clippy::redundant_closure_call)] // the comiler will figure it out :)
                $from_raw(value.0)
            }
        }
    };
}

impl_from_raw_wasm_value!(i32, |x| x as u64, |x| x as i32);
impl_from_raw_wasm_value!(i64, |x| x as u64, |x| x as i64);
impl_from_raw_wasm_value!(f32, |x| f32::to_bits(x) as u64, |x| f32::from_bits(x as u32));
impl_from_raw_wasm_value!(f64, f64::to_bits, f64::from_bits);

// convenience impls (not actually part of the spec)
impl_from_raw_wasm_value!(i8, |x| x as u64, |x| x as i8);
impl_from_raw_wasm_value!(i16, |x| x as u64, |x| x as i16);
impl_from_raw_wasm_value!(u32, |x| x as u64, |x| x as u32);
impl_from_raw_wasm_value!(u64, |x| x, |x| x);