use crate::Tid;
use std::any::Any;
use std::ops::CoerceUnsized;
use std::ptr::{DynMetadata, Pointee};
use std::rc::Rc;
use std::sync::Arc;
pub trait IntoRawPtr {
type Lifetime;
type Pointee: ?Sized;
unsafe fn into_raw(self) -> *const Self::Pointee;
unsafe fn from_raw(from: *const Self::Pointee) -> Self;
}
impl<T: ?Sized> IntoRawPtr for Box<T> {
type Lifetime = ();
type Pointee = T;
unsafe fn into_raw(self) -> *const Self::Pointee {
Box::into_raw(self)
}
unsafe fn from_raw(from: *const Self::Pointee) -> Self {
Box::from_raw(from as *mut _)
}
}
impl<T: ?Sized> IntoRawPtr for Rc<T> {
type Lifetime = ();
type Pointee = T;
unsafe fn into_raw(self) -> *const Self::Pointee {
Rc::into_raw(self)
}
unsafe fn from_raw(from: *const Self::Pointee) -> Self {
Rc::from_raw(from)
}
}
impl<T: ?Sized> IntoRawPtr for Arc<T> {
type Lifetime = ();
type Pointee = T;
unsafe fn into_raw(self) -> *const Self::Pointee {
Arc::into_raw(self)
}
unsafe fn from_raw(from: *const Self::Pointee) -> Self {
Arc::from_raw(from)
}
}
impl<'a, T: ?Sized> IntoRawPtr for &'a T {
type Lifetime = &'a ();
type Pointee = T;
unsafe fn into_raw(self) -> *const Self::Pointee {
self
}
unsafe fn from_raw(from: *const Self::Pointee) -> Self {
&*from
}
}
impl<'a, T: ?Sized> IntoRawPtr for &'a mut T {
type Lifetime = &'a mut ();
type Pointee = T;
unsafe fn into_raw(self) -> *const Self::Pointee {
self as *mut T as _
}
unsafe fn from_raw(from: *const Self::Pointee) -> Self {
&mut *(from as *mut _)
}
}
pub trait DynMetadataType: Pointee<Metadata = DynMetadata<Self::Over>> {
type Over: ?Sized + Pointee<Metadata = DynMetadata<Self::Over>>;
}
impl<T: ?Sized, X: ?Sized> DynMetadataType for X
where
X: Pointee<Metadata = DynMetadata<T>>,
T: Pointee<Metadata = DynMetadata<T>>,
{
type Over = T;
}
fn get_callable_trait_object<T: ?Sized + DynMetadataType>(
ptr: *const T,
) -> *const <T as DynMetadataType>::Over {
let metadata = ptr.to_raw_parts().1;
core::ptr::from_raw_parts(&(), metadata)
}
pub fn downcast_tid<'a, From: IntoRawPtr, To: IntoRawPtr<Lifetime = From::Lifetime>>(
f: From,
) -> Result<To, From>
where
From::Pointee: Pointee + DynMetadataType,
To::Pointee: Sized,
*const To::Pointee: CoerceUnsized<*const From::Pointee>,
<From::Pointee as DynMetadataType>::Over: Tid<'a>,
{
let raw = unsafe { f.into_raw() };
let vtable_only_pointer_from = unsafe { &*get_callable_trait_object(raw) };
let vtable_only_pointer_to = unsafe {
&*get_callable_trait_object(&() as *const () as *const To::Pointee as *const From::Pointee)
};
if vtable_only_pointer_from.self_id() == vtable_only_pointer_to.self_id() {
unsafe { Ok(To::from_raw(raw as _)) }
} else {
Err(unsafe { From::from_raw(raw) })
}
}
pub fn downcast_any<From: IntoRawPtr, To: IntoRawPtr<Lifetime = From::Lifetime>>(
f: From,
) -> Result<To, From>
where
From::Pointee: Pointee + DynMetadataType,
To::Pointee: Sized,
*const To::Pointee: CoerceUnsized<*const From::Pointee>,
<From::Pointee as DynMetadataType>::Over: Any,
{
let raw = unsafe { f.into_raw() };
let vtable_only_pointer_from = unsafe { &*get_callable_trait_object(raw) };
let vtable_only_pointer_to = unsafe {
&*get_callable_trait_object(&() as *const () as *const To::Pointee as *const From::Pointee)
};
if vtable_only_pointer_from.type_id() == vtable_only_pointer_to.type_id() {
unsafe { Ok(To::from_raw(raw as _)) }
} else {
Err(unsafe { From::from_raw(raw) })
}
}
pub trait DowncastExt: Sized + IntoRawPtr {
fn downcast_any<T>(self) -> Result<T, Self>
where
Self::Pointee: Pointee + DynMetadataType,
T: IntoRawPtr<Lifetime = Self::Lifetime>,
T::Pointee: Sized,
*const T::Pointee: CoerceUnsized<*const Self::Pointee>,
<Self::Pointee as DynMetadataType>::Over: Any,
{
downcast_any(self)
}
fn downcast_tid<'a, T: IntoRawPtr>(self) -> Result<T, Self>
where
Self::Pointee: Pointee + DynMetadataType,
T: IntoRawPtr<Lifetime = Self::Lifetime>,
T::Pointee: Sized,
*const T::Pointee: CoerceUnsized<*const Self::Pointee>,
<Self::Pointee as DynMetadataType>::Over: Tid<'a>,
{
downcast_tid(self)
}
}
impl<T: IntoRawPtr> DowncastExt for T where T::Pointee: DynMetadataType {}
fn doc_test() {}