markdown_that/common/
typekey.rs

1use std::any::{self, TypeId};
2use std::fmt::{self, Debug};
3use std::hash::{Hash, Hasher};
4
5#[readonly::make]
6#[derive(Clone, Copy)]
7/// [std::any::TypeId] and [std::any::type_name] fused into one struct.
8///
9/// It acts as TypeId when hashed or compared, and it acts as type_name when printed.
10/// Used to improve debuggability of type ids in hashmaps in particular.
11/// ```
12/// # use markdown_that::common::TypeKey;
13/// struct A;
14/// struct B;
15///
16/// let mut set = std::collections::HashSet::new();
17///
18/// set.insert(TypeKey::of::<A>());
19/// set.insert(TypeKey::of::<B>());
20///
21/// assert!(set.contains(&TypeKey::of::<A>()));
22/// dbg!(set);
23/// ```
24pub struct TypeKey {
25    /// type id (read-only)
26    pub id: TypeId,
27    /// type name (read-only)
28    pub name: &'static str,
29}
30
31impl TypeKey {
32    #[must_use]
33    /// Similar to [TypeId::of](TypeId::of), returns `TypeKey`
34    /// of the type this generic function has been instantiated with.
35    pub fn of<T: ?Sized + 'static>() -> Self {
36        Self {
37            id: TypeId::of::<T>(),
38            name: any::type_name::<T>(),
39        }
40    }
41}
42
43impl Hash for TypeKey {
44    fn hash<H: Hasher>(&self, state: &mut H) {
45        self.id.hash(state);
46    }
47}
48
49impl PartialEq for TypeKey {
50    fn eq(&self, other: &Self) -> bool {
51        self.id == other.id
52    }
53}
54
55impl Eq for TypeKey {}
56
57impl Debug for TypeKey {
58    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59        write!(f, "{}", self.name)
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use super::TypeKey;
66
67    #[test]
68    fn typekey_eq() {
69        struct A;
70        struct B;
71        assert_eq!(
72            TypeKey {
73                id: std::any::TypeId::of::<A>(),
74                name: "foo"
75            },
76            TypeKey {
77                id: std::any::TypeId::of::<A>(),
78                name: "bar"
79            }
80        );
81        assert_ne!(
82            TypeKey {
83                id: std::any::TypeId::of::<A>(),
84                name: "foo"
85            },
86            TypeKey {
87                id: std::any::TypeId::of::<B>(),
88                name: "foo"
89            }
90        );
91    }
92
93    #[test]
94    fn typekey_of() {
95        struct A;
96        struct B;
97        assert_eq!(TypeKey::of::<A>(), TypeKey::of::<A>());
98        assert_ne!(TypeKey::of::<A>(), TypeKey::of::<B>());
99    }
100}