#![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 + Send + Sync + '_ { type Static = dyn core::future::Future + Send + Sync; } unsafe impl StaticType for dyn core::future::Future + Send + '_ { type Static = dyn core::future::Future + Send; } unsafe impl StaticType for dyn core::future::Future + '_ { type Static = dyn core::future::Future; } #[cfg(feature = "alloc")] pub trait IntoDynAny<'n>: Sized + StaticType + 'n { fn into_dyn(self) -> Box + 'n> { Box::new(self) } } #[cfg(feature = "alloc")] impl<'n, T: StaticType + 'n> IntoDynAny<'n> for T {} #[cfg(feature = "alloc")] impl From<()> for Box> { fn from(_: ()) -> Box> { Box::new(()) } } #[cfg(feature = "alloc")] use alloc::borrow::Cow; #[cfg(feature = "alloc")] use alloc::boxed::Box; #[cfg(feature = "alloc")] use alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque}; #[cfg(feature = "alloc")] use alloc::string::String; #[cfg(feature = "alloc")] use alloc::vec::Vec; use core::cell::{Cell, RefCell, UnsafeCell}; use core::iter::Empty; use core::marker::{PhantomData, PhantomPinned}; use core::mem::{ManuallyDrop, MaybeUninit}; use core::num::Wrapping; use core::ops::Range; use core::pin::Pin; use core::sync::atomic::*; use core::time::Duration; impl_type!( Option, Result, Cell, UnsafeCell, RefCell, MaybeUninit, ManuallyDrop, PhantomData, PhantomPinned, Empty, Range, Wrapping, Pin, Duration, bool, f32, f64, char, u8, AtomicU8, u16, AtomicU16, u32, AtomicU32, u64, usize, AtomicUsize, i8, AtomicI8, i16, AtomicI16, i32, AtomicI32, i64, isize, AtomicIsize, i128, u128, AtomicBool, AtomicPtr ); #[cfg(feature = "large-atomics")] impl_type!(AtomicU64, AtomicI64); #[cfg(feature = "alloc")] impl_type!( Vec, String, BTreeMap,BTreeSet, LinkedList, VecDeque, BinaryHeap ); #[cfg(feature = "std")] use std::collections::{HashMap, HashSet}; #[cfg(feature = "std")] use std::sync::*; #[cfg(feature = "std")] impl_type!(Once, Mutex, RwLock, HashSet, HashMap); #[cfg(feature = "rc")] use std::rc::Rc; #[cfg(feature = "rc")] impl_type!(Rc); #[cfg(all(feature = "rc", feature = "alloc"))] use std::sync::Arc; #[cfg(all(feature = "rc", feature = "alloc"))] unsafe impl StaticType for Arc { type Static = Arc<::Static>; } #[cfg(feature = "glam")] use glam::*; #[cfg(feature = "glam")] #[rustfmt::skip] impl_type!( IVec2, IVec3, IVec4, UVec2, UVec3, UVec4, BVec2, BVec3, BVec4, Vec2, Vec3, Vec3A, Vec4, DVec2, DVec3, DVec4, Mat2, Mat3, Mat3A, Mat4, DMat2, DMat3, DMat4, Quat, Affine2, Affine3A, DAffine2, DAffine3, DQuat ); #[cfg(feature = "reqwest")] use reqwest::Response; #[cfg(feature = "reqwest")] impl_type!(Response); #[cfg(feature = "alloc")] unsafe impl crate::StaticType for Box { type Static = Box<::Static>; } #[test] fn test_tuple_of_boxes() { let tuple = (Box::new(&1u32 as &dyn DynAny<'static>), Box::new(&2u32 as &dyn DynAny<'static>)); let dyn_any = &tuple as &dyn DynAny; assert_eq!(&1, downcast_ref::(*downcast_ref::<(Box<&dyn DynAny>, Box<&dyn DynAny>)>(dyn_any).unwrap().0).unwrap()); assert_eq!(&2, downcast_ref::(*downcast_ref::<(Box<&dyn DynAny>, Box<&dyn DynAny>)>(dyn_any).unwrap().1).unwrap()); } macro_rules! impl_tuple { (@rec $t:ident) => { }; (@rec $_:ident $($t:ident)+) => { impl_tuple! { @impl $($t)* } impl_tuple! { @rec $($t)* } }; (@impl $($t:ident)*) => { unsafe 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); } #[cfg(not(target_arch = "wasm32"))] pub trait WasmNotSend: Send {} #[cfg(target_arch = "wasm32")] pub trait WasmNotSend {} #[cfg(not(target_arch = "wasm32"))] impl WasmNotSend for T {} #[cfg(target_arch = "wasm32")] impl WasmNotSend for T {} #[cfg(not(target_arch = "wasm32"))] pub trait WasmNotSync: Sync {} #[cfg(target_arch = "wasm32")] pub trait WasmNotSync {} #[cfg(not(target_arch = "wasm32"))] impl WasmNotSync for T {} #[cfg(target_arch = "wasm32")] impl WasmNotSync for T {} #[cfg(not(target_arch = "wasm32"))] #[cfg(feature = "alloc")] pub type DynFuture<'n, T> = Pin + 'n + Send>>; #[cfg(target_arch = "wasm32")] #[cfg(feature = "alloc")] pub type DynFuture<'n, T> = Pin + 'n>>;