numbat_codec/
try_static_cast.rs1use core::any::TypeId;
2
3pub trait TryStaticCast: Clone + 'static {
7 fn type_eq<U: TryStaticCast>() -> bool {
8 TypeId::of::<Self>() == TypeId::of::<U>()
9 }
10
11 #[inline]
12 fn try_cast<U: TryStaticCast>(self) -> Option<U> {
13 if Self::type_eq::<U>() {
14 let trans: U = unsafe { core::mem::transmute_copy(&self) };
15 core::mem::forget(self);
16 Some(trans)
17 } else {
18 None
19 }
20 }
21
22 #[inline]
23 fn try_cast_ref<U: TryStaticCast>(&self) -> Option<&U> {
24 if Self::type_eq::<U>() {
25 let trans = unsafe { core::mem::transmute::<&Self, &U>(self) };
26 Some(trans)
27 } else {
28 None
29 }
30 }
31}
32
33impl TryStaticCast for () {}
34
35fn type_eq<T, U>() -> bool
36where
37 T: 'static,
38 U: 'static,
39{
40 TypeId::of::<T>() == TypeId::of::<U>()
41}
42
43#[inline]
44pub fn try_cast_ref<T, U>(t: &T) -> Option<&U>
45where
46 T: 'static,
47 U: 'static,
48{
49 if type_eq::<T, U>() {
50 let trans = unsafe { core::mem::transmute::<&T, &U>(t) };
51 Some(trans)
52 } else {
53 None
54 }
55}
56
57#[inline]
58pub fn try_execute_then_cast<T, R, F>(f: F) -> Option<R>
59where
60 T: 'static,
61 R: 'static,
62 F: FnOnce() -> T,
63{
64 if type_eq::<T, R>() {
65 let result: T = f();
66 let transmuted_result: R = unsafe { core::mem::transmute_copy(&result) };
67 core::mem::forget(result);
68 Some(transmuted_result)
69 } else {
70 None
71 }
72}
73
74#[inline]
75pub fn try_cast_execute_or_else<T, U, R, If, Else>(t: T, exec_if: If, exec_else: Else) -> R
76where
77 T: 'static,
78 U: 'static,
79 R: 'static,
80 If: FnOnce(U) -> R,
81 Else: FnOnce(T) -> R,
82{
83 if type_eq::<T, U>() {
84 let transmuted: U = unsafe { core::mem::transmute_copy(&t) };
85 core::mem::forget(t);
86 exec_if(transmuted)
87 } else {
88 exec_else(t)
89 }
90}
91
92#[cfg(test)]
93mod test {
94 use super::TryStaticCast;
95
96 #[derive(Clone, PartialEq, Eq, Debug)]
97 struct SimpleType1(i32);
98
99 impl TryStaticCast for SimpleType1 {}
100
101 #[derive(Clone, PartialEq, Eq, Debug)]
102 struct SimpleType2(i32);
103
104 impl TryStaticCast for SimpleType2 {}
105
106 #[derive(Clone, PartialEq, Eq, Debug)]
107 struct GenericType<T> {
108 id: i32,
109 payload: T,
110 }
111
112 impl<T> GenericType<T> {
113 fn new(id: i32, payload: T) -> Self {
114 GenericType { id, payload }
115 }
116 }
117
118 impl<T: Clone + 'static> TryStaticCast for GenericType<T> {}
119
120 #[test]
121 fn test_try_static_cast_simple() {
122 let obj = SimpleType1(5);
123 assert_eq!(obj.clone().try_cast::<SimpleType1>(), Some(obj.clone()));
124 assert_eq!(obj.clone().try_cast::<SimpleType2>(), None);
125
126 assert_eq!(obj.try_cast_ref::<SimpleType1>(), Some(&obj));
127 assert_eq!(obj.try_cast_ref::<SimpleType2>(), None);
128 }
129
130 #[test]
131 fn test_try_static_cast_with_generics() {
132 let obj = GenericType::new(100, SimpleType1(5));
133 assert_eq!(
134 obj.clone().try_cast::<GenericType<SimpleType1>>(),
135 Some(obj.clone())
136 );
137 assert_eq!(obj.try_cast::<GenericType<SimpleType2>>(), None);
138 }
139}