use crate as stabby;
use crate::vtable::*;
pub trait IPtr {
unsafe fn as_ref<U: Sized>(&self) -> &U;
}
pub trait IPtrMut: IPtr {
unsafe fn as_mut<U: Sized>(&mut self) -> &mut U;
}
pub trait IPtrTryAsMut {
unsafe fn try_as_mut<U: Sized>(&mut self) -> Option<&mut U>;
}
impl<T: IPtrMut> IPtrTryAsMut for T {
unsafe fn try_as_mut<U>(&mut self) -> Option<&mut U> {
Some(self.as_mut())
}
}
pub trait IPtrOwned {
fn drop(this: &mut core::mem::ManuallyDrop<Self>, drop: unsafe extern "C" fn(&mut ()));
}
pub trait IPtrClone: IPtrOwned {
fn clone(this: &Self) -> Self;
}
impl<T> IPtr for &T {
unsafe fn as_ref<U>(&self) -> &U {
core::mem::transmute(self)
}
}
impl<T> IPtr for &mut T {
unsafe fn as_ref<U>(&self) -> &U {
core::mem::transmute(self)
}
}
impl<T> IPtrMut for &mut T {
unsafe fn as_mut<U>(&mut self) -> &mut U {
core::mem::transmute(self)
}
}
impl<T> IPtrOwned for &mut T {
fn drop(_: &mut core::mem::ManuallyDrop<Self>, _: unsafe extern "C" fn(&mut ())) {}
}
pub trait IntoDyn {
type Anonymized;
type Target;
fn anonimize(self) -> Self::Anonymized;
}
impl<'a, T> IntoDyn for &'a T {
type Anonymized = &'a ();
type Target = T;
fn anonimize(self) -> Self::Anonymized {
unsafe { core::mem::transmute(self) }
}
}
impl<'a, T> IntoDyn for &'a mut T {
type Anonymized = &'a mut ();
type Target = T;
fn anonimize(self) -> Self::Anonymized {
unsafe { core::mem::transmute(self) }
}
}
#[stabby::stabby]
#[derive(Clone, Copy)]
pub struct DynRef<'a, Vt: 'static> {
ptr: &'a (),
vtable: &'a Vt,
unsend: core::marker::PhantomData<*mut ()>,
}
impl<'a, Vt: Copy + 'a> DynRef<'a, Vt> {
pub const fn ptr(&self) -> &() {
self.ptr
}
pub const fn vtable(&self) -> &Vt {
self.vtable
}
pub fn into_super<Super>(self) -> Super
where
Self: IntoSuperTrait<Super>,
{
IntoSuperTrait::into_super(self)
}
pub unsafe fn downcast<T>(&self) -> Option<&T>
where
Vt: PartialEq + IConstConstructor<'a, T>,
{
(self.vtable == Vt::vtable()).then(|| unsafe { self.ptr.as_ref() })
}
pub fn stable_downcast<T: crate::IStable, Path>(&self) -> Option<&T>
where
Vt: TransitiveDeref<crate::vtable::StabbyVtableAny, Path>,
{
(self.report() == T::REPORT).then(|| unsafe { self.ptr.as_ref() })
}
}
#[stabby::stabby]
pub struct Dyn<'a, P: IPtrOwned + 'a, Vt: HasDropVt + 'static> {
pub(crate) ptr: core::mem::ManuallyDrop<P>,
pub(crate) vtable: &'static Vt,
pub(crate) unsend: core::marker::PhantomData<&'a P>,
}
pub trait IntoSuperTrait<Super> {
fn into_super(this: Self) -> Super;
}
macro_rules! impl_super {
($from: ty, $to: ty, $($generics: tt)*) => {
impl<'a, P: IPtrOwned + 'a + Sized, $($generics)*> IntoSuperTrait<Dyn<'a, P, $to>> for Dyn<'a, P, $from>
{
fn into_super(this: Self) -> Dyn<'a, P, $to> {
let ptr = &this as *const _;
core::mem::forget(this);
unsafe { core::ptr::read(ptr as *const _) }
}
}
impl<'a, $($generics)*> IntoSuperTrait<DynRef<'a, $to>> for DynRef<'a, $from>
{
fn into_super(this: Self) -> DynRef<'a, $to> {
let ptr = &this as *const _;
unsafe { core::ptr::read(ptr as *const _) }
}
}
};
}
impl_super!(VTable<Head, Tail>, Tail, Head, Tail: HasDropVt + 'static);
impl_super!(VtSend<Vt>, Vt, Vt: HasDropVt + 'static);
impl_super!(VtSync<Vt>, Vt, Vt: HasDropVt + 'static);
impl_super!(VtSync<VtSend<Vt>>, Vt, Vt: HasDropVt + 'static);
impl_super!(VtSend<VtSync<Vt>>, Vt, Vt: HasDropVt + 'static);
impl_super!(VtSync<VtSend<Vt>>, VtSync<Vt>, Vt: HasDropVt + 'static);
impl_super!(VtSend<VtSync<Vt>>, VtSend<Vt>, Vt: HasDropVt + 'static);
impl_super!(VtSend<VTable<Head, Tail>>, Tail, Head, Tail: HasDropVt + 'static);
impl_super!(VtSync<VTable<Head, Tail>>, Tail, Head, Tail: HasDropVt + 'static);
impl_super!(VtSync<VtSend<VTable<Head, Tail>>>, Tail, Head, Tail: HasDropVt + 'static);
impl_super!(VtSend<VtSync<VTable<Head, Tail>>>, Tail, Head, Tail: HasDropVt + 'static);
impl_super!(VtSend<VTable<Head, Tail>>, VtSend<Tail>, Head, Tail: HasDropVt + 'static);
impl_super!(VtSync<VTable<Head, Tail>>, VtSync<Tail>, Head, Tail: HasDropVt + 'static);
impl_super!(VtSync<VtSend<VTable<Head, Tail>>>, VtSync<VtSend<Tail>>, Head, Tail: HasDropVt + 'static);
impl_super!(VtSend<VtSync<VTable<Head, Tail>>>, VtSend<VtSync<Tail>>, Head, Tail: HasDropVt + 'static);
impl<'a, P: IPtrOwned + IPtrClone, Vt: HasDropVt + 'a> Clone for Dyn<'a, P, Vt> {
fn clone(&self) -> Self {
Self {
ptr: core::mem::ManuallyDrop::new(IPtrClone::clone(&self.ptr)),
vtable: self.vtable,
unsend: self.unsend,
}
}
}
impl<'a, P: IPtrOwned + IPtr, Vt: HasDropVt + 'a> Dyn<'a, P, Vt> {
pub fn ptr(&self) -> &P {
&self.ptr
}
pub fn ptr_mut(&mut self) -> &mut P {
&mut self.ptr
}
pub const fn vtable(&self) -> &'a Vt {
self.vtable
}
pub fn as_ref(&self) -> DynRef<'_, Vt> {
DynRef {
ptr: unsafe { self.ptr.as_ref() },
vtable: self.vtable,
unsend: core::marker::PhantomData,
}
}
pub fn as_mut(&mut self) -> Dyn<&mut (), Vt>
where
P: IPtrMut,
{
Dyn {
ptr: unsafe { core::mem::ManuallyDrop::new(self.ptr.as_mut()) },
vtable: self.vtable,
unsend: core::marker::PhantomData,
}
}
pub fn try_as_mut(&mut self) -> Option<Dyn<&mut (), Vt>>
where
P: IPtrTryAsMut,
{
Some(Dyn {
ptr: unsafe { core::mem::ManuallyDrop::new(self.ptr.try_as_mut()?) },
vtable: self.vtable,
unsend: core::marker::PhantomData,
})
}
pub fn into_super<Super>(self) -> Super
where
Self: IntoSuperTrait<Super>,
{
IntoSuperTrait::into_super(self)
}
pub unsafe fn downcast_ref<T>(&self) -> Option<&T>
where
Vt: PartialEq + Copy + IConstConstructor<'a, T>,
{
(self.vtable == Vt::vtable()).then(|| unsafe { self.ptr.as_ref() })
}
pub fn stable_downcast_ref<T: crate::IStable, Path>(&self) -> Option<&T>
where
Vt: TransitiveDeref<crate::vtable::StabbyVtableAny, Path> + IConstConstructor<'a, T>,
{
(self.id() == T::ID && self.report() == T::REPORT).then(|| unsafe { self.ptr.as_ref() })
}
pub unsafe fn downcast_mut<T>(&mut self) -> Option<&mut T>
where
Vt: PartialEq + Copy + IConstConstructor<'a, T>,
P: IPtrMut,
{
(self.vtable == Vt::vtable()).then(|| unsafe { self.ptr.as_mut() })
}
pub fn stable_downcast_mut<T: crate::IStable, Path>(&mut self) -> Option<&mut T>
where
Vt: TransitiveDeref<crate::vtable::StabbyVtableAny, Path> + IConstConstructor<'a, T>,
P: IPtrMut,
{
(self.id() == T::ID && self.report() == T::REPORT).then(|| unsafe { self.ptr.as_mut() })
}
}
impl<
'a,
Vt: HasDropVt + Copy + IConstConstructor<'static, P::Target> + 'static,
P: IntoDyn + 'a,
> From<P> for Dyn<'a, P::Anonymized, Vt>
where
P::Anonymized: IPtrOwned,
{
fn from(value: P) -> Self {
Self {
ptr: core::mem::ManuallyDrop::new(value.anonimize()),
vtable: Vt::vtable(),
unsend: core::marker::PhantomData,
}
}
}
impl<P: IPtrOwned, Vt: HasDropVt> Drop for Dyn<'_, P, Vt> {
fn drop(&mut self) {
P::drop(&mut self.ptr, *unsafe {
self.vtable.drop_vt().drop.as_ref_unchecked()
})
}
}
impl<'a, T, Vt: Copy + IConstConstructor<'a, T>> From<&'a T> for DynRef<'a, Vt> {
fn from(value: &'a T) -> Self {
unsafe {
DynRef {
ptr: core::mem::transmute::<&'a T, &'a ()>(value),
vtable: Vt::vtable(),
unsend: core::marker::PhantomData,
}
}
}
}
unsafe impl<Vt: HasSendVt> Send for DynRef<'_, Vt> {}
unsafe impl<Vt: HasSyncVt> Sync for DynRef<'_, Vt> {}
unsafe impl<P: IPtrOwned + Send, Vt: HasSendVt + HasDropVt> Send for Dyn<'_, P, Vt> {}
unsafe impl<P: IPtrOwned + Sync, Vt: HasSyncVt + HasDropVt> Sync for Dyn<'_, P, Vt> {}