use core::ptr::NonNull;
use crate as stabby;
use crate::vtable::*;
#[stabby::stabby]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct AnonymRef<'a> {
pub ptr: NonNull<()>,
pub _marker: core::marker::PhantomData<&'a ()>,
}
impl<T> From<&T> for AnonymRef<'_> {
fn from(value: &T) -> Self {
Self {
ptr: NonNull::from(value).cast(),
_marker: core::marker::PhantomData,
}
}
}
impl core::ops::Deref for AnonymRef<'_> {
type Target = NonNull<()>;
fn deref(&self) -> &Self::Target {
&self.ptr
}
}
#[stabby::stabby]
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct AnonymRefMut<'a> {
pub ptr: NonNull<()>,
pub _marker: core::marker::PhantomData<&'a mut ()>,
}
impl<T> From<&mut T> for AnonymRefMut<'_> {
fn from(value: &mut T) -> Self {
Self {
ptr: NonNull::from(value).cast(),
_marker: core::marker::PhantomData,
}
}
}
impl core::ops::Deref for AnonymRefMut<'_> {
type Target = NonNull<()>;
fn deref(&self) -> &Self::Target {
&self.ptr
}
}
impl core::ops::DerefMut for AnonymRefMut<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.ptr
}
}
impl IPtrOwned for AnonymRefMut<'_> {
fn drop(_: &mut core::mem::ManuallyDrop<Self>, _: unsafe extern "C" fn(AnonymRefMut<'_>)) {}
}
impl IPtr for AnonymRefMut<'_> {
unsafe fn as_ref(&self) -> AnonymRef<'_> {
AnonymRef {
ptr: self.ptr,
_marker: core::marker::PhantomData,
}
}
}
impl IPtrMut for AnonymRefMut<'_> {
unsafe fn as_mut(&mut self) -> AnonymRefMut<'_> {
AnonymRefMut {
ptr: self.ptr,
_marker: core::marker::PhantomData,
}
}
}
pub trait IPtr {
unsafe fn as_ref(&self) -> AnonymRef<'_>;
}
pub trait IPtrMut: IPtr {
unsafe fn as_mut(&mut self) -> AnonymRefMut<'_>;
}
pub trait IPtrTryAsMut {
unsafe fn try_as_mut(&mut self) -> Option<AnonymRefMut<'_>>;
}
impl<T: IPtrMut> IPtrTryAsMut for T {
unsafe fn try_as_mut(&mut self) -> Option<AnonymRefMut<'_>> {
Some(self.into())
}
}
pub trait IPtrOwned {
fn drop(this: &mut core::mem::ManuallyDrop<Self>, drop: unsafe extern "C" fn(AnonymRefMut<'_>));
}
pub trait IPtrClone: IPtrOwned {
fn clone(this: &Self) -> Self;
}
impl<T> IPtr for &T {
unsafe fn as_ref(&self) -> AnonymRef<'_> {
(self as &T).into()
}
}
impl<T> IPtr for &mut T {
unsafe fn as_ref(&self) -> AnonymRef<'_> {
(self as &T).into()
}
}
impl<T> IPtrMut for &mut T {
unsafe fn as_mut(&mut self) -> AnonymRefMut<'_> {
(self as &mut T).into()
}
}
impl<T> IPtrOwned for &mut T {
fn drop(_: &mut core::mem::ManuallyDrop<Self>, _: unsafe extern "C" fn(AnonymRefMut<'_>)) {}
}
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: AnonymRef<'a>,
vtable: &'a Vt,
unsend: core::marker::PhantomData<*mut ()>,
}
impl<'a, Vt: Copy + 'a> DynRef<'a, Vt> {
pub const fn ptr(&self) -> AnonymRef<'a> {
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.cast().as_ref() })
}
pub fn stable_downcast<T: crate::IStable, Path>(&self) -> Option<&T>
where
Vt: TransitiveDeref<crate::vtable::StabbyVtableAny<'a>, Path>,
{
(self.report() == T::REPORT).then(|| unsafe { self.ptr.cast().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> {
#[allow(clippy::missing_const_for_fn)]
pub fn ptr(&self) -> &P {
&self.ptr
}
#[allow(clippy::missing_const_for_fn)]
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<'_, AnonymRefMut<'_>, 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<'_, AnonymRefMut<'_>, 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().cast::<T>().as_ref() })
}
pub fn stable_downcast_ref<T: crate::IStable, Path>(&self) -> Option<&T>
where
Vt: TransitiveDeref<crate::vtable::StabbyVtableAny<'a>, Path> + IConstConstructor<'a, T>,
{
(self.id() == T::ID && self.report() == T::REPORT)
.then(|| unsafe { self.ptr.as_ref().cast::<T>().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().cast::<T>().as_mut() })
}
pub fn stable_downcast_mut<T: crate::IStable, Path>(&mut self) -> Option<&mut T>
where
Vt: TransitiveDeref<crate::vtable::StabbyVtableAny<'a>, Path> + IConstConstructor<'a, T>,
P: IPtrMut,
{
(self.id() == T::ID && self.report() == T::REPORT)
.then(|| unsafe { self.ptr.as_mut().cast::<T>().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 {
DynRef {
ptr: value.into(),
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> {}