use crate::cast_target::DynDynCastTarget;
use cfg_if::cfg_if;
use core::any::TypeId;
use core::fmt::{self, Debug};
use core::marker::Unsize;
use core::mem;
use core::ptr::{self, DynMetadata, Pointee};
#[cfg(doc)]
use crate::dyn_dyn_cast;
#[derive(Debug, Clone, Copy)]
pub struct AnyDynMetadata(*const ());
impl AnyDynMetadata {
pub const fn upcast<T: ?Sized>(meta: DynMetadata<T>) -> AnyDynMetadata {
unsafe { AnyDynMetadata(mem::transmute::<DynMetadata<T>, *const ()>(meta)) }
}
pub const unsafe fn downcast<T: DynDynCastTarget + ?Sized>(self) -> DynMetadata<T> {
unsafe { mem::transmute::<*const (), DynMetadata<T>>(self.0) }
}
}
impl<T: ?Sized> From<DynMetadata<T>> for AnyDynMetadata {
fn from(meta: DynMetadata<T>) -> Self {
AnyDynMetadata::upcast(meta)
}
}
unsafe impl Send for AnyDynMetadata {}
unsafe impl Sync for AnyDynMetadata {}
cfg_if! {
if #[cfg(feature = "dynamic-names")] {
type TypeName = &'static str;
const fn type_name<T: ?Sized>() -> TypeName {
core::any::type_name::<T>()
}
} else {
#[derive(Debug, Clone, Copy)]
struct TypeName;
#[allow(clippy::extra_unused_type_parameters)]
const fn type_name<T: ?Sized>() -> TypeName { TypeName }
}
}
#[derive(Debug, Clone, Copy)]
struct DynInfo(TypeId, TypeName);
impl DynInfo {
pub const fn of<T: 'static + ?Sized>() -> DynInfo {
DynInfo(TypeId::of::<T>(), type_name::<T>())
}
pub fn type_id(self) -> TypeId {
self.0
}
#[cfg(feature = "dynamic-names")]
pub fn name(self) -> &'static str {
self.1
}
}
impl PartialEq for DynInfo {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl Eq for DynInfo {}
pub struct DynDynTableEntry {
ty: DynInfo,
meta: AnyDynMetadata,
}
impl DynDynTableEntry {
const fn meta_for_ty<
T: Unsize<D>,
D: ?Sized + Pointee<Metadata = DynMetadata<M>>,
M: ?Sized,
>() -> DynMetadata<M> {
ptr::metadata(ptr::null::<T>() as *const D)
}
#[doc(hidden)]
pub const fn new<
T: Unsize<D>,
D: ?Sized + Pointee<Metadata = DynMetadata<M>> + 'static,
M: ?Sized,
>() -> DynDynTableEntry {
DynDynTableEntry {
ty: DynInfo::of::<D>(),
meta: AnyDynMetadata::upcast(Self::meta_for_ty::<T, D, M>()),
}
}
pub fn type_id(&self) -> TypeId {
self.ty.type_id()
}
#[cfg(feature = "dynamic-names")]
pub fn type_name(&self) -> &'static str {
self.ty.name()
}
}
impl Debug for DynDynTableEntry {
#[cfg(feature = "dynamic-names")]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"DynDynTableEntry(<{}>: {:?})",
self.type_name(),
self.meta
)
}
#[cfg(not(feature = "dynamic-names"))]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "DynDynTableEntry({:?}: {:?})", self.type_id(), self.meta)
}
}
#[derive(Debug, Clone, Copy)]
pub struct DynDynTable {
traits: &'static [DynDynTableEntry],
}
impl DynDynTable {
pub fn find_untyped(&self, type_id: TypeId) -> Option<AnyDynMetadata> {
self.traits
.iter()
.find(|&entry| entry.ty.type_id() == type_id)
.map(|entry| entry.meta)
}
pub fn find<D: ?Sized + DynDynCastTarget + 'static>(&self) -> Option<DynMetadata<D>> {
self.find_untyped(TypeId::of::<D>()).map(|meta| {
unsafe { meta.downcast() }
})
}
pub fn into_slice(self) -> &'static [DynDynTableEntry] {
self.traits
}
#[doc(hidden)]
pub const fn new(traits: &'static [DynDynTableEntry]) -> DynDynTable {
DynDynTable { traits }
}
}
impl IntoIterator for DynDynTable {
type Item = &'static DynDynTableEntry;
type IntoIter = DynDynTableIterator;
fn into_iter(self) -> Self::IntoIter {
DynDynTableIterator(self.traits.iter())
}
}
pub struct DynDynTableIterator(core::slice::Iter<'static, DynDynTableEntry>);
impl Iterator for DynDynTableIterator {
type Item = &'static DynDynTableEntry;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}