use crate::runtime::vm::{VMGcRef, ValRaw};
use crate::{
HeapType, RefType, Result, ValType, WasmTy,
store::{AutoAssertNoGc, StoreOpaque},
};
use core::fmt;
use core::mem::MaybeUninit;
#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct I31(crate::runtime::vm::I31);
impl fmt::Debug for I31 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("I31")
.field("as_u32", &self.get_u32())
.field("as_i32", &self.get_i32())
.finish()
}
}
impl From<crate::runtime::vm::I31> for I31 {
#[inline]
fn from(value: crate::runtime::vm::I31) -> Self {
Self(value)
}
}
impl From<I31> for crate::runtime::vm::I31 {
#[inline]
fn from(value: I31) -> Self {
value.0
}
}
impl I31 {
pub(crate) fn runtime_i31(self) -> crate::runtime::vm::I31 {
self.0
}
#[inline]
pub fn new_u32(value: u32) -> Option<Self> {
crate::runtime::vm::I31::new_u32(value).map(Self)
}
#[inline]
pub fn new_i32(value: i32) -> Option<Self> {
crate::runtime::vm::I31::new_i32(value).map(Self)
}
#[inline]
pub fn wrapping_u32(value: u32) -> Self {
Self(crate::runtime::vm::I31::wrapping_u32(value))
}
#[inline]
pub fn wrapping_i32(value: i32) -> Self {
Self(crate::runtime::vm::I31::wrapping_i32(value))
}
#[inline]
pub fn get_u32(&self) -> u32 {
self.0.get_u32()
}
#[inline]
pub fn get_i32(&self) -> i32 {
self.0.get_i32()
}
}
unsafe impl WasmTy for I31 {
#[inline]
fn valtype() -> ValType {
ValType::Ref(RefType::new(false, HeapType::I31))
}
#[inline]
fn compatible_with_store(&self, _store: &StoreOpaque) -> bool {
true
}
fn dynamic_concrete_type_check(
&self,
_store: &StoreOpaque,
_nullable: bool,
_actual: &HeapType,
) -> Result<()> {
unreachable!()
}
fn store(self, _store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
let gc_ref = VMGcRef::from_i31(self.into()).as_raw_u32();
ptr.write(ValRaw::anyref(gc_ref));
Ok(())
}
unsafe fn load(_store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
let raw = ptr.get_anyref();
let gc_ref = VMGcRef::from_raw_u32(raw).expect("non-null");
gc_ref.unwrap_i31().into()
}
}
unsafe impl WasmTy for Option<I31> {
#[inline]
fn valtype() -> ValType {
ValType::Ref(RefType::new(true, HeapType::I31))
}
#[inline]
fn compatible_with_store(&self, _store: &StoreOpaque) -> bool {
true
}
fn dynamic_concrete_type_check(
&self,
_store: &StoreOpaque,
_nullable: bool,
_actual: &HeapType,
) -> Result<()> {
unreachable!()
}
fn store(self, store: &mut AutoAssertNoGc<'_>, ptr: &mut MaybeUninit<ValRaw>) -> Result<()> {
match self {
Some(i) => i.store(store, ptr),
None => {
ptr.write(ValRaw::anyref(0));
Ok(())
}
}
}
unsafe fn load(_store: &mut AutoAssertNoGc<'_>, ptr: &ValRaw) -> Self {
let raw = ptr.get_anyref();
let gc_ref = VMGcRef::from_raw_u32(raw)?;
Some(I31(gc_ref.unwrap_i31()))
}
}