use crate::{
ElementSegment,
Func,
Global,
Handle,
Memory,
Table,
memory::DataSegment,
store::Stored,
};
pub struct AnyHandleEntity;
define_handle! {
struct RawAnyHandle(u32, Stored) => AnyHandleEntity;
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(not(debug_assertions), expect(dead_code))]
pub(super) enum HandleKind {
Global,
Memory,
Table,
Func,
ElementSegment,
DataSegment,
}
#[derive(Debug, Copy, Clone)]
pub struct AnyHandle {
raw: RawAnyHandle,
#[cfg(debug_assertions)]
kind: HandleKind,
}
pub(super) trait HasHandleKind: Handle {
#[cfg_attr(not(debug_assertions), expect(dead_code))]
const KIND: HandleKind;
}
impl AnyHandle {
#[inline]
pub(super) fn assert_kind<T: HasHandleKind>(self) {
#[cfg(debug_assertions)]
debug_assert_eq!(
self.kind,
<T as HasHandleKind>::KIND,
"unexpected instance handle kind",
);
}
}
macro_rules! impl_cast_for_any_handle {
( $(
pub unsafe fn $cast_ident:ident(self) -> $handle:ident;
)* $(;)? ) => {
$(
#[doc = concat!("Casts `self` into a [`", stringify!($handle), "`] handle.")]
#[doc = ""]
#[doc = "# Safety"]
#[doc = ""]
#[doc = "The caller must guarantee that `self` was created from a"]
#[doc = concat!("[`", stringify!($handle), "`] handle.")]
#[doc = "Casting to any other handle type is undefined behavior."]
#[inline]
pub unsafe fn $cast_ident(self) -> $handle {
self.assert_kind::<$handle>();
unsafe { ::core::mem::transmute::<RawAnyHandle, $handle>(self.raw) }
}
)*
};
}
impl AnyHandle {
impl_cast_for_any_handle! {
pub unsafe fn cast_global(self) -> Global;
pub unsafe fn cast_func(self) -> Func;
pub unsafe fn cast_memory(self) -> Memory;
pub unsafe fn cast_table(self) -> Table;
pub unsafe fn cast_data(self) -> DataSegment;
pub unsafe fn cast_elem(self) -> ElementSegment;
}
}
macro_rules! impl_from_for_any_handle {
(
$( $handle:ident ),* $(,)?
) => {
$(
impl HasHandleKind for $handle {
const KIND: HandleKind = HandleKind::$handle;
}
impl From<$handle> for AnyHandle {
#[inline]
fn from(handle: $handle) -> Self {
let raw = unsafe { ::core::mem::transmute::<$handle, RawAnyHandle>(handle) };
Self {
raw,
#[cfg(debug_assertions)]
kind: HandleKind::$handle,
}
}
}
)*
};
}
impl_from_for_any_handle!(Global, Func, Memory, Table, DataSegment, ElementSegment);