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
12pub 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
20pub 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 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 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}