use std::any::TypeId;
use std::mem::{align_of, size_of};
use indexmap::IndexSet;
use crate::export::NativeClass;
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
struct Tag {
type_id: TypeId,
}
impl Tag {
#[inline]
fn of<T>() -> Self
where
T: NativeClass,
{
Tag {
type_id: TypeId::of::<T>(),
}
}
}
const USE_TRANSMUTE: bool = cfg!(not(feature = "type-tag-fallback"))
&& size_of::<Tag>() == size_of::<usize>()
&& align_of::<Tag>() == align_of::<usize>();
static mut TAGS: Option<IndexSet<Tag, ahash::RandomState>> = None;
const MAGIC: usize = 1usize.rotate_right(1);
const MAGIC_MASK: usize = !MAGIC;
#[inline]
pub(crate) unsafe fn create<T>() -> *const libc::c_void
where
T: NativeClass,
{
let tag = Tag::of::<T>();
if USE_TRANSMUTE {
*(&tag as *const Tag as *const *const libc::c_void)
} else {
let tags = TAGS.get_or_insert_with(IndexSet::default);
let (idx, _) = tags.insert_full(tag);
(idx | MAGIC) as *const libc::c_void
}
}
#[inline]
pub(crate) unsafe fn check<T>(tag: *const libc::c_void) -> bool
where
T: NativeClass,
{
if USE_TRANSMUTE {
Tag::of::<T>() == *(&tag as *const *const libc::c_void as *const Tag)
} else {
let tags = TAGS.as_ref().expect("tag should be created by `create`");
let idx = tag as usize;
let tag = tags
.get_index(idx & MAGIC_MASK)
.expect("tag should be created by `create`");
Tag::of::<T>() == *tag
}
}
#[inline]
pub(crate) unsafe fn cleanup() {
if let Some(tags) = TAGS.take() {
drop(tags);
}
}