use crate::lib::std::fmt;
use crate::lib::std::ptr;
use crate::lib::std::string::{String, ToString};
use crate::r#ref::ExternRef;
use crate::types::Type;
#[derive(Clone, PartialEq)]
pub enum Value<T> {
I32(i32),
I64(i64),
F32(f32),
F64(f64),
ExternRef(ExternRef),
FuncRef(T),
V128(u128),
}
macro_rules! accessors {
($bind:ident $(($variant:ident($ty:ty) $get:ident $unwrap:ident $cvt:expr))*) => ($(
pub fn $get(&self) -> Option<$ty> {
if let Self::$variant($bind) = self {
Some($cvt)
} else {
None
}
}
pub fn $unwrap(&self) -> $ty {
self.$get().expect(concat!("expected ", stringify!($ty)))
}
)*)
}
impl<T> Value<T> {
pub fn null() -> Self {
Self::ExternRef(ExternRef::null())
}
pub fn ty(&self) -> Type {
match self {
Self::I32(_) => Type::I32,
Self::I64(_) => Type::I64,
Self::F32(_) => Type::F32,
Self::F64(_) => Type::F64,
Self::ExternRef(_) => Type::ExternRef,
Self::FuncRef(_) => Type::FuncRef,
Self::V128(_) => Type::V128,
}
}
pub unsafe fn write_value_to(&self, p: *mut i128) {
match self {
Self::I32(i) => ptr::write(p as *mut i32, *i),
Self::I64(i) => ptr::write(p as *mut i64, *i),
Self::F32(u) => ptr::write(p as *mut f32, *u),
Self::F64(u) => ptr::write(p as *mut f64, *u),
Self::V128(b) => ptr::write(p as *mut u128, *b),
_ => unimplemented!("Value::write_value_to"),
}
}
pub unsafe fn read_value_from(p: *const i128, ty: Type) -> Self {
match ty {
Type::I32 => Self::I32(ptr::read(p as *const i32)),
Type::I64 => Self::I64(ptr::read(p as *const i64)),
Type::F32 => Self::F32(ptr::read(p as *const f32)),
Type::F64 => Self::F64(ptr::read(p as *const f64)),
Type::V128 => Self::V128(ptr::read(p as *const u128)),
_ => unimplemented!("Value::read_value_from"),
}
}
accessors! {
e
(I32(i32) i32 unwrap_i32 *e)
(I64(i64) i64 unwrap_i64 *e)
(F32(f32) f32 unwrap_f32 *e)
(F64(f64) f64 unwrap_f64 *e)
(FuncRef(&T) funcref unwrap_funcref e)
(V128(u128) v128 unwrap_v128 *e)
}
pub fn externref(&self) -> Option<ExternRef> {
match self {
Self::ExternRef(e) => Some(e.clone()),
_ => None,
}
}
pub fn unwrap_externref(&self) -> ExternRef {
self.externref().expect("expected externref")
}
}
impl<T> fmt::Debug for Value<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::I32(v) => write!(f, "I32({:?})", v),
Self::I64(v) => write!(f, "I64({:?})", v),
Self::F32(v) => write!(f, "F32({:?})", v),
Self::F64(v) => write!(f, "F64({:?})", v),
Self::ExternRef(v) => write!(f, "ExternRef({:?})", v),
Self::FuncRef(_) => write!(f, "FuncRef"),
Self::V128(v) => write!(f, "V128({:?})", v),
}
}
}
impl<T> ToString for Value<T> {
fn to_string(&self) -> String {
match self {
Self::I32(v) => v.to_string(),
Self::I64(v) => v.to_string(),
Self::F32(v) => v.to_string(),
Self::F64(v) => v.to_string(),
Self::ExternRef(_) => "externref".to_string(),
Self::FuncRef(_) => "funcref".to_string(),
Self::V128(v) => v.to_string(),
}
}
}
impl<T> From<i32> for Value<T> {
fn from(val: i32) -> Self {
Self::I32(val)
}
}
impl<T> From<u32> for Value<T> {
fn from(val: u32) -> Self {
Self::I32(val as i32)
}
}
impl<T> From<i64> for Value<T> {
fn from(val: i64) -> Self {
Self::I64(val)
}
}
impl<T> From<u64> for Value<T> {
fn from(val: u64) -> Self {
Self::I64(val as i64)
}
}
impl<T> From<f32> for Value<T> {
fn from(val: f32) -> Self {
Self::F32(val)
}
}
impl<T> From<f64> for Value<T> {
fn from(val: f64) -> Self {
Self::F64(val)
}
}
impl<T> From<ExternRef> for Value<T> {
fn from(val: ExternRef) -> Self {
Self::ExternRef(val)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_value_i32_from_u32() {
let bytes = [0x00, 0x00, 0x00, 0x00];
let v = Value::<()>::from(u32::from_be_bytes(bytes.clone()));
assert_eq!(v, Value::I32(i32::from_be_bytes(bytes.clone())));
let bytes = [0x00, 0x00, 0x00, 0x01];
let v = Value::<()>::from(u32::from_be_bytes(bytes.clone()));
assert_eq!(v, Value::I32(i32::from_be_bytes(bytes.clone())));
let bytes = [0xAA, 0xBB, 0xCC, 0xDD];
let v = Value::<()>::from(u32::from_be_bytes(bytes.clone()));
assert_eq!(v, Value::I32(i32::from_be_bytes(bytes.clone())));
let bytes = [0xFF, 0xFF, 0xFF, 0xFF];
let v = Value::<()>::from(u32::from_be_bytes(bytes.clone()));
assert_eq!(v, Value::I32(i32::from_be_bytes(bytes.clone())));
}
#[test]
fn test_value_i64_from_u64() {
let bytes = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
let v = Value::<()>::from(u64::from_be_bytes(bytes.clone()));
assert_eq!(v, Value::I64(i64::from_be_bytes(bytes.clone())));
let bytes = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01];
let v = Value::<()>::from(u64::from_be_bytes(bytes.clone()));
assert_eq!(v, Value::I64(i64::from_be_bytes(bytes.clone())));
let bytes = [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x11];
let v = Value::<()>::from(u64::from_be_bytes(bytes.clone()));
assert_eq!(v, Value::I64(i64::from_be_bytes(bytes.clone())));
let bytes = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
let v = Value::<()>::from(u64::from_be_bytes(bytes.clone()));
assert_eq!(v, Value::I64(i64::from_be_bytes(bytes.clone())));
}
}