1use core::{alloc::Layout, any::TypeId, marker::PhantomData, mem, ptr::NonNull};
2
3use once_cell::sync::OnceCell;
4
5use crate::{
6 buffer::ComponentBuffer,
7 component::{ComponentDesc, ComponentValue},
8};
9
10#[doc(hidden)]
11pub struct LazyComponentBuffer {
12 value: OnceCell<ComponentBuffer>,
13 init: fn(ComponentDesc) -> ComponentBuffer,
14}
15
16impl LazyComponentBuffer {
17 pub const fn new(init: fn(ComponentDesc) -> ComponentBuffer) -> Self {
19 Self {
20 value: OnceCell::new(),
21 init,
22 }
23 }
24
25 pub(crate) fn get_ref(&self, desc: ComponentDesc) -> &ComponentBuffer {
26 self.value.get_or_init(|| (self.init)(desc))
27 }
28
29 pub(crate) fn get(&self, desc: ComponentDesc) -> ComponentBuffer {
30 (self.init)(desc)
31 }
32}
33
34pub struct UntypedVTable {
36 pub(crate) name: &'static str,
37 pub(crate) drop: unsafe fn(*mut u8),
38 pub(crate) layout: Layout,
39 pub(crate) type_id: fn() -> TypeId,
40 pub(crate) type_name: fn() -> &'static str,
41 pub(crate) dangling: fn() -> NonNull<u8>,
44 pub(crate) meta: LazyComponentBuffer,
47}
48
49impl UntypedVTable {
50 pub fn is<T: ComponentValue>(&self) -> bool {
52 (self.type_id)() == TypeId::of::<T>()
53 }
54
55 pub(crate) const fn new<T: ComponentValue>(
57 name: &'static str,
58 meta: LazyComponentBuffer,
59 ) -> Self {
60 unsafe fn drop_ptr<T>(x: *mut u8) {
61 x.cast::<T>().drop_in_place()
62 }
63
64 UntypedVTable {
65 name,
66 drop: drop_ptr::<T>,
67 layout: Layout::new::<T>(),
68 type_id: || TypeId::of::<T>(),
69 type_name: || core::any::type_name::<T>(),
70 meta,
71 dangling: || NonNull::<T>::dangling().cast(),
72 }
73 }
74}
75
76#[repr(transparent)]
78pub struct ComponentVTable<T> {
79 inner: UntypedVTable,
80 marker: PhantomData<T>,
81}
82
83impl<T> core::fmt::Debug for ComponentVTable<T> {
84 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
85 f.debug_struct("ComponentVTable")
86 .field("name", &self.inner.name)
87 .field("type_name", &self.inner.type_name)
88 .finish()
89 }
90}
91
92impl<T> core::ops::Deref for ComponentVTable<T> {
93 type Target = UntypedVTable;
94
95 fn deref(&self) -> &Self::Target {
96 &self.inner
97 }
98}
99
100impl<T: ComponentValue> ComponentVTable<T> {
101 pub const fn new(name: &'static str, meta: LazyComponentBuffer) -> Self {
103 Self {
104 inner: UntypedVTable::new::<T>(name, meta),
105 marker: PhantomData,
106 }
107 }
108
109 pub(crate) fn erase(&self) -> &'static UntypedVTable {
110 unsafe { mem::transmute(self) }
111 }
112}