1use crate::{self as stabby, fatptr::AnonymRefMut};
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<'vt_lt> {
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(AnonymRefMut<'_>), 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() }
368 as *const unsafe extern "C" fn(AnonymRefMut<'_>),
369 unsafe { other.drop.as_ref_unchecked() }
370 as *const unsafe extern "C" fn(AnonymRefMut<'_>),
371 )
372 }
373}
374unsafe extern "C" fn drop<T>(this: AnonymRefMut<'_>) {
375 core::ptr::drop_in_place(unsafe { this.cast::<T>().as_mut() })
376}
377#[allow(unknown_lints)]
378#[allow(clippy::missing_transmute_annotations, clippy::needless_lifetimes)]
379impl<'a, T> IConstConstructor<'a, T> for VtDrop {
380 impl_vtable_constructor!(
381 const VTABLE_REF: &'a VtDrop = &VtDrop {
382 drop: unsafe {
383 core::mem::transmute(drop::<T> as unsafe extern "C" fn(AnonymRefMut<'_>))
384 },
385 }; =>
386 const VTABLE: VtDrop = VtDrop {
387 drop: unsafe {
388 core::mem::transmute(drop::<T> as unsafe extern "C" fn(AnonymRefMut<'_>))
389 },
390 };
391 );
392}
393
394#[stabby::stabby]
396#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
397pub struct VtSend<T>(pub T);
398impl<'a> CompoundVt<'a> for dyn Send {
399 type Vt<T> = VtSend<T>;
400}
401impl<Tail: TransitiveDeref<Vt, N>, Vt, N> TransitiveDeref<Vt, N> for VtSend<Tail> {
402 fn tderef(&self) -> &Vt {
403 self.0.tderef()
404 }
405}
406impl<Head, Tail> From<crate::vtable::VtSend<VTable<Head, Tail>>> for VTable<Head, Tail> {
407 fn from(value: VtSend<VTable<Head, Tail>>) -> Self {
408 value.0
409 }
410}
411impl<'a, T: Send, Vt: IConstConstructor<'a, T>> IConstConstructor<'a, T> for VtSend<Vt> {
412 impl_vtable_constructor!(
413 const VTABLE_REF: &'a VtSend<Vt> = &VtSend(*Vt::VTABLE_REF);=>
414 const VTABLE: VtSend<Vt> = VtSend(Vt::VTABLE);
415 );
416}
417
418#[stabby::stabby]
420#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
421pub struct VtSync<T>(pub T);
422impl<'a> CompoundVt<'a> for dyn Sync {
423 type Vt<T> = VtSync<T>;
424}
425impl<'a, T: Sync, Vt: IConstConstructor<'a, T>> IConstConstructor<'a, T> for VtSync<Vt> {
426 impl_vtable_constructor!(
427 const VTABLE_REF: &'a VtSync<Vt> = &VtSync(*Vt::VTABLE_REF);=>
428 const VTABLE: VtSync<Vt> = VtSync(Vt::VTABLE);
429 );
430}
431impl<Tail: TransitiveDeref<Vt, N>, Vt, N> TransitiveDeref<Vt, N> for VtSync<Tail> {
432 fn tderef(&self) -> &Vt {
433 self.0.tderef()
434 }
435}
436impl<Head, Tail> From<crate::vtable::VtSync<VtSend<VTable<Head, Tail>>>> for VTable<Head, Tail> {
437 fn from(value: VtSync<VtSend<VTable<Head, Tail>>>) -> Self {
438 value.0 .0
439 }
440}
441impl<Head, Tail> From<crate::vtable::VtSync<VtSend<VTable<Head, Tail>>>>
442 for VtSend<VTable<Head, Tail>>
443{
444 fn from(value: VtSync<VtSend<VTable<Head, Tail>>>) -> Self {
445 value.0
446 }
447}
448impl<Head, Tail> From<crate::vtable::VtSync<VTable<Head, Tail>>> for VTable<Head, Tail> {
449 fn from(value: VtSync<VTable<Head, Tail>>) -> Self {
450 value.0
451 }
452}
453
454#[stabby::stabby]
456pub trait Any {
457 extern "C" fn report(&self) -> &'static crate::report::TypeReport;
459 extern "C" fn id(&self) -> u64;
461}
462impl<T: crate::IStable> Any for T {
463 extern "C" fn report(&self) -> &'static crate::report::TypeReport {
464 Self::REPORT
465 }
466 extern "C" fn id(&self) -> u64 {
467 Self::ID
468 }
469}