#![doc(html_root_url = "http://docs.rs/const-default/1.0.0")]
#![cfg_attr(not(feature = "std"), no_std)]
#![allow(clippy::missing_safety_doc)]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "derive")]
pub use dyn_any_derive::DynAny;
/// Implement this trait for your `dyn Trait` types for all `T: Trait`
pub trait UpcastFrom {
fn up_from(value: &T) -> &Self;
fn up_from_mut(value: &mut T) -> &mut Self;
#[cfg(feature = "alloc")]
fn up_from_box(value: Box) -> Box;
}
/// Use this trait to perform your upcasts on dyn traits. Make sure to require it in the supertrait!
pub trait Upcast {
fn up(&self) -> &U;
fn up_mut(&mut self) -> &mut U;
#[cfg(feature = "alloc")]
fn up_box(self: Box) -> Box;
}
impl Upcast for T
where
U: UpcastFrom,
{
fn up(&self) -> &U {
U::up_from(self)
}
fn up_mut(&mut self) -> &mut U {
U::up_from_mut(self)
}
#[cfg(feature = "alloc")]
fn up_box(self: Box) -> Box {
U::up_from_box(self)
}
}
use core::any::TypeId;
impl<'a, T: DynAny<'a> + 'a> UpcastFrom for dyn DynAny<'a> + 'a {
fn up_from(value: &T) -> &(dyn DynAny<'a> + 'a) {
value
}
fn up_from_mut(value: &mut T) -> &mut (dyn DynAny<'a> + 'a) {
value
}
#[cfg(feature = "alloc")]
fn up_from_box(value: Box) -> Box {
value
}
}
pub trait DynAny<'a>: 'a {
fn type_id(&self) -> TypeId;
#[cfg(feature = "log-bad-types")]
fn type_name(&self) -> &'static str;
fn reborrow_box<'short>(self: Box) -> Box + 'short>
where
'a: 'short;
fn reborrow_ref<'short>(&'a self) -> &'short (dyn DynAny<'short> + Send + Sync + 'short)
where
'a: 'short,
Self: Send + Sync;
}
impl<'a, T: StaticType + 'a> DynAny<'a> for T {
fn type_id(&self) -> core::any::TypeId {
core::any::TypeId::of::()
}
#[cfg(feature = "log-bad-types")]
fn type_name(&self) -> &'static str {
core::any::type_name::()
}
fn reborrow_box<'short>(self: Box) -> Box + 'short>
where
'a: 'short,
{
self
}
fn reborrow_ref<'short>(&'a self) -> &'short (dyn DynAny<'short> + Send + Sync + 'short)
where
'a: 'short,
Self: Send + Sync,
{
self
}
}
pub fn downcast_ref<'a, V: StaticType + 'a>(i: &'a dyn DynAny<'a>) -> Option<&'a V> {
if i.type_id() == core::any::TypeId::of::<::Static>() {
// SAFETY: caller guarantees that T is the correct type
let ptr = i as *const dyn DynAny<'a> as *const V;
Some(unsafe { &*ptr })
} else {
None
}
}
#[cfg(feature = "alloc")]
pub fn downcast<'a, V: StaticType + 'a>(i: Box + 'a>) -> Result, String> {
let type_id = DynAny::type_id(i.as_ref());
if type_id == core::any::TypeId::of::<::Static>() {
// SAFETY: caller guarantees that T is the correct type
let ptr = Box::into_raw(i) as *mut V;
Ok(unsafe { Box::from_raw(ptr) })
} else {
if type_id == core::any::TypeId::of::<&dyn DynAny<'static>>() {
panic!("downcast error: type_id == core::any::TypeId::of::>()");
}
#[cfg(feature = "log-bad-types")]
{
Err(format!("Incorrect type, expected {} but found {}", core::any::type_name::(), DynAny::type_name(i.as_ref())))
}
#[cfg(not(feature = "log-bad-types"))]
{
Err(format!("Incorrect type, expected {}", core::any::type_name::()))
}
}
}
pub unsafe trait StaticType {
type Static: 'static + ?Sized;
fn type_id(&self) -> core::any::TypeId {
core::any::TypeId::of::()
}
}
pub unsafe trait StaticTypeSized {
type Static: 'static;
fn type_id(&self) -> core::any::TypeId {
core::any::TypeId::of::<::Static>()
}
}
unsafe impl StaticTypeSized for T
where
T::Static: Sized,
{
type Static = ::Static;
}
pub unsafe trait StaticTypeClone {
type Static: 'static + Clone;
fn type_id(&self) -> core::any::TypeId {
core::any::TypeId::of::<::Static>()
}
}
unsafe impl StaticTypeClone for T
where
T::Static: Clone,
{
type Static = ::Static;
}
macro_rules! impl_type {
($($id:ident$(<$($(($l:lifetime, $s:lifetime)),*|)?$($T:ident),*>)?),*) => {
$(
unsafe impl< $($($T: $crate::StaticTypeSized ,)*)?> $crate::StaticType for $id $(<$($($l,)*)?$($T, )*>)?{
type Static = $id$(<$($($s,)*)?$(<$T as $crate::StaticTypeSized>::Static,)*>)?;
}
)*
};
}
#[cfg(feature = "alloc")]
unsafe impl StaticType for Cow<'_, T> {
type Static = Cow<'static, ::Static>;
}
unsafe impl StaticType for *const [T] {
type Static = *const [::Static];
}
unsafe impl StaticType for *mut [T] {
type Static = *mut [::Static];
}
macro_rules! impl_slice {
($($id:ident),*) => {
$(
unsafe impl<'a, T: StaticTypeSized> StaticType for $id<'a, T> {
type Static = $id<'static, ::Static>;
}
)*
};
}
mod slice {
use super::*;
use core::slice::*;
impl_slice!(Iter, IterMut, Chunks, ChunksMut, RChunks, RChunksMut, Windows);
}
#[cfg(feature = "alloc")]
unsafe impl StaticType for Box + '_ + Send + Sync> {
type Static = Box::Static> + Send + Sync>;
}
unsafe impl StaticType for &str {
type Static = &'static str;
}
unsafe impl StaticType for () {
type Static = ();
}
unsafe impl<'a, T: 'a + StaticType + ?Sized> StaticType for &'a T {
type Static = &'static ::Static;
}
unsafe impl StaticType for [T; N] {
type Static = [::Static; N];
}
unsafe impl StaticType for [T] {
type Static = [::Static];
}
unsafe impl StaticType for dyn for<'i> DynAny<'_> + '_ {
type Static = dyn DynAny<'static>;
}
unsafe impl StaticType for dyn for<'i> DynAny<'_> + Send + Sync + '_ {
type Static = dyn DynAny<'static> + Send + Sync;
}
unsafe impl StaticType for dyn for<'i> DynAny<'_> + Send + '_ {
type Static = dyn DynAny<'static> + Sync;
}
unsafe impl StaticType for dyn core::future::Future