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