dyn_any/
lib.rs

1#![doc(html_root_url = "http://docs.rs/const-default/1.0.0")]
2#![cfg_attr(feature = "unstable-docs", feature(doc_cfg))]
3#![cfg_attr(not(feature = "std"), no_std)]
4
5#[cfg(feature = "alloc")]
6extern crate alloc;
7
8#[cfg(feature = "derive")]
9#[cfg_attr(feature = "unstable-docs", doc(cfg(feature = "derive")))]
10pub use dyn_any_derive::DynAny;
11
12/// Implement this trait for your `dyn Trait` types for all `T: Trait`
13pub trait UpcastFrom<T: ?Sized> {
14	fn up_from(value: &T) -> &Self;
15	fn up_from_mut(value: &mut T) -> &mut Self;
16	#[cfg(feature = "alloc")]
17	fn up_from_box(value: Box<T>) -> Box<Self>;
18}
19
20/// Use this trait to perform your upcasts on dyn traits. Make sure to require it in the supertrait!
21pub trait Upcast<U: ?Sized> {
22	fn up(&self) -> &U;
23	fn up_mut(&mut self) -> &mut U;
24	#[cfg(feature = "alloc")]
25	fn up_box(self: Box<Self>) -> Box<U>;
26}
27
28impl<T: ?Sized, U: ?Sized> Upcast<U> for T
29where
30	U: UpcastFrom<T>,
31{
32	fn up(&self) -> &U {
33		U::up_from(self)
34	}
35	fn up_mut(&mut self) -> &mut U {
36		U::up_from_mut(self)
37	}
38	#[cfg(feature = "alloc")]
39	fn up_box(self: Box<Self>) -> Box<U> {
40		U::up_from_box(self)
41	}
42}
43
44use core::any::TypeId;
45
46impl<'a, T: DynAny<'a> + 'a> UpcastFrom<T> for dyn DynAny<'a> + 'a {
47	fn up_from(value: &T) -> &(dyn DynAny<'a> + 'a) {
48		value
49	}
50	fn up_from_mut(value: &mut T) -> &mut (dyn DynAny<'a> + 'a) {
51		value
52	}
53	#[cfg(feature = "alloc")]
54	fn up_from_box(value: Box<T>) -> Box<Self> {
55		value
56	}
57}
58
59pub trait DynAny<'a> {
60	fn type_id(&self) -> TypeId;
61	#[cfg(feature = "log-bad-types")]
62	fn type_name(&self) -> &'static str;
63}
64
65impl<'a, T: StaticType> DynAny<'a> for T {
66	fn type_id(&self) -> core::any::TypeId {
67		core::any::TypeId::of::<T::Static>()
68	}
69	#[cfg(feature = "log-bad-types")]
70	fn type_name(&self) -> &'static str {
71		core::any::type_name::<T>()
72	}
73}
74pub fn downcast_ref<'a, V: StaticType>(i: &'a dyn DynAny<'a>) -> Option<&'a V> {
75	if i.type_id() == core::any::TypeId::of::<<V as StaticType>::Static>() {
76		// SAFETY: caller guarantees that T is the correct type
77		let ptr = i as *const dyn DynAny<'a> as *const V;
78		Some(unsafe { &*ptr })
79	} else {
80		None
81	}
82}
83
84#[cfg(feature = "alloc")]
85pub fn downcast<'a, V: StaticType>(i: Box<dyn DynAny<'a> + 'a>) -> Result<Box<V>, String> {
86	let type_id = DynAny::type_id(i.as_ref());
87	if type_id == core::any::TypeId::of::<<V as StaticType>::Static>() {
88		// SAFETY: caller guarantees that T is the correct type
89		let ptr = Box::into_raw(i) as *mut dyn DynAny<'a> as *mut V;
90		Ok(unsafe { Box::from_raw(ptr) })
91	} else {
92		if type_id == core::any::TypeId::of::<&dyn DynAny<'static>>() {
93			panic!("downcast error: type_id == core::any::TypeId::of::<dyn DynAny<'a>>()");
94		}
95		#[cfg(feature = "log-bad-types")]
96		{
97			Err(format!("Incorrect type, expected {} but found {}", core::any::type_name::<V>(), DynAny::type_name(i.as_ref())))
98		}
99
100		#[cfg(not(feature = "log-bad-types"))]
101		{
102			Err(format!("Incorrect type, expected {}", core::any::type_name::<V>()))
103		}
104	}
105}
106
107pub unsafe trait StaticType {
108	type Static: 'static + ?Sized;
109	fn type_id(&self) -> core::any::TypeId {
110		core::any::TypeId::of::<Self::Static>()
111	}
112}
113
114pub unsafe trait StaticTypeSized {
115	type Static: 'static;
116	fn type_id(&self) -> core::any::TypeId {
117		core::any::TypeId::of::<<Self as StaticTypeSized>::Static>()
118	}
119}
120unsafe impl<T: StaticType + Sized> StaticTypeSized for T
121where
122	T::Static: Sized,
123{
124	type Static = <T as StaticType>::Static;
125}
126pub unsafe trait StaticTypeClone {
127	type Static: 'static + Clone;
128	fn type_id(&self) -> core::any::TypeId {
129		core::any::TypeId::of::<<Self as StaticTypeClone>::Static>()
130	}
131}
132unsafe impl<T: StaticType + Clone> StaticTypeClone for T
133where
134	T::Static: Clone,
135{
136	type Static = <T as StaticType>::Static;
137}
138
139macro_rules! impl_type {
140	($($id:ident$(<$($(($l:lifetime, $s:lifetime)),*|)?$($T:ident),*>)?),*) => {
141		$(
142		unsafe impl< $($($T:  $crate::StaticTypeSized ,)*)?> $crate::StaticType for $id $(<$($($l,)*)?$($T, )*>)?{
143			type Static = $id$(<$($($s,)*)?$(<$T as $crate::StaticTypeSized>::Static,)*>)?;
144		}
145		)*
146	};
147}
148
149#[cfg(feature = "alloc")]
150unsafe impl<'a, T: StaticTypeClone + Clone> StaticType for Cow<'a, T> {
151	type Static = Cow<'static, <T as StaticTypeClone>::Static>;
152}
153unsafe impl<T: StaticTypeSized> StaticType for *const [T] {
154	type Static = *const [<T as StaticTypeSized>::Static];
155}
156unsafe impl<T: StaticTypeSized> StaticType for *mut [T] {
157	type Static = *mut [<T as StaticTypeSized>::Static];
158}
159unsafe impl<'a, T: StaticTypeSized> StaticType for &'a [T] {
160	type Static = &'static [<T as StaticTypeSized>::Static];
161}
162macro_rules! impl_slice {
163    ($($id:ident),*) => {
164        $(
165        unsafe impl<'a, T: StaticTypeSized> StaticType for $id<'a, T> {
166            type Static = $id<'static, <T as StaticTypeSized>::Static>;
167        }
168        )*
169    };
170}
171
172mod slice {
173	use super::*;
174	use core::slice::*;
175	impl_slice!(Iter, IterMut, Chunks, ChunksMut, RChunks, RChunksMut, Windows);
176}
177
178#[cfg(feature = "alloc")]
179unsafe impl<'a, T: StaticTypeSized> StaticType for Box<dyn Iterator<Item = T> + 'a + Send + Sync> {
180	type Static = Box<dyn Iterator<Item = <T as StaticTypeSized>::Static> + Send + Sync>;
181}
182
183unsafe impl<'a> StaticType for &'a str {
184	type Static = &'static str;
185}
186unsafe impl StaticType for () {
187	type Static = ();
188}
189unsafe impl<'a, T: 'a + StaticType + ?Sized> StaticType for &'a T {
190	type Static = &'static <T as StaticType>::Static;
191}
192unsafe impl<T: StaticTypeSized, const N: usize> StaticType for [T; N] {
193	type Static = [<T as StaticTypeSized>::Static; N];
194}
195
196unsafe impl<'a> StaticType for dyn DynAny<'a> + '_ {
197	type Static = dyn DynAny<'static>;
198}
199#[cfg(feature = "alloc")]
200pub trait IntoDynAny<'n>: Sized + StaticType + 'n {
201	fn into_dyn(self) -> Box<dyn DynAny<'n> + 'n> {
202		Box::new(self)
203	}
204}
205#[cfg(feature = "alloc")]
206impl<'n, T: StaticType + 'n> IntoDynAny<'n> for T {}
207
208#[cfg(feature = "alloc")]
209impl From<()> for Box<dyn DynAny<'static>> {
210	fn from(_: ()) -> Box<dyn DynAny<'static>> {
211		Box::new(())
212	}
213}
214
215#[cfg(feature = "alloc")]
216use alloc::{
217	borrow::Cow,
218	boxed::Box,
219	collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque},
220	string::String,
221	vec::Vec,
222};
223use core::sync::atomic::*;
224use core::{
225	cell::{Cell, RefCell, UnsafeCell},
226	iter::Empty,
227	marker::{PhantomData, PhantomPinned},
228	mem::{ManuallyDrop, MaybeUninit},
229	num::Wrapping,
230	ops::Range,
231	time::Duration,
232};
233
234impl_type!(
235	Option<T>, Result<T, E>, Cell<T>, UnsafeCell<T>, RefCell<T>, MaybeUninit<T>,
236	 ManuallyDrop<T>, PhantomData<T>, PhantomPinned, Empty<T>, Range<T>,
237	Wrapping<T>, Duration, bool, f32, f64, char,
238	u8, AtomicU8, u16, AtomicU16, u32, AtomicU32, u64,  usize, AtomicUsize,
239	i8, AtomicI8, i16, AtomicI16, i32, AtomicI32, i64,  isize, AtomicIsize,
240	i128, u128, AtomicBool, AtomicPtr<T>
241);
242#[cfg(feature = "large-atomics")]
243impl_type!(AtomicU64, AtomicI64);
244
245#[cfg(feature = "alloc")]
246impl_type!(
247	Vec<T>, String, BTreeMap<K,V>,BTreeSet<V>, LinkedList<T>, VecDeque<T>,
248	BinaryHeap<T>
249);
250
251#[cfg(feature = "std")]
252use std::sync::*;
253
254#[cfg(feature = "std")]
255impl_type!(Once, Mutex<T>, RwLock<T>);
256
257#[cfg(feature = "rc")]
258use std::rc::Rc;
259#[cfg(feature = "rc")]
260impl_type!(Rc<T>);
261#[cfg(all(feature = "rc", feature = "alloc"))]
262use std::sync::Arc;
263#[cfg(all(feature = "rc", feature = "alloc"))]
264impl_type!(Arc<T>);
265
266#[cfg(feature = "glam")]
267use glam::*;
268#[cfg(feature = "glam")]
269#[rustfmt::skip]
270impl_type!(
271	IVec2, IVec3, IVec4, UVec2, UVec3, UVec4, BVec2, BVec3, BVec4,
272	Vec2, Vec3, Vec3A, Vec4, DVec2, DVec3, DVec4,
273	Mat2, Mat3, Mat3A, Mat4, DMat2, DMat3, DMat4,
274	Quat, Affine2, Affine3A, DAffine2, DAffine3, DQuat
275);
276
277#[cfg(feature = "alloc")]
278unsafe impl<T: crate::StaticType + ?Sized> crate::StaticType for Box<T> {
279	type Static = Box<<T as crate::StaticType>::Static>;
280}
281#[test]
282fn test_tuple_of_boxes() {
283	let tuple = (Box::new(&1 as &dyn DynAny<'static>), Box::new(&2 as &dyn DynAny<'static>));
284	let dyn_any = &tuple as &dyn DynAny;
285	assert_eq!(&1, downcast_ref(*downcast_ref::<(Box<&dyn DynAny>, Box<&dyn DynAny>)>(dyn_any).unwrap().0).unwrap());
286	assert_eq!(&2, downcast_ref(*downcast_ref::<(Box<&dyn DynAny>, Box<&dyn DynAny>)>(dyn_any).unwrap().1).unwrap());
287}
288
289macro_rules! impl_tuple {
290	(@rec $t:ident) => { };
291	(@rec $_:ident $($t:ident)+) => {
292		impl_tuple! { @impl $($t)* }
293		impl_tuple! { @rec $($t)* }
294	};
295	(@impl $($t:ident)*) => {
296		unsafe impl< $($t: StaticTypeSized,)*> StaticType for ($($t,)*) {
297			type Static = ($(<$t as $crate::StaticTypeSized>::Static,)*);
298		}
299	};
300	($($t:ident)*) => {
301		impl_tuple! { @rec _t $($t)* }
302	};
303}
304
305impl_tuple! {
306	A B C D E F G H I J K L
307}
308
309#[test]
310fn simple_downcast() {
311	let x = Box::new(3_u32) as Box<dyn DynAny>;
312	assert_eq!(*downcast::<u32>(x).unwrap(), 3_u32);
313}
314#[test]
315#[should_panic]
316fn simple_downcast_panic() {
317	let x = Box::new(3_i32) as Box<dyn DynAny>;
318	assert_eq!(*downcast::<u32>(x).expect("attempted to perform invalid downcast"), 3_u32);
319}