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