1use crate::{self as stabby};
16use core::hash::Hash;
17
18#[rustversion::nightly]
19pub trait IConstConstructor<'a, Source>: 'a + Copy + core::marker::Freeze {
22 const VTABLE: Self;
24 const VTABLE_REF: &'a Self = &Self::VTABLE;
26 fn vtable() -> &'a Self {
28 Self::VTABLE_REF
29 }
30}
31
32#[rustversion::before(1.78.0)]
33pub trait IConstConstructor<'a, Source>: 'a + Copy {
36 const VTABLE_REF: &'a Self;
38 fn vtable() -> &'a Self {
40 Self::VTABLE_REF
41 }
42}
43
44#[cfg(all(not(stabby_default_alloc = "disabled"), feature = "test"))]
45pub use internal::{VTableRegistry, VtBtree, VtVec};
46
47#[cfg(not(stabby_default_alloc = "disabled"))]
48pub(crate) mod internal {
49 use crate::alloc::{boxed::BoxedSlice, collections::arc_btree::AtomicArcBTreeSet};
50 use core::ptr::NonNull;
51 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
52 pub struct VTable(&'static [*const ()]);
53 impl PartialOrd<&[*const ()]> for VTable {
54 fn partial_cmp(&self, other: &&[*const ()]) -> Option<core::cmp::Ordering> {
55 Some(self.0.cmp(*other))
56 }
57 }
58 impl PartialEq<&[*const ()]> for VTable {
59 fn eq(&self, other: &&[*const ()]) -> bool {
60 self.0.eq(*other)
61 }
62 }
63 unsafe impl Send for VTable {}
65 unsafe impl Sync for VTable {}
67 use crate::alloc::{vec::Vec, DefaultAllocator};
68 pub type VtBtree<const SIZE: usize> = AtomicArcBTreeSet<VTable, false, SIZE>;
72 pub type VtVec =
76 crate::alloc::sync::AtomicArc<crate::alloc::vec::Vec<VTable>, DefaultAllocator>;
77 pub trait VTableRegistry {
81 fn insert(&self, vtable: &[*const ()]) -> NonNull<*const ()>;
83 fn insert_typed<'a, Vt: Copy>(&self, vtable: &Vt) -> &'a Vt {
85 unsafe {
86 let vtable = core::slice::from_raw_parts(
87 (vtable as *const Vt).cast(),
88 core::mem::size_of::<Vt>() / core::mem::size_of::<*const ()>(),
89 );
90 let vt = self.insert(vtable).cast().as_ref();
91 debug_assert_eq!(
92 core::slice::from_raw_parts(
93 (vt as *const Vt).cast::<*const ()>(),
94 core::mem::size_of::<Vt>() / core::mem::size_of::<*const ()>(),
95 ),
96 vtable
97 );
98 vt
99 }
100 }
101 }
102 impl VTableRegistry for VtVec {
103 fn insert(&self, vtable: &[*const ()]) -> NonNull<*const ()> {
104 let mut search_start = 0;
105 let mut allocated_slice: Option<BoxedSlice<_, DefaultAllocator>> = None;
106 let mut vtables = self.load(core::sync::atomic::Ordering::SeqCst);
107 loop {
108 let vts = match vtables.as_ref() {
109 None => [].as_slice(),
110 Some(vts) => match vts[search_start..].iter().find(|e| **e == vtable) {
111 Some(vt) => {
112 return unsafe { NonNull::new_unchecked(vt.0.as_ptr().cast_mut()) };
114 }
115 None => vts,
116 },
117 };
118 let avt = allocated_slice.unwrap_or_else(|| BoxedSlice::from(vtable));
119 let vt = unsafe { core::mem::transmute::<&[_], &'static [_]>(avt.as_slice()) };
121 allocated_slice = Some(avt);
122 if let Err(updated) =
123 self.is(vtables.as_ref(), core::sync::atomic::Ordering::SeqCst)
124 {
125 vtables = updated;
126 continue;
127 }
128 let mut vec = Vec::with_capacity(vts.len() + 1);
129 vec.copy_extend(vts);
130 vec.push(VTable(vt));
131 if let Err(updated) =
132 self.is(vtables.as_ref(), core::sync::atomic::Ordering::SeqCst)
133 {
134 vtables = updated;
135 continue;
136 }
137 let vec = Some(crate::alloc::sync::Arc::new(vec));
138 match self.compare_exchange(
139 vtables.as_ref(),
140 vec,
141 core::sync::atomic::Ordering::SeqCst,
142 core::sync::atomic::Ordering::SeqCst,
143 ) {
144 Ok(_) => {
145 core::mem::forget(allocated_slice);
146 return unsafe { NonNull::new_unchecked(vt.as_ptr().cast_mut()) };
147 }
148 Err(new_vtables) => {
149 search_start = vts.len();
150 vtables = new_vtables;
151 }
152 }
153 }
154 }
155 }
156 #[allow(unknown_lints)]
157 #[allow(clippy::missing_transmute_annotations)]
158 impl<const SIZE: usize> VTableRegistry for VtBtree<SIZE> {
159 fn insert(&self, vtable: &[*const ()]) -> NonNull<*const ()> {
160 let mut ret = None;
161 let mut allocated_slice: Option<BoxedSlice<_, DefaultAllocator>> = None;
162 self.edit(|tree| {
163 let mut tree = tree.clone();
164 if let Some(vt) = tree.get(&vtable) {
165 ret = unsafe { Some(NonNull::new_unchecked(vt.0.as_ptr().cast_mut())) };
166 return tree;
167 }
168 let vt = match &allocated_slice {
169 Some(vt) => unsafe { core::mem::transmute(vt.as_slice()) },
170 None => {
171 let vt = BoxedSlice::from(vtable);
172 let slice = unsafe { core::mem::transmute(vt.as_slice()) };
173 allocated_slice = Some(vt);
174 slice
175 }
176 };
177 tree.insert(vt);
178 tree
179 });
180 if ret.is_none() {
181 let ret = &mut ret;
182 self.get(&vtable, move |vt| {
183 let start = unsafe {
184 NonNull::new_unchecked(
185 vt.expect("VTable should've been inserted by now")
186 .0
187 .as_ptr()
188 .cast_mut(),
189 )
190 };
191 if let Some(allocated) = allocated_slice {
192 if allocated.slice.start.ptr == start {
193 core::mem::forget(allocated);
194 }
195 }
196 *ret = Some(start);
197 });
198 }
199 unsafe { ret.unwrap_unchecked() }
200 }
201 }
202 #[cfg(stabby_vtables = "vec")]
203 #[rustversion::all(not(nightly), since(1.78.0))]
204 pub(crate) static VTABLES: crate::alloc::sync::AtomicArc<
205 crate::alloc::vec::Vec<VTable>,
206 DefaultAllocator,
207 > = crate::alloc::sync::AtomicArc::new(None);
208 #[cfg(any(stabby_vtables = "btree", not(stabby_vtables)))]
209 #[rustversion::all(not(nightly), since(1.78.0))]
210 pub(crate) static VTABLES: AtomicArcBTreeSet<VTable, false, 5> = AtomicArcBTreeSet::new();
211 #[rustversion::nightly]
212 #[cfg(stabby_vtables = "btree")]
213 pub(crate) static VTABLES: AtomicArcBTreeSet<VTable, false, 5> = AtomicArcBTreeSet::new();
214}
215
216#[cfg(all(
217 not(stabby_default_alloc = "disabled"),
218 any(stabby_vtables = "vec", stabby_vtables = "btree", not(stabby_vtables))
219))]
220#[rustversion::all(not(nightly), since(1.78.0))]
221pub trait IConstConstructor<'a, Source>: 'a + Copy {
224 const VTABLE: Self;
226 fn vtable() -> &'a Self {
228 use internal::VTableRegistry;
229 internal::VTABLES.insert_typed(&Self::VTABLE)
230 }
231}
232#[cfg(not(all(
233 not(stabby_default_alloc = "disabled"),
234 any(stabby_vtables = "vec", stabby_vtables = "btree", not(stabby_vtables))
235)))]
236#[rustversion::all(not(nightly), since(1.78.0))]
237pub trait IConstConstructor<'a, Source>: 'a + Copy {
240 const VTABLE: Self;
242 fn vtable() -> &'a Self {
244 core::compile_error!("stabby's dyn traits need an allocator for non-nightly versions of Rust starting `1.78.0` and until https://github.com/rust-lang/rfcs/pull/3633 lands in stable.")
245 }
246}
247pub trait TransitiveDeref<Head, N> {
249 fn tderef(&self) -> &Head;
251}
252pub struct H;
254pub struct T<T>(T);
256#[stabby::stabby]
260#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
261pub struct VTable<Head, Tail = VtDrop> {
262 pub tail: Tail,
266 pub head: Head,
268}
269
270pub trait CompoundVt {
272 type Vt<T>;
274}
275
276impl<'a, T, Head: Copy + 'a, Tail: Copy + 'a> IConstConstructor<'a, T> for VTable<Head, Tail>
277where
278 Head: IConstConstructor<'a, T>,
279 Tail: IConstConstructor<'a, T>,
280{
281 impl_vtable_constructor!(
282 const VTABLE_REF: &'a VTable<Head, Tail> = &VTable {
283 head: *Head::VTABLE_REF,
284 tail: *Tail::VTABLE_REF,
285 }; =>
286 const VTABLE: VTable<Head, Tail> = VTable {
287 head: Head::VTABLE,
288 tail: Tail::VTABLE,
289 };
290 );
291}
292#[allow(clippy::needless_lifetimes)]
293impl<'a, T> IConstConstructor<'a, T> for () {
294 impl_vtable_constructor!(
295 const VTABLE_REF: &'a () = &();=>
296 const VTABLE: () = (););
297}
298impl<Head, Tail> TransitiveDeref<Head, H> for VTable<Head, Tail> {
299 fn tderef(&self) -> &Head {
300 &self.head
301 }
302}
303impl<Head, Tail: TransitiveDeref<Vt, N>, Vt, N> TransitiveDeref<Vt, T<N>> for VTable<Head, Tail> {
304 fn tderef(&self) -> &Vt {
305 self.tail.tderef()
306 }
307}
308
309pub trait HasDropVt {
311 fn drop_vt(&self) -> &VtDrop;
313}
314impl HasDropVt for VtDrop {
315 fn drop_vt(&self) -> &VtDrop {
316 self
317 }
318}
319impl<Head, Tail: HasDropVt> HasDropVt for VTable<Head, Tail> {
320 fn drop_vt(&self) -> &VtDrop {
321 self.tail.drop_vt()
322 }
323}
324impl<T: HasDropVt> HasDropVt for VtSend<T> {
325 fn drop_vt(&self) -> &VtDrop {
326 self.0.drop_vt()
327 }
328}
329impl<T: HasDropVt> HasDropVt for VtSync<T> {
330 fn drop_vt(&self) -> &VtDrop {
331 self.0.drop_vt()
332 }
333}
334
335pub trait HasSendVt {}
337impl<T> HasSendVt for VtSend<T> {}
338impl<T: HasSendVt> HasSendVt for VtSync<T> {}
339impl<Head, Tail: HasSyncVt> HasSendVt for VTable<Head, Tail> {}
340pub trait HasSyncVt {}
342impl<T> HasSyncVt for VtSync<T> {}
343impl<T: HasSyncVt> HasSyncVt for VtSend<T> {}
344impl<Head, Tail: HasSyncVt> HasSyncVt for VTable<Head, Tail> {}
345
346#[stabby::stabby]
349#[derive(Clone, Copy, Eq)]
350pub struct VtDrop {
351 pub drop: crate::StableLike<unsafe extern "C" fn(&mut ()), core::num::NonZeroUsize>,
353}
354impl core::fmt::Debug for VtDrop {
355 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
356 write!(f, "VtDrop({:p})", unsafe { self.drop.as_ref_unchecked() })
357 }
358}
359impl Hash for VtDrop {
360 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
361 self.drop.hash(state)
362 }
363}
364impl PartialEq for VtDrop {
365 fn eq(&self, other: &Self) -> bool {
366 core::ptr::eq(
367 unsafe { self.drop.as_ref_unchecked() } as *const unsafe extern "C" fn(&mut ()),
368 unsafe { other.drop.as_ref_unchecked() } as *const unsafe extern "C" fn(&mut ()),
369 )
370 }
371}
372unsafe extern "C" fn drop<T>(this: &mut T) {
373 core::ptr::drop_in_place(this)
374}
375#[allow(unknown_lints)]
376#[allow(clippy::missing_transmute_annotations, clippy::needless_lifetimes)]
377impl<'a, T> IConstConstructor<'a, T> for VtDrop {
378 impl_vtable_constructor!(
379 const VTABLE_REF: &'a VtDrop = &VtDrop {
380 drop: unsafe {
381 core::mem::transmute(drop::<T> as unsafe extern "C" fn(&mut T))
382 },
383 }; =>
384 const VTABLE: VtDrop = VtDrop {
385 drop: unsafe {
386 core::mem::transmute(drop::<T> as unsafe extern "C" fn(&mut T))
387 },
388 };
389 );
390}
391
392#[stabby::stabby]
394#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
395pub struct VtSend<T>(pub T);
396impl CompoundVt for dyn Send {
397 type Vt<T> = VtSend<T>;
398}
399impl<Tail: TransitiveDeref<Vt, N>, Vt, N> TransitiveDeref<Vt, N> for VtSend<Tail> {
400 fn tderef(&self) -> &Vt {
401 self.0.tderef()
402 }
403}
404impl<Head, Tail> From<crate::vtable::VtSend<VTable<Head, Tail>>> for VTable<Head, Tail> {
405 fn from(value: VtSend<VTable<Head, Tail>>) -> Self {
406 value.0
407 }
408}
409impl<'a, T: Send, Vt: IConstConstructor<'a, T>> IConstConstructor<'a, T> for VtSend<Vt> {
410 impl_vtable_constructor!(
411 const VTABLE_REF: &'a VtSend<Vt> = &VtSend(*Vt::VTABLE_REF);=>
412 const VTABLE: VtSend<Vt> = VtSend(Vt::VTABLE);
413 );
414}
415
416#[stabby::stabby]
418#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
419pub struct VtSync<T>(pub T);
420impl CompoundVt for dyn Sync {
421 type Vt<T> = VtSync<T>;
422}
423impl<'a, T: Sync, Vt: IConstConstructor<'a, T>> IConstConstructor<'a, T> for VtSync<Vt> {
424 impl_vtable_constructor!(
425 const VTABLE_REF: &'a VtSync<Vt> = &VtSync(*Vt::VTABLE_REF);=>
426 const VTABLE: VtSync<Vt> = VtSync(Vt::VTABLE);
427 );
428}
429impl<Tail: TransitiveDeref<Vt, N>, Vt, N> TransitiveDeref<Vt, N> for VtSync<Tail> {
430 fn tderef(&self) -> &Vt {
431 self.0.tderef()
432 }
433}
434impl<Head, Tail> From<crate::vtable::VtSync<VtSend<VTable<Head, Tail>>>> for VTable<Head, Tail> {
435 fn from(value: VtSync<VtSend<VTable<Head, Tail>>>) -> Self {
436 value.0 .0
437 }
438}
439impl<Head, Tail> From<crate::vtable::VtSync<VtSend<VTable<Head, Tail>>>>
440 for VtSend<VTable<Head, Tail>>
441{
442 fn from(value: VtSync<VtSend<VTable<Head, Tail>>>) -> Self {
443 value.0
444 }
445}
446impl<Head, Tail> From<crate::vtable::VtSync<VTable<Head, Tail>>> for VTable<Head, Tail> {
447 fn from(value: VtSync<VTable<Head, Tail>>) -> Self {
448 value.0
449 }
450}
451
452#[stabby::stabby]
454pub trait Any {
455 extern "C" fn report(&self) -> &'static crate::report::TypeReport;
457 extern "C" fn id(&self) -> u64;
459}
460impl<T: crate::IStable> Any for T {
461 extern "C" fn report(&self) -> &'static crate::report::TypeReport {
462 Self::REPORT
463 }
464 extern "C" fn id(&self) -> u64 {
465 Self::ID
466 }
467}