markdown_it/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_it::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](std::any::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 { id: TypeId::of::<T>(), name: any::type_name::<T>() }
37    }
38}
39
40impl Hash for TypeKey {
41    fn hash<H: Hasher>(&self, state: &mut H) {
42        self.id.hash(state);
43    }
44}
45
46impl PartialEq for TypeKey {
47    fn eq(&self, other: &Self) -> bool {
48        self.id == other.id
49    }
50}
51
52impl Eq for TypeKey {}
53
54impl Debug for TypeKey {
55    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56        write!(f, "{}", self.name)
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use super::TypeKey;
63
64    #[test]
65    fn typekey_eq() {
66        struct A;
67        struct B;
68        assert_eq!(TypeKey { id: std::any::TypeId::of::<A>(), name: "foo" },
69                   TypeKey { id: std::any::TypeId::of::<A>(), name: "bar" });
70        assert_ne!(TypeKey { id: std::any::TypeId::of::<A>(), name: "foo" },
71                   TypeKey { id: std::any::TypeId::of::<B>(), name: "foo" });
72    }
73
74    #[test]
75    fn typekey_of() {
76        struct A;
77        struct B;
78        assert_eq!(TypeKey::of::<A>(), TypeKey::of::<A>());
79        assert_ne!(TypeKey::of::<A>(), TypeKey::of::<B>());
80    }
81}