1use std::any::TypeId;
12use std::collections::HashMap;
13
14pub use cityhasher;
16pub use dashmap;
18pub use typeuri_macros::Named;
20
21pub static ACTOR_PORT_BIT: u64 = 1 << 63;
23
24pub trait Named: Sized + 'static {
26 fn typename() -> &'static str;
29
30 fn typehash() -> u64 {
33 cityhasher::hash(Self::typename())
36 }
37
38 fn typeid() -> TypeId {
41 TypeId::of::<Self>()
42 }
43
44 fn port() -> u64 {
47 Self::typehash() | ACTOR_PORT_BIT
48 }
49
50 fn arm(&self) -> Option<&'static str> {
53 None
54 }
55
56 unsafe fn arm_unchecked(self_: *const ()) -> Option<&'static str> {
64 unsafe { &*(self_ as *const Self) }.arm()
66 }
67}
68
69macro_rules! impl_basic {
70 ($t:ty) => {
71 impl Named for $t {
72 fn typename() -> &'static str {
73 stringify!($t)
74 }
75 }
76 };
77}
78
79impl_basic!(());
80impl_basic!(bool);
81impl_basic!(i8);
82impl_basic!(u8);
83impl_basic!(i16);
84impl_basic!(u16);
85impl_basic!(i32);
86impl_basic!(u32);
87impl_basic!(i64);
88impl_basic!(u64);
89impl_basic!(i128);
90impl_basic!(u128);
91impl_basic!(isize);
92impl_basic!(usize);
93impl_basic!(f32);
94impl_basic!(f64);
95impl_basic!(String);
96impl_basic!(std::net::IpAddr);
97impl_basic!(std::net::Ipv4Addr);
98impl_basic!(std::net::Ipv6Addr);
99impl_basic!(std::time::Duration);
100impl_basic!(std::time::SystemTime);
101impl_basic!(bytes::Bytes);
102
103impl Named for &'static str {
104 fn typename() -> &'static str {
105 "&str"
106 }
107}
108
109#[doc(hidden)] #[macro_export]
113macro_rules! intern_typename {
114 ($key:ty, $format_string:expr, $($args:ty),+) => {
115 {
116 static CACHE: std::sync::LazyLock<$crate::dashmap::DashMap<std::any::TypeId, &'static str>> =
117 std::sync::LazyLock::new($crate::dashmap::DashMap::new);
118
119 let typeid = std::any::TypeId::of::<$key>();
122 if let Some(value) = CACHE.get(&typeid) {
123 *value
124 } else {
125 let typename = format!($format_string, $(<$args>::typename()),+).leak();
126 CACHE.insert(typeid, typename);
127 typename
128 }
129 }
130 };
131}
132
133macro_rules! tuple_format_string {
134 ($a:ident,) => { "{}" };
135 ($a:ident, $($rest_a:ident,)+) => { concat!("{}, ", tuple_format_string!($($rest_a,)+)) };
136}
137
138macro_rules! impl_tuple_peel {
139 ($name:ident, $($other:ident,)*) => (impl_tuple! { $($other,)* })
140}
141
142macro_rules! impl_tuple {
143 () => ();
144 ( $($name:ident,)+ ) => (
145 impl<$($name:Named + 'static),+> Named for ($($name,)+) {
146 fn typename() -> &'static str {
147 intern_typename!(Self, concat!("(", tuple_format_string!($($name,)+), ")"), $($name),+)
148 }
149 }
150 impl_tuple_peel! { $($name,)+ }
151 )
152}
153
154impl_tuple! { E, D, C, B, A, Z, Y, X, W, V, U, T, }
155
156impl<T: Named + 'static> Named for Option<T> {
157 fn typename() -> &'static str {
158 intern_typename!(Self, "Option<{}>", T)
159 }
160}
161
162impl<T: Named + 'static> Named for Vec<T> {
163 fn typename() -> &'static str {
164 intern_typename!(Self, "Vec<{}>", T)
165 }
166}
167
168impl<K: Named + 'static, V: Named + 'static> Named for HashMap<K, V> {
169 fn typename() -> &'static str {
170 intern_typename!(Self, "HashMap<{}, {}>", K, V)
171 }
172}
173
174impl<T: Named + 'static, E: Named + 'static> Named for Result<T, E> {
175 fn typename() -> &'static str {
176 intern_typename!(Self, "Result<{}, {}>", T, E)
177 }
178}
179
180impl<T: Named + 'static> Named for std::ops::Range<T> {
181 fn typename() -> &'static str {
182 intern_typename!(Self, "std::ops::Range<{}>", T)
183 }
184}
185
186#[cfg(test)]
187mod tests {
188 use super::*;
189
190 #[test]
191 fn test_names() {
192 assert_eq!(String::typename(), "String");
193 assert_eq!(Option::<String>::typename(), "Option<String>");
194 assert_eq!(Vec::<String>::typename(), "Vec<String>");
195 assert_eq!(Vec::<Vec::<String>>::typename(), "Vec<Vec<String>>");
196 assert_eq!(
197 Vec::<Vec::<Vec::<String>>>::typename(),
198 "Vec<Vec<Vec<String>>>"
199 );
200 assert_eq!(
201 <(u64, String, Option::<isize>)>::typename(),
202 "(u64, String, Option<isize>)"
203 );
204 }
205
206 #[test]
207 fn test_ports() {
208 assert_eq!(String::typehash(), 3947244799002047352u64);
209 assert_eq!(String::port(), 13170616835856823160u64);
210 assert_ne!(
211 Vec::<Vec::<Vec::<String>>>::typehash(),
212 Vec::<Vec::<Vec::<Vec::<String>>>>::typehash(),
213 );
214 }
215}