dungeon_cell/vtable/
static_vtable.rs1use core::any::TypeId;
2use core::fmt;
3
4use crate::bound::{Dynamic, Subset};
5use crate::marker_traits::IsBound;
6
7use super::{
8 BoundsImpl, ConstVTableOf, Descriptor, Inspect, VTable, VTableOf,
9 VTableSubset,
10};
11
12#[derive(Clone)]
39#[repr(C)]
40pub struct StaticVTable<B> {
41 bound_impl: BoundsImpl<B>,
42 descriptor: Descriptor<Static>,
43}
44
45impl<B> fmt::Debug for StaticVTable<B> {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 f.debug_struct("StaticVTable")
48 .field("type_name", &self.descriptor.type_name())
49 .field("type_id", &self.descriptor.id().0)
50 .field("size", &self.descriptor.size)
51 .field("alignment", &self.descriptor.alignment)
52 .finish()
53 }
54}
55
56impl<B: IsBound> StaticVTable<B> {
57 pub const fn new<T: 'static>() -> Self
59 where
60 T: Dynamic<B>,
61 {
62 <Self as ConstVTableOf<T>>::INSTANCE
63 }
64}
65
66#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug)]
80pub struct Static(TypeId);
81
82unsafe impl<T: 'static> Inspect<Static> for T {
84 fn inspect() -> Static {
85 Static(TypeId::of::<T>())
86 }
87}
88
89unsafe impl<B: IsBound> VTable for StaticVTable<B> {
93 type Bounds = B;
94
95 type Id = Static;
96
97 fn descriptor(&self) -> &super::Descriptor<Self::Id> {
98 &self.descriptor
99 }
100
101 fn bound_impl(&self) -> &BoundsImpl<Self::Bounds> {
102 &self.bound_impl
103 }
104}
105
106unsafe impl<B: IsBound, Bnew: IsBound> VTableSubset<Bnew> for StaticVTable<B>
108where
109 Bnew: Subset<B>,
110{
111 type Subset = StaticVTable<Bnew>;
112
113 fn into_subset(self) -> Self::Subset {
114 StaticVTable {
115 bound_impl: self.bound_impl.into_subset::<Bnew>(),
116 descriptor: self.descriptor,
117 }
118 }
119}
120
121unsafe impl<'a, B: IsBound, Bnew: IsBound> VTableSubset<Bnew>
123 for &'a StaticVTable<B>
124where
125 Bnew: Subset<B>,
126{
127 type Subset = &'a StaticVTable<Bnew>;
128
129 fn into_subset(self) -> Self::Subset {
130 unsafe {
134 &*(self as *const StaticVTable<B> as *const StaticVTable<Bnew>)
135 }
136 }
137}
138
139unsafe impl<T: 'static, B: IsBound> VTableOf<T> for StaticVTable<B>
141where
142 T: Dynamic<B>,
143{
144 fn instance() -> Self {
145 Self::new::<T>()
146 }
147}
148
149unsafe impl<T: 'static, B: IsBound> ConstVTableOf<T> for StaticVTable<B>
151where
152 T: Dynamic<B>,
153{
154 const INSTANCE: Self = Self {
155 descriptor: Descriptor::new::<T>(),
156 bound_impl: BoundsImpl::new::<T>(),
157 };
158}
159
160unsafe impl<'a, T: 'static, B: IsBound> VTableOf<T> for &'a StaticVTable<B>
162where
163 T: Dynamic<B>,
164{
165 fn instance() -> Self {
166 &ConstVTableOf::<T>::INSTANCE
167 }
168}
169
170unsafe impl<'a, T: 'static, B: IsBound> ConstVTableOf<T> for &'a StaticVTable<B>
172where
173 T: Dynamic<B>,
174{
175 const INSTANCE: Self = &ConstVTableOf::<T>::INSTANCE;
176}
177
178#[cfg(test)]
179mod test {
180 use core::mem::MaybeUninit;
181 use core::sync::atomic::AtomicBool;
182
183 use crate::bound::bounds;
184
185 use super::*;
186
187 #[test]
188 fn has_debug() {
189 let _ = format!("{:?}", StaticVTable::<bounds::Normal>::new::<i32>());
190 }
191
192 #[test]
193 fn can_drop_a_t() {
194 static Y: AtomicBool = AtomicBool::new(false);
195
196 struct X {
197 a: i32,
198 }
199
200 impl Drop for X {
201 fn drop(&mut self) {
202 assert_eq!(self.a, 123);
203
204 Y.store(true, core::sync::atomic::Ordering::Relaxed);
205 }
206 }
207
208 let v = StaticVTable::<bounds::Empty>::new::<X>();
209
210 let mut x = MaybeUninit::new(X { a: 123 });
211
212 unsafe { v.bound_impl().drop_value(x.as_mut_ptr() as _) };
213
214 assert!(Y.load(core::sync::atomic::Ordering::Relaxed));
215 }
216
217 #[test]
218 fn vtable_interface() {
219 fn assert_for<T: 'static>() {
220 let v = StaticVTable::<bounds::Empty>::new::<T>();
221
222 assert_eq!(v.descriptor().size(), core::mem::size_of::<T>());
223 assert_eq!(v.descriptor().alignment(), core::mem::align_of::<T>());
224 let _ = v.descriptor().type_name();
226
227 let _ = <StaticVTable<bounds::Empty> as VTableOf<T>>::instance();
228 let _ = <&StaticVTable<bounds::Empty> as VTableOf<T>>::instance();
229
230 let _ = <StaticVTable<bounds::Empty> as ConstVTableOf<T>>::INSTANCE;
231 let _ =
232 <&StaticVTable<bounds::Empty> as ConstVTableOf<T>>::INSTANCE;
233 }
234
235 assert_for::<i32>();
236 assert_for::<String>();
237 assert_for::<()>();
238 assert_for::<u8>();
239 assert_for::<[i32; 100]>();
240 }
241}