#![doc = include_str!("../README.md")]
#![cfg_attr(not(feature = "std"), no_std)]
#![warn(missing_docs)]
#![warn(clippy::undocumented_unsafe_blocks)]
#![allow(clippy::needless_borrowed_reference)]
#![forbid(unsafe_op_in_unsafe_fn)]
#![feature(coerce_unsized)]
#![feature(const_nonnull_new)]
#![feature(const_option)]
#![feature(const_trait_impl)]
#![feature(const_type_id)]
#![cfg_attr(feature = "dynamic-names", feature(const_type_name))]
#![feature(doc_auto_cfg)]
#![feature(ptr_metadata)]
#![feature(unsize)]
#[cfg(feature = "alloc")]
extern crate alloc;
mod cast_target;
mod fat;
mod table;
#[doc(hidden)]
pub mod internal;
pub use dyn_dyn_macros::dyn_dyn_base;
pub use dyn_dyn_macros::dyn_dyn_cast;
pub use dyn_dyn_macros::dyn_dyn_impl;
pub use cast_target::DynDynCastTarget;
pub use fat::DynDynFat;
pub use table::{AnyDynMetadata, DynDynTable, DynDynTableEntry, DynDynTableIterator};
#[cfg(doc)]
use core::ops::Deref;
use cfg_if::cfg_if;
use core::marker::{PhantomData, Unsize};
use core::ops::DerefMut;
use core::ptr::{self, Pointee};
use stable_deref_trait::StableDeref;
pub unsafe trait DynDynBase {
fn get_dyn_dyn_table(&self) -> DynDynTable;
}
pub struct DynDynRef<'a, B: ?Sized + DynDynBase, T: GetDynDynTable<B> + StableDeref>(
&'a T,
PhantomData<fn(B) -> B>,
);
impl<'a, B: ?Sized + DynDynBase, T: GetDynDynTable<B> + StableDeref> DynDynRef<'a, B, T>
where
T::Target: Unsize<B>,
{
pub fn new(r: &'a T) -> Self {
DynDynRef(r, PhantomData)
}
}
pub struct DynDynRefMut<'a, B: ?Sized + DynDynBase, T: GetDynDynTable<B> + StableDeref + DerefMut>(
&'a mut T,
PhantomData<fn(B) -> B>,
);
impl<'a, B: ?Sized + DynDynBase, T: GetDynDynTable<B> + StableDeref + DerefMut>
DynDynRefMut<'a, B, T>
{
pub fn new(r: &'a mut T) -> Self {
DynDynRefMut(r, PhantomData)
}
}
pub unsafe trait GetDynDynTable<B: ?Sized + DynDynBase> {
type DynTarget: ?Sized + Unsize<B>;
fn get_dyn_dyn_table(&self) -> DynDynTable;
}
pub trait DowncastUnchecked<'a> {
type DowncastResult<D: ?Sized + 'a>;
unsafe fn downcast_unchecked<D: ?Sized + Pointee>(
self,
metadata: <D as Pointee>::Metadata,
) -> Self::DowncastResult<D>;
}
pub trait DynDyn<'a, B: ?Sized + DynDynBase>: GetDynDynTable<B> + DowncastUnchecked<'a> {}
impl<'a, B: ?Sized + DynDynBase, T: GetDynDynTable<B> + DowncastUnchecked<'a>> DynDyn<'a, B> for T {}
unsafe impl<'a, B: ?Sized + DynDynBase, T: ?Sized + Unsize<B>> GetDynDynTable<B> for &'a T {
type DynTarget = T;
fn get_dyn_dyn_table(&self) -> DynDynTable {
B::get_dyn_dyn_table(*self)
}
}
impl<'a, T: ?Sized> DowncastUnchecked<'a> for &'a T {
type DowncastResult<D: ?Sized + 'a> = &'a D;
unsafe fn downcast_unchecked<D: ?Sized + Pointee>(
self,
metadata: <D as Pointee>::Metadata,
) -> &'a D {
unsafe { &*ptr::from_raw_parts(self as *const T as *const (), metadata) }
}
}
unsafe impl<'a, B: ?Sized + DynDynBase, T: GetDynDynTable<B> + StableDeref + 'a> GetDynDynTable<B>
for DynDynRef<'a, B, T>
where
T::Target: Unsize<B>,
{
type DynTarget = T::DynTarget;
fn get_dyn_dyn_table(&self) -> DynDynTable {
<T as GetDynDynTable<B>>::get_dyn_dyn_table(self.0)
}
}
impl<'a, B: ?Sized + DynDynBase, T: DynDyn<'a, B> + StableDeref + 'a> DowncastUnchecked<'a>
for DynDynRef<'a, B, T>
where
T::Target: Unsize<B>,
{
type DowncastResult<D: ?Sized + 'a> = &'a D;
unsafe fn downcast_unchecked<D: ?Sized + Pointee>(
self,
metadata: <D as Pointee>::Metadata,
) -> Self::DowncastResult<D> {
unsafe { <&T::Target as DowncastUnchecked>::downcast_unchecked(&**self.0, metadata) }
}
}
unsafe impl<'a, B: ?Sized + DynDynBase, T: ?Sized + Unsize<B>> GetDynDynTable<B> for &'a mut T {
type DynTarget = T;
fn get_dyn_dyn_table(&self) -> DynDynTable {
B::get_dyn_dyn_table(*self)
}
}
impl<'a, T: ?Sized> DowncastUnchecked<'a> for &'a mut T {
type DowncastResult<D: ?Sized + 'a> = &'a mut D;
unsafe fn downcast_unchecked<D: ?Sized + Pointee>(
self,
metadata: <D as Pointee>::Metadata,
) -> &'a mut D {
unsafe { &mut *ptr::from_raw_parts_mut(self as *mut T as *mut (), metadata) }
}
}
unsafe impl<'a, B: ?Sized + DynDynBase, T: DynDyn<'a, B> + StableDeref + DerefMut + 'a>
GetDynDynTable<B> for DynDynRefMut<'a, B, T>
where
T::Target: Unsize<B>,
{
type DynTarget = T::Target;
fn get_dyn_dyn_table(&self) -> DynDynTable {
<T as GetDynDynTable<B>>::get_dyn_dyn_table(self.0)
}
}
impl<'a, B: ?Sized + DynDynBase, T: DynDyn<'a, B> + StableDeref + DerefMut + 'a>
DowncastUnchecked<'a> for DynDynRefMut<'a, B, T>
where
T::Target: Unsize<B>,
{
type DowncastResult<D: ?Sized + 'a> = &'a mut D;
unsafe fn downcast_unchecked<D: ?Sized + Pointee>(
self,
metadata: <D as Pointee>::Metadata,
) -> Self::DowncastResult<D> {
unsafe {
<&mut T::Target as DowncastUnchecked>::downcast_unchecked(&mut **self.0, metadata)
}
}
}
cfg_if! {
if #[cfg(feature = "alloc")] {
use alloc::boxed::Box;
use alloc::sync::Arc;
use alloc::rc::Rc;
unsafe impl<B: ?Sized + DynDynBase, T: ?Sized + Unsize<B>> GetDynDynTable<B> for Box<T> {
type DynTarget = T;
fn get_dyn_dyn_table(&self) -> DynDynTable {
B::get_dyn_dyn_table(&**self)
}
}
impl<'a, T: ?Sized + 'a> DowncastUnchecked<'a>
for Box<T>
{
type DowncastResult<D: ?Sized + 'a> = Box<D>;
unsafe fn downcast_unchecked<D: ?Sized + Pointee>(self, metadata: <D as Pointee>::Metadata) -> Box<D> {
unsafe {
Box::from_raw(
ptr::from_raw_parts_mut(Box::into_raw(self) as *mut (), metadata)
)
}
}
}
unsafe impl<B: ?Sized + DynDynBase, T: ?Sized + Unsize<B>> GetDynDynTable<B> for Rc<T> {
type DynTarget = T;
fn get_dyn_dyn_table(&self) -> DynDynTable {
B::get_dyn_dyn_table(&**self)
}
}
impl<'a, T: ?Sized + 'a> DowncastUnchecked<'a>
for Rc<T>
{
type DowncastResult<D: ?Sized + 'a> = Rc<D>;
unsafe fn downcast_unchecked<D: ?Sized + Pointee>(self, metadata: <D as Pointee>::Metadata) -> Rc<D> {
unsafe {
Rc::from_raw(
ptr::from_raw_parts(
Rc::into_raw(self) as *const (),
metadata,
),
)
}
}
}
unsafe impl<B: ?Sized + DynDynBase, T: ?Sized + Unsize<B>> GetDynDynTable<B> for Arc<T> {
type DynTarget = T;
fn get_dyn_dyn_table(&self) -> DynDynTable {
B::get_dyn_dyn_table(&**self)
}
}
impl<'a, T: ?Sized + 'a> DowncastUnchecked<'a>
for Arc<T>
{
type DowncastResult<D: ?Sized + 'a> = Arc<D>;
unsafe fn downcast_unchecked<D: ?Sized + Pointee>(self, metadata: <D as Pointee>::Metadata) -> Arc<D> {
unsafe {
Arc::from_raw(
ptr::from_raw_parts(Arc::into_raw(self) as *const (), metadata),
)
}
}
}
}
}