1#![no_std]
3#![deny(unsafe_code, clippy::unwrap_used)]
4
5extern crate alloc;
6
7use core::any::{TypeId, type_name};
8use alloc::vec::Vec;
9
10#[derive(Debug, Clone, Copy, Eq, PartialEq)]
12pub struct Type{
13 pub id: TypeId,
14 pub name: &'static str
15}
16
17impl Type{
18 pub fn of<T: 'static>() -> Self{
19 Self{
20 id: TypeId::of::<T>(),
21 name: type_name::<T>()
22 }
23 }
24
25 pub fn of_val<T: 'static>(_: &T) -> Self{
26 Self{
27 id: TypeId::of::<T>(),
28 name: type_name::<T>()
29 }
30 }
31}
32
33pub trait TupleExt{
35 fn types() -> Vec<crate::Type>;
37 fn type_ids() -> Vec<core::any::TypeId>;
39 fn type_names() -> Vec<&'static str>;
41
42 fn self_types(&self) -> Vec<Type> { Self::types() }
44 fn self_type_ids(&self) -> Vec<TypeId> { Self::type_ids() }
46 fn self_type_names(&self) -> Vec<&'static str> { Self::type_names() }
48}
49
50#[doc(hidden)]
52macro_rules! impl_tuple_ext{
53 [$($t:ident), *] => {
54 impl<$($t: 'static), *> TupleExt for ($($t),*,) {
55 fn types() -> Vec<crate::Type> { alloc::vec![$(crate::Type::of::<$t>()), *] }
56 fn type_ids() -> Vec<core::any::TypeId> { alloc::vec![$(core::any::TypeId::of::<$t>()), *] }
57 fn type_names() -> Vec<&'static str> { alloc::vec![$(core::any::type_name::<$t>()), *] }
58 }
59 }
60}
61
62impl TupleExt for () {
63 fn types() -> Vec<crate::Type> { alloc::vec![] }
64 fn type_ids() -> Vec<core::any::TypeId> { alloc::vec![] }
65 fn type_names() -> Vec<&'static str> { alloc::vec![] }
66}
67
68impl_tuple_ext![T1];
69impl_tuple_ext![T1, T2];
70impl_tuple_ext![T1, T2, T3];
71impl_tuple_ext![T1, T2, T3, T4];
72impl_tuple_ext![T1, T2, T3, T4, T5];
73impl_tuple_ext![T1, T2, T3, T4, T5, T6];
74impl_tuple_ext![T1, T2, T3, T4, T5, T6, T7];
75
76#[cfg(test)]
77#[allow(dead_code)]
78mod tests {
79 use alloc::string::ToString as _;
80
81 use super::*;
82
83 #[test]
84 fn test_type_of() {
85 assert_eq!(Type::of::<i32>().name, "i32");
86 assert_eq!(Type::of_val(&"hello".to_string()).name, "alloc::string::String");
87 }
88
89 #[test]
90 fn test_tuple_ext() {
91 let tuple = (1, 2.0, 3, 4, "test", 6, -8);
92 assert_eq!(tuple.self_types().len(), 7);
93 assert_eq!(tuple.self_type_ids().len(), 7);
94 assert_eq!(tuple.self_type_names().len(), 7);
95 }
96
97 #[test]
98 fn test_tuple_ext_different_types() {
99 let tuple = (1, "hello", 3.14, true);
100 let types = tuple.self_types();
101 let type_names: Vec<&str> = types.iter().map(|t| t.name).collect();
102 let type_ids: Vec<TypeId> = types.iter().map(|t| t.id).collect();
103
104 assert_eq!(types.len(), 4);
105 assert_eq!(type_names, alloc::vec!["i32", "&str", "f64", "bool"]);
106 assert_eq!(type_ids.len(), 4);
107 }
108
109 #[test]
110 fn test_type_of_struct() {
111 #[derive(Debug)]
112 struct Person {
113 name: alloc::string::String,
114 age: u8,
115 }
116
117 let person: Person = Person {
118 name: "Proton".to_string(),
119 age: 14,
120 };
121
122 assert!(Type::of_val(&person).name.ends_with("test_type_of_struct::Person"));
123 }
124}
125