use crate::{
store::{AutoAssertNoGc, StoreOpaque},
FuncType, HeapType, RefType, Result, ValType, WasmTy,
};
use wasmtime_runtime::{VMGcRef, ValRaw};
#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct I31(wasmtime_runtime::I31);
impl std::fmt::Debug for I31 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("I31")
.field("as_u32", &self.get_u32())
.field("as_i32", &self.get_i32())
.finish()
}
}
impl From<wasmtime_runtime::I31> for I31 {
#[inline]
fn from(value: wasmtime_runtime::I31) -> Self {
Self(value)
}
}
impl From<I31> for wasmtime_runtime::I31 {
#[inline]
fn from(value: I31) -> Self {
value.0
}
}
impl I31 {
pub(crate) fn runtime_i31(self) -> wasmtime_runtime::I31 {
self.0
}
#[inline]
pub fn new_u32(value: u32) -> Option<Self> {
wasmtime_runtime::I31::new_u32(value).map(Self)
}
#[inline]
pub fn new_i32(value: i32) -> Option<Self> {
wasmtime_runtime::I31::new_i32(value).map(Self)
}
#[inline]
pub fn wrapping_u32(value: u32) -> Self {
Self(wasmtime_runtime::I31::wrapping_u32(value))
}
#[inline]
pub fn wrapping_i32(value: i32) -> Self {
Self(wasmtime_runtime::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 {
type Abi = u64;
#[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: &FuncType,
) -> Result<()> {
unreachable!()
}
#[inline]
fn is_non_i31_gc_ref(&self) -> bool {
false
}
#[inline]
unsafe fn abi_from_raw(raw: *mut ValRaw) -> Self::Abi {
let raw = (*raw).get_anyref();
if cfg!(debug_assertions) {
let gc_ref = VMGcRef::from_raw_u32(raw).unwrap();
assert!(gc_ref.is_i31());
}
u64::from(raw)
}
#[inline]
unsafe fn abi_into_raw(abi: Self::Abi, raw: *mut ValRaw) {
if cfg!(debug_assertions) {
let gc_ref = VMGcRef::from_r64(abi).unwrap().unwrap();
assert!(gc_ref.is_i31());
}
let anyref = u32::try_from(abi).unwrap();
*raw = ValRaw::anyref(anyref)
}
#[inline]
fn into_abi(self, _store: &mut AutoAssertNoGc<'_>) -> Result<Self::Abi> {
Ok(VMGcRef::from_i31(self.into()).into_r64())
}
#[inline]
unsafe fn from_abi(abi: Self::Abi, _store: &mut AutoAssertNoGc<'_>) -> Self {
let gc_ref = VMGcRef::from_r64(abi)
.expect("valid r64")
.expect("non-null");
gc_ref.unwrap_i31().into()
}
}
unsafe impl WasmTy for Option<I31> {
type Abi = u64;
#[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: &FuncType,
) -> Result<()> {
unreachable!()
}
#[inline]
fn is_non_i31_gc_ref(&self) -> bool {
false
}
#[inline]
unsafe fn abi_from_raw(raw: *mut ValRaw) -> Self::Abi {
let raw = (*raw).get_anyref();
if cfg!(debug_assertions) {
if let Some(gc_ref) = VMGcRef::from_raw_u32(raw) {
assert!(gc_ref.is_i31());
}
}
u64::from(raw)
}
#[inline]
unsafe fn abi_into_raw(abi: Self::Abi, raw: *mut ValRaw) {
if cfg!(debug_assertions) {
if let Some(gc_ref) = VMGcRef::from_r64(abi).unwrap() {
assert!(gc_ref.is_i31());
}
}
let anyref = u32::try_from(abi).unwrap();
*raw = ValRaw::anyref(anyref)
}
#[inline]
fn into_abi(self, _store: &mut AutoAssertNoGc<'_>) -> Result<Self::Abi> {
Ok(self.map_or(0, |x| VMGcRef::from_i31(x.into()).into_r64()))
}
#[inline]
unsafe fn from_abi(abi: Self::Abi, _store: &mut AutoAssertNoGc<'_>) -> Self {
let gc_ref = VMGcRef::from_r64(abi).expect("valid r64");
gc_ref.map(|r| r.unwrap_i31().into())
}
}