1use std::any::TypeId;
13use std::cell::Cell;
14use std::cell::RefCell;
15use std::cell::UnsafeCell;
16use std::collections::BTreeMap;
17use std::collections::HashMap;
18use std::rc::Rc;
19use std::sync::Arc;
20
21pub use gazebo_derive::ProvidesStaticType;
22
23pub unsafe trait ProvidesStaticType {
28 type StaticType: 'static + ?Sized;
33}
34
35unsafe impl<'a, T: ProvidesStaticType + 'a + ?Sized> AnyLifetime<'a> for T {
41 fn static_type_id() -> TypeId
42 where
43 Self: Sized,
44 {
45 TypeId::of::<T::StaticType>()
46 }
47
48 fn static_type_of(&self) -> TypeId {
49 TypeId::of::<T::StaticType>()
50 }
51}
52
53pub unsafe trait AnyLifetime<'a>: 'a {
90 fn static_type_id() -> TypeId
93 where
94 Self: Sized;
95
96 fn static_type_of(&self) -> TypeId;
100 }
102
103impl<'a> dyn AnyLifetime<'a> {
104 pub fn is<T: AnyLifetime<'a>>(&self) -> bool {
106 self.static_type_of() == T::static_type_id()
107 }
108
109 pub fn downcast_ref<T: AnyLifetime<'a>>(&self) -> Option<&T> {
112 if self.is::<T>() {
113 unsafe { Some(&*(self as *const Self as *const T)) }
115 } else {
116 None
117 }
118 }
119
120 pub fn downcast_mut<T: AnyLifetime<'a>>(&mut self) -> Option<&mut T> {
123 if self.is::<T>() {
124 unsafe { Some(&mut *(self as *mut Self as *mut T)) }
126 } else {
127 None
128 }
129 }
130}
131
132macro_rules! any_lifetime {
133 ( $t:ty ) => {
134 unsafe impl $crate::any::ProvidesStaticType for $t {
135 type StaticType = $t;
136 }
137 };
138}
139
140any_lifetime!(());
144any_lifetime!(bool);
145any_lifetime!(u8);
146any_lifetime!(u16);
147any_lifetime!(u32);
148any_lifetime!(u64);
149any_lifetime!(u128);
150any_lifetime!(usize);
151any_lifetime!(i8);
152any_lifetime!(i16);
153any_lifetime!(i32);
154any_lifetime!(i64);
155any_lifetime!(i128);
156any_lifetime!(isize);
157any_lifetime!(f32);
158any_lifetime!(f64);
159any_lifetime!(String);
160any_lifetime!(str);
161
162unsafe impl<'a, T: ProvidesStaticType + ?Sized> ProvidesStaticType for &'a T {
163 type StaticType = &'static T::StaticType;
164}
165unsafe impl<'a, T: ProvidesStaticType + ?Sized> ProvidesStaticType for &'a mut T {
166 type StaticType = &'static mut T::StaticType;
167}
168unsafe impl<T: ProvidesStaticType + ?Sized> ProvidesStaticType for *const T {
169 type StaticType = *const T::StaticType;
170}
171unsafe impl<T: ProvidesStaticType + ?Sized> ProvidesStaticType for *mut T {
172 type StaticType = *mut T::StaticType;
173}
174unsafe impl<T> ProvidesStaticType for [T]
175where
176 T: ProvidesStaticType,
177 T::StaticType: Sized,
178{
179 type StaticType = [T::StaticType];
180}
181unsafe impl<T: ProvidesStaticType + ?Sized> ProvidesStaticType for Box<T> {
182 type StaticType = Box<T::StaticType>;
183}
184unsafe impl<T: ProvidesStaticType + ?Sized> ProvidesStaticType for Rc<T> {
185 type StaticType = Rc<T::StaticType>;
186}
187unsafe impl<T: ProvidesStaticType + ?Sized> ProvidesStaticType for Arc<T> {
188 type StaticType = Arc<T::StaticType>;
189}
190unsafe impl<T: ProvidesStaticType> ProvidesStaticType for Cell<T> {
191 type StaticType = Cell<T::StaticType>;
192}
193unsafe impl<T: ProvidesStaticType> ProvidesStaticType for UnsafeCell<T> {
194 type StaticType = UnsafeCell<T::StaticType>;
195}
196unsafe impl<T: ProvidesStaticType> ProvidesStaticType for RefCell<T> {
197 type StaticType = RefCell<T::StaticType>;
198}
199unsafe impl<T> ProvidesStaticType for Option<T>
200where
201 T: ProvidesStaticType,
202 T::StaticType: Sized,
203{
204 type StaticType = Option<T::StaticType>;
205}
206unsafe impl<T, E> ProvidesStaticType for Result<T, E>
207where
208 T: ProvidesStaticType,
209 T::StaticType: Sized,
210 E: ProvidesStaticType,
211 E::StaticType: Sized,
212{
213 type StaticType = Result<T::StaticType, E::StaticType>;
214}
215unsafe impl<T> ProvidesStaticType for Vec<T>
216where
217 T: ProvidesStaticType,
218 T::StaticType: Sized,
219{
220 type StaticType = Vec<T::StaticType>;
221}
222unsafe impl<K, V> ProvidesStaticType for HashMap<K, V>
223where
224 K: ProvidesStaticType,
225 K::StaticType: Sized,
226 V: ProvidesStaticType,
227 V::StaticType: Sized,
228{
229 type StaticType = HashMap<K::StaticType, V::StaticType>;
230}
231unsafe impl<K, V> ProvidesStaticType for BTreeMap<K, V>
232where
233 K: ProvidesStaticType,
234 K::StaticType: Sized,
235 V: ProvidesStaticType,
236 V::StaticType: Sized,
237{
238 type StaticType = BTreeMap<K::StaticType, V::StaticType>;
239}
240
241#[cfg(test)]
242mod tests {
243 use std::fmt::Display;
244
245 use super::*;
246 #[allow(unused_imports)] use crate as gazebo;
248
249 #[test]
250 fn test_can_convert() {
251 #[derive(Debug, PartialEq, ProvidesStaticType)]
252 struct Value<'a>(&'a str);
253
254 #[derive(ProvidesStaticType)]
255 struct Value2<'a>(&'a str);
256
257 fn convert_value<'a>(x: &'a Value<'a>) -> Option<&'a Value<'a>> {
259 <dyn AnyLifetime>::downcast_ref(x)
260 }
261
262 fn convert_any<'p, 'a>(x: &'p dyn AnyLifetime<'a>) -> Option<&'p Value<'a>> {
263 x.downcast_ref()
264 }
265
266 let v = Value("test");
267 let v2 = Value2("test");
268 assert_eq!(convert_value(&v), Some(&v));
269 assert_eq!(convert_any(&v), Some(&v));
270 assert_eq!(convert_any(&v2), None);
271 }
272
273 #[test]
274 fn test_any_lifetime() {
275 fn test<'a, A: AnyLifetime<'a>>(expected: TypeId) {
276 assert_eq!(expected, A::static_type_id());
277 }
278
279 test::<&str>(TypeId::of::<&str>());
280 test::<&String>(TypeId::of::<&String>());
281 test::<Box<str>>(TypeId::of::<Box<str>>());
282 }
283
284 #[test]
285 fn test_provides_static_type_id() {
286 fn test<'a, A: AnyLifetime<'a>>(expected: TypeId) {
287 assert_eq!(expected, A::static_type_id());
288 }
289
290 #[derive(ProvidesStaticType)]
291 struct Aaa;
292 test::<Aaa>(TypeId::of::<Aaa>());
293
294 #[derive(ProvidesStaticType)]
295 struct Bbb<'a>(&'a str);
296 test::<Bbb>(TypeId::of::<Bbb<'static>>());
297
298 #[derive(ProvidesStaticType)]
299 struct Bbb2<'a, 'b>(&'a str, &'b str);
300 test::<Bbb2>(TypeId::of::<Bbb2<'static, 'static>>());
301
302 #[derive(ProvidesStaticType)]
303 struct Ccc<X>(X);
304 test::<Ccc<String>>(TypeId::of::<Ccc<String>>());
305
306 #[derive(ProvidesStaticType)]
307 struct LifetimeTypeConst<'a, T, const N: usize>([&'a T; N]);
308 test::<LifetimeTypeConst<i32, 3>>(TypeId::of::<LifetimeTypeConst<'static, i32, 3>>());
309
310 #[derive(ProvidesStaticType)]
311 struct TypeWithConstraint<T: Display>(T);
312 test::<TypeWithConstraint<String>>(TypeId::of::<TypeWithConstraint<String>>());
313
314 struct TypeWhichDoesNotImplementAnyLifetime;
315
316 #[derive(ProvidesStaticType)]
317 struct TypeWithStaticLifetime<T: 'static>(T);
318 test::<TypeWithStaticLifetime<TypeWhichDoesNotImplementAnyLifetime>>(TypeId::of::<
319 TypeWithStaticLifetime<TypeWhichDoesNotImplementAnyLifetime>,
320 >());
321 }
322
323 #[test]
324 fn test_provides_static_type_when_type_parameter_has_bound_with_lifetime() {
325 trait My<'a> {}
326
327 #[derive(ProvidesStaticType)]
328 struct FooBar<'x, P: My<'x>>(&'x P);
329 }
330}