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