#![doc(html_root_url = "http://docs.rs/const-default/1.0.0")] #![cfg_attr(feature = "unstable-docs", feature(doc_cfg))] #[cfg(feature = "derive")] #[cfg_attr(feature = "unstable-docs", doc(cfg(feature = "derive")))] pub use dyn_any_derive::DynAny; use std::any::TypeId; pub trait DynAny<'a> { fn type_id(&self) -> TypeId; } impl<'a, T: StaticType> DynAny<'a> for T { fn type_id(&self) -> std::any::TypeId { std::any::TypeId::of::() } } pub fn downcast_ref<'a, V: StaticType>(i: &'a dyn DynAny<'a>) -> Option<&'a V> { if i.type_id() == std::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 } } pub fn downcast<'a, V: StaticType>(i: Box + 'a>) -> Option> { let type_id = DynAny::type_id(i.as_ref()); if type_id == std::any::TypeId::of::<::Static>() { // SAFETY: caller guarantees that T is the correct type let ptr = Box::into_raw(i) as *mut dyn DynAny<'a> as *mut V; Some(unsafe { Box::from_raw(ptr) }) } else { // TODO: add log error if type_id == std::any::TypeId::of::<&dyn DynAny<'static>>() { panic!("downcast error: type_id == std::any::TypeId::of::>()"); } println!("expected: {:?}", std::any::TypeId::of::<::Static>()); println!("actual one: {:?}", type_id); None } } pub trait StaticType { type Static: 'static + ?Sized; fn type_id(&self) -> std::any::TypeId { std::any::TypeId::of::() } } pub trait StaticTypeSized { type Static: 'static; fn type_id(&self) -> std::any::TypeId { std::any::TypeId::of::() } } impl StaticTypeSized for T where T::Static: Sized, { type Static = ::Static; } pub trait StaticTypeClone { type Static: 'static + Clone; fn type_id(&self) -> std::any::TypeId { std::any::TypeId::of::() } } impl StaticTypeClone for T where T::Static: Clone, { type Static = ::Static; } macro_rules! impl_type { ($($id:ident$(<$($(($l:lifetime, $s:lifetime)),*|)?$($T:ident),*>)?),*) => { $( impl< $($($T: $crate::StaticTypeSized ,)*)?> $crate::StaticType for $id $(<$($($l,)*)?$($T, )*>)?{ type Static = $id$(<$($($s,)*)?$(<$T as $crate::StaticTypeSized>::Static,)*>)?; } )* }; } impl<'a, T: StaticTypeClone + Clone> StaticType for std::borrow::Cow<'a, T> { type Static = std::borrow::Cow<'static, T::Static>; } impl StaticType for *const [T] { type Static = *const [::Static]; } impl StaticType for *mut [T] { type Static = *mut [::Static]; } impl<'a, T: StaticTypeSized> StaticType for &'a [T] { type Static = &'static [::Static]; } impl<'a> StaticType for &'a str { type Static = &'static str; } impl StaticType for () { type Static = (); } impl<'a, T: 'a + StaticType + ?Sized> StaticType for &'a T { type Static = &'static ::Static; } impl StaticType for [T; N] { type Static = [::Static; N]; } impl<'a> StaticType for dyn DynAny<'a> + '_ { type Static = dyn DynAny<'static>; } pub trait IntoDynAny<'n>: Sized + StaticType + 'n { fn into_dyn(self) -> Box + 'n> { Box::new(self) } } impl<'n, T: StaticType + 'n> IntoDynAny<'n> for T {} impl From<()> for Box> { fn from(_: ()) -> Box> { Box::new(()) } } use core::{ cell::{Cell, RefCell, UnsafeCell}, iter::Empty, marker::{PhantomData, PhantomPinned}, mem::{ManuallyDrop, MaybeUninit}, num::Wrapping, time::Duration, }; use std::{ collections::*, sync::{atomic::*, *}, vec::Vec, }; impl_type!(Option,Result,Cell,UnsafeCell,RefCell,MaybeUninit, Vec, String, BTreeMap,BTreeSet, LinkedList, VecDeque, BinaryHeap, ManuallyDrop, PhantomData, PhantomPinned,Empty, Wrapping, Duration, Once, Mutex, RwLock, bool, f32, f64, char, u8, AtomicU8, u16,AtomicU16, u32,AtomicU32, u64,AtomicU64, usize,AtomicUsize, i8,AtomicI8, i16,AtomicI16, i32,AtomicI32, i64,AtomicI64, isize,AtomicIsize, i128, u128, AtomicBool, AtomicPtr ); impl crate::StaticType for Box { type Static = Box<::Static>; } fn test() { let foo = (Box::new(&1 as &dyn DynAny<'static>), Box::new(&2 as &dyn DynAny<'static>)); //let bar = &foo as &dyn DynAny<'static>; } macro_rules! impl_tuple { (@rec $t:ident) => { }; (@rec $_:ident $($t:ident)+) => { impl_tuple! { @impl $($t)* } impl_tuple! { @rec $($t)* } }; (@impl $($t:ident)*) => { impl< $($t: StaticTypeSized,)*> StaticType for ($($t,)*) { type Static = ($(<$t as $crate::StaticTypeSized>::Static,)*); } }; ($($t:ident)*) => { impl_tuple! { @rec _t $($t)* } }; } impl_tuple! { A B C D E F G H I J K L } #[test] fn simple_downcast() { let x = Box::new(3_u32) as Box; assert_eq!(*downcast::(x).unwrap(), 3_u32); } #[test] #[should_panic] fn simple_downcast_panic() { let x = Box::new(3_i32) as Box; assert_eq!(*downcast::(x).expect("attempted to perform invalid downcast"), 3_u32); }