use crate::{self as stabby};
use core::{
hash::{Hash, Hasher},
marker::PhantomData,
ptr::NonNull,
};
#[rustversion::nightly]
pub trait IConstConstructor<'a, Source>: 'a + Copy + core::marker::Freeze {
const VTABLE: Self;
const VTABLE_REF: &'a Self = &Self::VTABLE;
fn vtable() -> &'a Self {
Self::VTABLE_REF
}
}
#[rustversion::before(1.78.0)]
pub trait IConstConstructor<'a, Source>: 'a + Copy {
const VTABLE: Self;
const VTABLE_REF: &'a Self = &Self::VTABLE;
fn vtable() -> &'a Self {
Self::VTABLE_REF
}
}
#[cfg(feature = "libc")]
#[rustversion::all(since(1.78.0), not(nightly))]
pub trait IConstConstructor<'a, Source>: 'a + Copy + core::hash::Hash + core::fmt::Debug {
const VTABLE: Self;
fn vtable() -> &'a Self {
static VTABLES: core::sync::atomic::AtomicPtr<
crate::alloc::vec::Vec<(
u64,
crate::alloc::AllocPtr<*const (), crate::alloc::DefaultAllocator>,
)>,
> = core::sync::atomic::AtomicPtr::new(core::ptr::null_mut());
use crate::alloc::{boxed::Box, vec::Vec, AllocPtr, DefaultAllocator};
let vtable = Self::VTABLE;
#[allow(deprecated)]
let hash = {
let mut hasher = core::hash::SipHasher::new();
vtable.hash(&mut hasher);
hasher.finish()
};
fn insert_vtable(hash: u64, vtable: &[*const ()]) -> AllocPtr<*const (), DefaultAllocator> {
let mut search_start = 0;
let mut allocated_vt = None;
let mut vtables = VTABLES.load(core::sync::atomic::Ordering::SeqCst);
loop {
let vts = match unsafe { vtables.as_ref() } {
None => [].as_slice(),
Some(vts) => match vts[search_start..]
.iter()
.find_map(|e| (e.0 == hash).then_some(e.1))
{
Some(vt) => return vt,
None => vts,
},
};
let vt = allocated_vt.unwrap_or_else(|| {
let mut ptr =
AllocPtr::alloc_array(&mut DefaultAllocator::new(), vtable.len()).unwrap();
unsafe {
core::ptr::copy_nonoverlapping(vtable.as_ptr(), ptr.as_mut(), vtable.len())
};
ptr
});
allocated_vt = Some(vt);
let updated = VTABLES.load(core::sync::atomic::Ordering::SeqCst);
if !core::ptr::eq(vtables, updated) {
vtables = updated;
continue;
}
let mut vec = Vec::with_capacity(vts.len() + 1);
vec.copy_extend(vts);
vec.push((hash, vt));
let mut vec = Box::into_raw(Box::new(vec));
match VTABLES.compare_exchange(
updated,
unsafe { vec.as_mut() },
core::sync::atomic::Ordering::SeqCst,
core::sync::atomic::Ordering::SeqCst,
) {
Ok(updated) => {
if let Some(updated) = NonNull::new(updated) {
unsafe {
Box::from_raw(AllocPtr {
ptr: updated,
marker: PhantomData::<DefaultAllocator>,
})
};
}
return vt;
}
Err(new_vtables) => {
search_start = vts.len();
vtables = new_vtables;
unsafe { Box::from_raw(vec) };
}
}
}
}
unsafe {
let vtable = core::slice::from_raw_parts(
(&vtable as *const Self).cast(),
core::mem::size_of::<Self>() / core::mem::size_of::<*const ()>(),
);
let vt = insert_vtable(hash, vtable).cast().as_ref();
debug_assert_eq!(
core::slice::from_raw_parts(
(vt as *const Self).cast::<*const ()>(),
core::mem::size_of::<Self>() / core::mem::size_of::<*const ()>(),
),
vtable
);
vt
}
}
}
pub trait TransitiveDeref<Head, N> {
fn tderef(&self) -> &Head;
}
pub struct H;
pub struct T<T>(T);
#[stabby::stabby]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct VTable<Head, Tail = VtDrop> {
pub tail: Tail,
pub head: Head,
}
pub trait CompoundVt {
type Vt<T>;
}
impl<'a, T, Head: Copy + 'a, Tail: Copy + 'a> IConstConstructor<'a, T> for VTable<Head, Tail>
where
Head: IConstConstructor<'a, T>,
Tail: IConstConstructor<'a, T>,
{
const VTABLE: VTable<Head, Tail> = VTable {
head: Head::VTABLE,
tail: Tail::VTABLE,
};
}
impl<'a, T> IConstConstructor<'a, T> for () {
const VTABLE: () = ();
}
impl<Head, Tail> TransitiveDeref<Head, H> for VTable<Head, Tail> {
fn tderef(&self) -> &Head {
&self.head
}
}
impl<Head, Tail: TransitiveDeref<Vt, N>, Vt, N> TransitiveDeref<Vt, T<N>> for VTable<Head, Tail> {
fn tderef(&self) -> &Vt {
self.tail.tderef()
}
}
pub trait HasDropVt {
fn drop_vt(&self) -> &VtDrop;
}
impl HasDropVt for VtDrop {
fn drop_vt(&self) -> &VtDrop {
self
}
}
impl<Head, Tail: HasDropVt> HasDropVt for VTable<Head, Tail> {
fn drop_vt(&self) -> &VtDrop {
self.tail.drop_vt()
}
}
impl<T: HasDropVt> HasDropVt for VtSend<T> {
fn drop_vt(&self) -> &VtDrop {
self.0.drop_vt()
}
}
impl<T: HasDropVt> HasDropVt for VtSync<T> {
fn drop_vt(&self) -> &VtDrop {
self.0.drop_vt()
}
}
pub trait HasSendVt {}
impl<T> HasSendVt for VtSend<T> {}
impl<T: HasSendVt> HasSendVt for VtSync<T> {}
impl<Head, Tail: HasSyncVt> HasSendVt for VTable<Head, Tail> {}
pub trait HasSyncVt {}
impl<T> HasSyncVt for VtSync<T> {}
impl<T: HasSyncVt> HasSyncVt for VtSend<T> {}
impl<Head, Tail: HasSyncVt> HasSyncVt for VTable<Head, Tail> {}
#[stabby::stabby]
#[derive(Clone, Copy, Eq)]
pub struct VtDrop {
pub drop: crate::StableLike<unsafe extern "C" fn(&mut ()), core::num::NonZeroUsize>,
}
impl core::fmt::Debug for VtDrop {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "VtDrop({:p})", unsafe { self.drop.as_ref_unchecked() })
}
}
impl Hash for VtDrop {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.drop.hash(state)
}
}
impl PartialEq for VtDrop {
fn eq(&self, other: &Self) -> bool {
core::ptr::eq(
unsafe { self.drop.as_ref_unchecked() } as *const unsafe extern "C" fn(&mut ()),
unsafe { other.drop.as_ref_unchecked() } as *const unsafe extern "C" fn(&mut ()),
)
}
}
impl<'a, T> IConstConstructor<'a, T> for VtDrop {
const VTABLE: VtDrop = VtDrop {
drop: unsafe {
core::mem::transmute({
unsafe extern "C" fn drop<T>(this: &mut T) {
core::ptr::drop_in_place(this)
}
drop::<T>
} as unsafe extern "C" fn(&mut T))
},
};
}
#[stabby::stabby]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct VtSend<T>(pub T);
impl CompoundVt for dyn Send {
type Vt<T> = VtSend<T>;
}
impl<Tail: TransitiveDeref<Vt, N>, Vt, N> TransitiveDeref<Vt, N> for VtSend<Tail> {
fn tderef(&self) -> &Vt {
self.0.tderef()
}
}
impl<Head, Tail> From<crate::vtable::VtSend<VTable<Head, Tail>>> for VTable<Head, Tail> {
fn from(value: VtSend<VTable<Head, Tail>>) -> Self {
value.0
}
}
impl<'a, T: Send, Vt: IConstConstructor<'a, T>> IConstConstructor<'a, T> for VtSend<Vt> {
const VTABLE: VtSend<Vt> = VtSend(Vt::VTABLE);
}
#[stabby::stabby]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct VtSync<T>(pub T);
impl CompoundVt for dyn Sync {
type Vt<T> = VtSync<T>;
}
impl<'a, T: Sync, Vt: IConstConstructor<'a, T>> IConstConstructor<'a, T> for VtSync<Vt> {
const VTABLE: VtSync<Vt> = VtSync(Vt::VTABLE);
}
impl<Tail: TransitiveDeref<Vt, N>, Vt, N> TransitiveDeref<Vt, N> for VtSync<Tail> {
fn tderef(&self) -> &Vt {
self.0.tderef()
}
}
impl<Head, Tail> From<crate::vtable::VtSync<VtSend<VTable<Head, Tail>>>> for VTable<Head, Tail> {
fn from(value: VtSync<VtSend<VTable<Head, Tail>>>) -> Self {
value.0 .0
}
}
impl<Head, Tail> From<crate::vtable::VtSync<VtSend<VTable<Head, Tail>>>>
for VtSend<VTable<Head, Tail>>
{
fn from(value: VtSync<VtSend<VTable<Head, Tail>>>) -> Self {
value.0
}
}
impl<Head, Tail> From<crate::vtable::VtSync<VTable<Head, Tail>>> for VTable<Head, Tail> {
fn from(value: VtSync<VTable<Head, Tail>>) -> Self {
value.0
}
}
#[stabby::stabby]
pub trait Any {
extern "C" fn report(&self) -> &'static crate::report::TypeReport;
extern "C" fn id(&self) -> u64;
}
impl<T: crate::IStable> Any for T {
extern "C" fn report(&self) -> &'static crate::report::TypeReport {
Self::REPORT
}
extern "C" fn id(&self) -> u64 {
Self::ID
}
}