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