gdnative_core/export/
type_tag.rs1use std::any::TypeId;
2use std::mem::{align_of, size_of};
3
4use indexmap::IndexSet;
5
6use crate::export::NativeClass;
7
8#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
9struct Tag {
10 type_id: TypeId,
11}
12
13impl Tag {
14 #[inline]
15 fn of<T>() -> Self
16 where
17 T: NativeClass,
18 {
19 Tag {
20 type_id: TypeId::of::<T>(),
21 }
22 }
23}
24
25const USE_TRANSMUTE: bool = cfg!(not(feature = "type-tag-fallback"))
28 && size_of::<Tag>() == size_of::<usize>()
29 && align_of::<Tag>() == align_of::<usize>();
30
31static mut TAGS: Option<IndexSet<Tag, ahash::RandomState>> = None;
34
35const MAGIC: usize = 1usize.rotate_right(1);
38const MAGIC_MASK: usize = !MAGIC;
40
41#[inline]
43pub(crate) unsafe fn create<T>() -> *const libc::c_void
44where
45 T: NativeClass,
46{
47 let tag = Tag::of::<T>();
48
49 if USE_TRANSMUTE {
50 *(&tag as *const Tag as *const *const libc::c_void)
52 } else {
53 let tags = TAGS.get_or_insert_with(IndexSet::default);
55 let (idx, _) = tags.insert_full(tag);
56 (idx | MAGIC) as *const libc::c_void
59 }
60}
61
62#[inline]
64pub(crate) unsafe fn check<T>(tag: *const libc::c_void) -> bool
65where
66 T: NativeClass,
67{
68 if USE_TRANSMUTE {
69 Tag::of::<T>() == *(&tag as *const *const libc::c_void as *const Tag)
71 } else {
72 let tags = TAGS.as_ref().expect("tag should be created by `create`");
73 let idx = tag as usize;
74 let tag = tags
75 .get_index(idx & MAGIC_MASK)
76 .expect("tag should be created by `create`");
77 Tag::of::<T>() == *tag
78 }
79}
80
81#[inline]
84pub(crate) unsafe fn cleanup() {
85 if let Some(tags) = TAGS.take() {
87 drop(tags);
88 }
89}