calimero_primitives/
reflect.rs

1use core::any::{type_name, TypeId};
2use core::marker::PhantomData;
3use core::mem::transmute;
4use core::ptr;
5use std::rc::Rc;
6use std::sync::Arc;
7
8// https://github.com/sagebind/castaway/pull/14
9
10/// Produces type IDs that are compatible with `TypeId::of::<T>`, but without
11/// `T: 'static` bound.
12fn non_static_type_id<T: ?Sized>() -> TypeId {
13    trait NonStaticAny {
14        fn get_type_id(&self) -> TypeId
15        where
16            Self: 'static;
17    }
18
19    impl<T: ?Sized> NonStaticAny for PhantomData<T> {
20        fn get_type_id(&self) -> TypeId
21        where
22            Self: 'static,
23        {
24            TypeId::of::<T>()
25        }
26    }
27
28    let phantom_data = PhantomData::<T>;
29    NonStaticAny::get_type_id(unsafe {
30        transmute::<&dyn NonStaticAny, &(dyn NonStaticAny + 'static)>(&phantom_data)
31    })
32}
33
34pub trait Reflect {
35    fn type_id(&self) -> TypeId {
36        non_static_type_id::<Self>()
37    }
38
39    fn type_name(&self) -> &'static str {
40        type_name::<Self>()
41    }
42
43    fn as_dyn_ref<'a>(&self) -> &(dyn Reflect + 'a)
44    where
45        Self: 'a;
46
47    fn as_dyn_mut<'a>(&mut self) -> &mut (dyn Reflect + 'a)
48    where
49        Self: 'a;
50
51    fn as_dyn_box<'a>(self: Box<Self>) -> Box<dyn Reflect + 'a>
52    where
53        Self: 'a;
54
55    fn as_dyn_rc<'a>(self: Rc<Self>) -> Rc<dyn Reflect + 'a>
56    where
57        Self: 'a;
58
59    fn as_dyn_arc<'a>(self: Arc<Self>) -> Arc<dyn Reflect + 'a>
60    where
61        Self: 'a;
62}
63
64impl<T> Reflect for T {
65    fn as_dyn_ref<'a>(&self) -> &(dyn Reflect + 'a)
66    where
67        T: 'a,
68    {
69        self
70    }
71
72    fn as_dyn_mut<'a>(&mut self) -> &mut (dyn Reflect + 'a)
73    where
74        T: 'a,
75    {
76        self
77    }
78
79    fn as_dyn_box<'a>(self: Box<Self>) -> Box<dyn Reflect + 'a>
80    where
81        T: 'a,
82    {
83        self
84    }
85
86    fn as_dyn_rc<'a>(self: Rc<Self>) -> Rc<dyn Reflect + 'a>
87    where
88        T: 'a,
89    {
90        self
91    }
92
93    fn as_dyn_arc<'a>(self: Arc<Self>) -> Arc<dyn Reflect + 'a>
94    where
95        T: 'a,
96    {
97        self
98    }
99}
100
101pub trait ReflectExt: Reflect {
102    fn is<T: Reflect + ?Sized>(&self) -> bool {
103        self.type_id() == non_static_type_id::<T>()
104    }
105
106    #[must_use]
107    fn type_id() -> TypeId {
108        non_static_type_id::<Self>()
109    }
110
111    fn downcast_ref<T: Reflect>(&self) -> Option<&T> {
112        if self.is::<T>() {
113            return Some(unsafe { &*ptr::from_ref(self).cast() });
114        }
115
116        None
117    }
118
119    fn downcast_mut<T: Reflect>(&mut self) -> Option<&mut T> {
120        if self.is::<T>() {
121            return Some(unsafe { &mut *ptr::from_mut(self).cast() });
122        }
123
124        None
125    }
126
127    fn downcast_box<T: Reflect>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
128        if (*self).is::<T>() {
129            return Ok(unsafe { Box::from_raw(Box::into_raw(self).cast()) });
130        }
131
132        Err(self)
133    }
134
135    fn downcast_rc<T: Reflect>(self: Rc<Self>) -> Result<Rc<T>, Rc<Self>> {
136        if (*self).is::<T>() {
137            return Ok(unsafe { Rc::from_raw(Rc::into_raw(self).cast()) });
138        }
139
140        Err(self)
141    }
142
143    fn downcast_arc<T: Reflect>(self: Arc<Self>) -> Result<Arc<T>, Arc<Self>> {
144        if (*self).is::<T>() {
145            return Ok(unsafe { Arc::from_raw(Arc::into_raw(self).cast()) });
146        }
147
148        Err(self)
149    }
150}
151
152impl<T: Reflect + ?Sized> ReflectExt for T {}