use crate::{
StorageType, Val,
prelude::*,
runtime::vm::{GcHeap, GcStore, VMGcRef},
store::{AutoAssertNoGc, StoreOpaque},
};
use core::fmt;
use wasmtime_environ::{GcArrayLayout, VMGcKind};
#[derive(Debug, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct VMArrayRef(VMGcRef);
impl fmt::Pointer for VMArrayRef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Pointer::fmt(&self.0, f)
}
}
impl From<VMArrayRef> for VMGcRef {
#[inline]
fn from(x: VMArrayRef) -> Self {
x.0
}
}
impl VMGcRef {
pub fn is_arrayref(&self, gc_heap: &(impl GcHeap + ?Sized)) -> bool {
if self.is_i31() {
return false;
}
match gc_heap.header(&self) {
Ok(header) => header.kind().matches(VMGcKind::ArrayRef),
Err(_) => false,
}
}
pub fn into_arrayref(self, gc_heap: &(impl GcHeap + ?Sized)) -> Result<VMArrayRef, VMGcRef> {
if self.is_arrayref(gc_heap) {
Ok(self.into_arrayref_unchecked())
} else {
Err(self)
}
}
#[inline]
pub fn into_arrayref_unchecked(self) -> VMArrayRef {
debug_assert!(!self.is_i31());
VMArrayRef(self)
}
pub fn as_arrayref(&self, gc_heap: &(impl GcHeap + ?Sized)) -> Option<&VMArrayRef> {
if self.is_arrayref(gc_heap) {
Some(self.as_arrayref_unchecked())
} else {
None
}
}
pub fn as_arrayref_unchecked(&self) -> &VMArrayRef {
debug_assert!(!self.is_i31());
let ptr = self as *const VMGcRef;
let ret = unsafe { &*ptr.cast() };
assert!(matches!(ret, VMArrayRef(VMGcRef { .. })));
ret
}
}
impl VMArrayRef {
pub fn as_gc_ref(&self) -> &VMGcRef {
&self.0
}
pub fn clone(&self, gc_store: &mut GcStore) -> Self {
Self(gc_store.clone_gc_ref(&self.0))
}
pub fn drop(self, gc_store: &mut GcStore) {
gc_store.drop_gc_ref(self.0);
}
pub fn unchecked_copy(&self) -> Self {
Self(self.0.unchecked_copy())
}
pub fn len(&self, store: &StoreOpaque) -> Result<u32> {
store.unwrap_gc_store().array_len(self)
}
pub fn read_elem(
&self,
store: &mut AutoAssertNoGc,
layout: &GcArrayLayout,
ty: &StorageType,
index: u32,
) -> Result<Val> {
let offset = layout.elem_offset(index).unwrap();
self.as_gc_ref().read_val(store, ty, offset)
}
pub fn write_elem(
&self,
store: &mut AutoAssertNoGc,
layout: &GcArrayLayout,
ty: &StorageType,
index: u32,
val: Val,
) -> Result<()> {
debug_assert!(val._matches_ty(&store, &ty.unpack())?);
let offset = layout.elem_offset(index).unwrap();
self.as_gc_ref().write_val(store, ty, offset, val)
}
pub fn initialize_elem(
&self,
store: &mut AutoAssertNoGc,
layout: &GcArrayLayout,
ty: &StorageType,
index: u32,
val: Val,
) -> Result<()> {
debug_assert!(val._matches_ty(&store, &ty.unpack())?);
let offset = layout.elem_offset(index).unwrap();
self.as_gc_ref().initialize_val(store, ty, offset, val)
}
}