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>().div_euclid(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>().div_euclid(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
111 .get(search_start..)
112 .unwrap_or(&[])
113 .iter()
114 .find(|e| **e == vtable)
115 {
116 Some(vt) => {
117 return unsafe { NonNull::new_unchecked(vt.0.as_ptr().cast_mut()) };
119 }
120 None => vts,
121 },
122 };
123 let avt = allocated_slice.unwrap_or_else(|| BoxedSlice::from(vtable));
124 let vt = unsafe { core::mem::transmute::<&[_], &'static [_]>(avt.as_slice()) };
126 allocated_slice = Some(avt);
127 if let Err(updated) =
128 self.is(vtables.as_ref(), core::sync::atomic::Ordering::SeqCst)
129 {
130 vtables = updated;
131 continue;
132 }
133 let mut vec = Vec::with_capacity(vts.len().wrapping_add(1));
134 vec.copy_extend(vts);
135 vec.push(VTable(vt));
136 if let Err(updated) =
137 self.is(vtables.as_ref(), core::sync::atomic::Ordering::SeqCst)
138 {
139 vtables = updated;
140 continue;
141 }
142 let vec = Some(crate::alloc::sync::Arc::new(vec));
143 match self.compare_exchange(
144 vtables.as_ref(),
145 vec,
146 core::sync::atomic::Ordering::SeqCst,
147 core::sync::atomic::Ordering::SeqCst,
148 ) {
149 Ok(_) => {
150 core::mem::forget(allocated_slice);
151 return unsafe { NonNull::new_unchecked(vt.as_ptr().cast_mut()) };
152 }
153 Err(new_vtables) => {
154 search_start = vts.len();
155 vtables = new_vtables;
156 }
157 }
158 }
159 }
160 }
161 #[allow(unknown_lints)]
162 #[allow(clippy::missing_transmute_annotations)]
163 impl<const SIZE: usize> VTableRegistry for VtBtree<SIZE> {
164 fn insert(&self, vtable: &[*const ()]) -> NonNull<*const ()> {
165 let mut ret = None;
166 let mut allocated_slice: Option<BoxedSlice<_, DefaultAllocator>> = None;
167 self.edit(|tree| {
168 let mut tree = tree.clone();
169 if let Some(vt) = tree.get(&vtable) {
170 ret = unsafe { Some(NonNull::new_unchecked(vt.0.as_ptr().cast_mut())) };
171 return tree;
172 }
173 let vt = match &allocated_slice {
174 Some(vt) => unsafe { core::mem::transmute(vt.as_slice()) },
175 None => {
176 let vt = BoxedSlice::from(vtable);
177 let slice = unsafe { core::mem::transmute(vt.as_slice()) };
178 allocated_slice = Some(vt);
179 slice
180 }
181 };
182 tree.insert(vt);
183 tree
184 });
185 if ret.is_none() {
186 let ret = &mut ret;
187 self.get(&vtable, move |vt| {
188 let start = unsafe {
189 NonNull::new_unchecked(
190 vt.expect("VTable should've been inserted by now")
191 .0
192 .as_ptr()
193 .cast_mut(),
194 )
195 };
196 if let Some(allocated) = allocated_slice {
197 if allocated.slice.start.ptr == start {
198 core::mem::forget(allocated);
199 }
200 }
201 *ret = Some(start);
202 });
203 }
204 unsafe { ret.unwrap_unchecked() }
205 }
206 }
207 #[cfg(stabby_vtables = "vec")]
208 #[rustversion::all(not(nightly), since(1.78.0))]
209 pub(crate) static VTABLES: crate::alloc::sync::AtomicArc<
210 crate::alloc::vec::Vec<VTable>,
211 DefaultAllocator,
212 > = crate::alloc::sync::AtomicArc::new(None);
213 #[cfg(any(stabby_vtables = "btree", not(stabby_vtables)))]
214 #[rustversion::all(not(nightly), since(1.78.0))]
215 pub(crate) static VTABLES: AtomicArcBTreeSet<VTable, false, 5> = AtomicArcBTreeSet::new();
216 #[rustversion::nightly]
217 #[cfg(stabby_vtables = "btree")]
218 pub(crate) static VTABLES: AtomicArcBTreeSet<VTable, false, 5> = AtomicArcBTreeSet::new();
219}
220
221#[cfg(all(
222 not(stabby_default_alloc = "disabled"),
223 any(stabby_vtables = "vec", stabby_vtables = "btree", not(stabby_vtables))
224))]
225#[rustversion::all(not(nightly), since(1.78.0))]
226pub trait IConstConstructor<'a, Source>: 'a + Copy {
229 const VTABLE: Self;
231 fn vtable() -> &'a Self {
233 use internal::VTableRegistry;
234 internal::VTABLES.insert_typed(&Self::VTABLE)
235 }
236}
237#[cfg(not(all(
238 not(stabby_default_alloc = "disabled"),
239 any(stabby_vtables = "vec", stabby_vtables = "btree", not(stabby_vtables))
240)))]
241#[rustversion::all(not(nightly), since(1.78.0))]
242pub trait IConstConstructor<'a, Source>: 'a + Copy {
245 const VTABLE: Self;
247 fn vtable() -> &'a Self {
249 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.")
250 }
251}
252pub trait TransitiveDeref<Head, N> {
254 fn tderef(&self) -> &Head;
256}
257pub struct H;
259pub struct T<T>(T);
261#[stabby::stabby]
265#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
266pub struct VTable<Head, Tail = VtDrop> {
267 pub tail: Tail,
271 pub head: Head,
273}
274
275pub trait CompoundVt<'vt_lt> {
277 type Vt<T>;
279}
280
281impl<'a, T, Head: Copy + 'a, Tail: Copy + 'a> IConstConstructor<'a, T> for VTable<Head, Tail>
282where
283 Head: IConstConstructor<'a, T>,
284 Tail: IConstConstructor<'a, T>,
285{
286 impl_vtable_constructor!(
287 const VTABLE_REF: &'a VTable<Head, Tail> = &VTable {
288 head: *Head::VTABLE_REF,
289 tail: *Tail::VTABLE_REF,
290 }; =>
291 const VTABLE: VTable<Head, Tail> = VTable {
292 head: Head::VTABLE,
293 tail: Tail::VTABLE,
294 };
295 );
296}
297#[allow(clippy::needless_lifetimes)]
298impl<'a, T> IConstConstructor<'a, T> for () {
299 impl_vtable_constructor!(
300 const VTABLE_REF: &'a () = &();=>
301 const VTABLE: () = (););
302}
303impl<Head, Tail> TransitiveDeref<Head, H> for VTable<Head, Tail> {
304 fn tderef(&self) -> &Head {
305 &self.head
306 }
307}
308impl<Head, Tail: TransitiveDeref<Vt, N>, Vt, N> TransitiveDeref<Vt, T<N>> for VTable<Head, Tail> {
309 fn tderef(&self) -> &Vt {
310 self.tail.tderef()
311 }
312}
313
314pub trait HasDropVt {
316 fn drop_vt(&self) -> &VtDrop;
318}
319impl HasDropVt for VtDrop {
320 fn drop_vt(&self) -> &VtDrop {
321 self
322 }
323}
324impl<Head, Tail: HasDropVt> HasDropVt for VTable<Head, Tail> {
325 fn drop_vt(&self) -> &VtDrop {
326 self.tail.drop_vt()
327 }
328}
329impl<T: HasDropVt> HasDropVt for VtSend<T> {
330 fn drop_vt(&self) -> &VtDrop {
331 self.0.drop_vt()
332 }
333}
334impl<T: HasDropVt> HasDropVt for VtSync<T> {
335 fn drop_vt(&self) -> &VtDrop {
336 self.0.drop_vt()
337 }
338}
339
340pub trait HasSendVt {}
342impl<T> HasSendVt for VtSend<T> {}
343impl<T: HasSendVt> HasSendVt for VtSync<T> {}
344impl<Head, Tail: HasSyncVt> HasSendVt for VTable<Head, Tail> {}
345pub trait HasSyncVt {}
347impl<T> HasSyncVt for VtSync<T> {}
348impl<T: HasSyncVt> HasSyncVt for VtSend<T> {}
349impl<Head, Tail: HasSyncVt> HasSyncVt for VTable<Head, Tail> {}
350
351#[stabby::stabby]
354#[derive(Clone, Copy, Eq)]
355pub struct VtDrop {
356 pub drop: crate::StableLike<unsafe extern "C" fn(AnonymRefMut<'_>), core::num::NonZeroUsize>,
358}
359impl core::fmt::Debug for VtDrop {
360 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
361 write!(f, "VtDrop({:p})", unsafe { self.drop.as_ref_unchecked() })
362 }
363}
364impl Hash for VtDrop {
365 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
366 self.drop.hash(state)
367 }
368}
369impl PartialEq for VtDrop {
370 fn eq(&self, other: &Self) -> bool {
371 core::ptr::eq(
372 unsafe { self.drop.as_ref_unchecked() }
373 as *const unsafe extern "C" fn(AnonymRefMut<'_>),
374 unsafe { other.drop.as_ref_unchecked() }
375 as *const unsafe extern "C" fn(AnonymRefMut<'_>),
376 )
377 }
378}
379unsafe extern "C" fn drop<T>(this: AnonymRefMut<'_>) {
380 core::ptr::drop_in_place(unsafe { this.cast::<T>().as_mut() })
381}
382#[allow(unknown_lints)]
383#[allow(clippy::missing_transmute_annotations, clippy::needless_lifetimes)]
384impl<'a, T> IConstConstructor<'a, T> for VtDrop {
385 impl_vtable_constructor!(
386 const VTABLE_REF: &'a VtDrop = &VtDrop {
387 drop: unsafe {
388 core::mem::transmute(drop::<T> as unsafe extern "C" fn(AnonymRefMut<'_>))
389 },
390 }; =>
391 const VTABLE: VtDrop = VtDrop {
392 drop: unsafe {
393 core::mem::transmute(drop::<T> as unsafe extern "C" fn(AnonymRefMut<'_>))
394 },
395 };
396 );
397}
398
399#[stabby::stabby]
401#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
402pub struct VtSend<T>(pub T);
403impl<'a> CompoundVt<'a> for dyn Send {
404 type Vt<T> = VtSend<T>;
405}
406impl<Tail: TransitiveDeref<Vt, N>, Vt, N> TransitiveDeref<Vt, N> for VtSend<Tail> {
407 fn tderef(&self) -> &Vt {
408 self.0.tderef()
409 }
410}
411impl<Head, Tail> From<crate::vtable::VtSend<VTable<Head, Tail>>> for VTable<Head, Tail> {
412 fn from(value: VtSend<VTable<Head, Tail>>) -> Self {
413 value.0
414 }
415}
416impl<'a, T: Send, Vt: IConstConstructor<'a, T>> IConstConstructor<'a, T> for VtSend<Vt> {
417 impl_vtable_constructor!(
418 const VTABLE_REF: &'a VtSend<Vt> = &VtSend(*Vt::VTABLE_REF);=>
419 const VTABLE: VtSend<Vt> = VtSend(Vt::VTABLE);
420 );
421}
422
423#[stabby::stabby]
425#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
426pub struct VtSync<T>(pub T);
427impl<'a> CompoundVt<'a> for dyn Sync {
428 type Vt<T> = VtSync<T>;
429}
430impl<'a, T: Sync, Vt: IConstConstructor<'a, T>> IConstConstructor<'a, T> for VtSync<Vt> {
431 impl_vtable_constructor!(
432 const VTABLE_REF: &'a VtSync<Vt> = &VtSync(*Vt::VTABLE_REF);=>
433 const VTABLE: VtSync<Vt> = VtSync(Vt::VTABLE);
434 );
435}
436impl<Tail: TransitiveDeref<Vt, N>, Vt, N> TransitiveDeref<Vt, N> for VtSync<Tail> {
437 fn tderef(&self) -> &Vt {
438 self.0.tderef()
439 }
440}
441impl<Head, Tail> From<crate::vtable::VtSync<VtSend<VTable<Head, Tail>>>> for VTable<Head, Tail> {
442 fn from(value: VtSync<VtSend<VTable<Head, Tail>>>) -> Self {
443 value.0 .0
444 }
445}
446impl<Head, Tail> From<crate::vtable::VtSync<VtSend<VTable<Head, Tail>>>>
447 for VtSend<VTable<Head, Tail>>
448{
449 fn from(value: VtSync<VtSend<VTable<Head, Tail>>>) -> Self {
450 value.0
451 }
452}
453impl<Head, Tail> From<crate::vtable::VtSync<VTable<Head, Tail>>> for VTable<Head, Tail> {
454 fn from(value: VtSync<VTable<Head, Tail>>) -> Self {
455 value.0
456 }
457}
458
459#[stabby::stabby]
461pub trait Any {
462 extern "C" fn report(&self) -> &'static crate::report::TypeReport;
464 extern "C" fn id(&self) -> u64;
466}
467impl<T: crate::IStable> Any for T {
468 extern "C" fn report(&self) -> &'static crate::report::TypeReport {
469 Self::REPORT
470 }
471 extern "C" fn id(&self) -> u64 {
472 Self::ID
473 }
474}