use core::{fmt, marker::PhantomData, mem::ManuallyDrop, num::NonZeroU32};
use crate::{GcValue, abi, schema::ValueKind};
#[must_use]
pub struct ExternRef {
handle: NonZeroU32,
local: PhantomData<*mut ()>,
}
impl ExternRef {
pub fn null() -> Self {
unsafe { Self::from_raw(abi::externref_null()) }
}
pub fn is_null(&self) -> bool {
unsafe { abi::externref_is_null(self.as_raw()) != 0 }
}
}
impl ExternRef {
#[inline]
pub fn as_raw(&self) -> u32 {
self.handle.get()
}
#[inline]
pub fn into_raw(self) -> u32 {
ManuallyDrop::new(self).handle.get()
}
#[inline]
pub unsafe fn from_raw(handle: u32) -> Self {
Self {
handle: NonZeroU32::new(handle).expect("wasmgc: an externref root cannot be null"),
local: PhantomData,
}
}
}
impl Clone for ExternRef {
fn clone(&self) -> Self {
unsafe { Self::from_raw(abi::externref_clone(self.as_raw())) }
}
}
impl Drop for ExternRef {
fn drop(&mut self) {
unsafe { abi::externref_release(self.as_raw()) }
}
}
impl Default for ExternRef {
fn default() -> Self {
Self::null()
}
}
impl fmt::Debug for ExternRef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ExternRef")
.field("root", &self.handle)
.finish()
}
}
unsafe impl GcValue for ExternRef {
type Abi = u32;
type SetterValue<'a> = &'a Self;
const KIND: ValueKind = ValueKind::EXTERNREF;
#[inline]
fn to_abi(&self) -> u32 {
self.as_raw()
}
#[inline]
fn setter_abi(value: &Self::SetterValue<'_>) -> u32 {
value.as_raw()
}
#[inline]
fn into_abi(self) -> u32 {
self.into_raw()
}
#[inline]
unsafe fn from_abi(value: u32) -> Self {
unsafe { Self::from_raw(value) }
}
}