type_registry/logical/
registration_id.rs

1use std::any::TypeId;
2use std::borrow::Borrow;
3use std::fmt::{Debug, Display, Formatter};
4use std::hash::{Hash, Hasher};
5use std::marker::PhantomData;
6use crate::logical::{Registered, RegistryEntry, RegistryExt};
7use crate::logical::registry::Registry;
8use crate::raw::{RegistrationId as RawRegistrationId, RegistryEntry as RawRegistryEntry};
9
10/// Identifies a [registered](Registered) type in a particular [registry](Registry).
11pub struct RegistrationId<R: Registry + ?Sized> {
12    /// The registration's raw identifier 
13    raw_id: RawRegistrationId,
14    /// The position of the type's registration within the particular registry
15    registry_index: usize,
16    /// Marker of the registry to which the type is registered
17    registry: PhantomData<fn(R)>
18}
19
20impl<R: Registry + ?Sized> RegistrationId<R> {
21    pub(crate) fn new(
22        raw_index: usize,
23        registry_index: usize
24    ) -> Self {
25        Self {
26            raw_id: RawRegistrationId::new(raw_index),
27            registry_index,
28            registry: PhantomData
29        }
30    }
31
32    #[allow(dead_code)]
33    pub(crate) fn raw(self) -> RawRegistrationId {
34        self.raw_id
35    }
36    
37    /// The position of the identified type in the registry.
38    pub fn index(self) -> usize {
39        self.registry_index
40    }
41
42    /// Gets the 
43    pub fn entry(self) -> RegistryEntry<R> {
44        // SAFETY: raw_id is for R
45        unsafe { RegistryEntry::new_unchecked(self.raw_id.entry()) }
46    }
47
48    pub fn metadata(self) -> &'static R::TypeInfo {
49        self.entry().type_info()
50    }
51
52    pub fn of<T: Registered<R> + ?Sized>() -> Self {
53        // SAFETY: T is registered to R
54        unsafe {
55            Self::from_type_id_unchecked(TypeId::of::<T>())
56        }
57    }
58
59    /// SAFETY: raw_entry must be for R
60    pub(crate) unsafe fn from_raw_entry_unchecked(raw_entry: &RawRegistryEntry) -> Self {
61        Self::from_type_id_unchecked(raw_entry.type_id())
62    }
63
64    /// SAFETY: type_id must be a type registered to R
65    pub(crate) unsafe fn from_type_id_unchecked(type_id: TypeId) -> Self {
66        *R::index::<RawRegistryEntry>().get(&type_id).expect("type is registered")
67    }
68}
69
70// Have to manually derive Copy/Clone, as the derive macro requires a Sized bound.
71
72impl<R: Registry + ?Sized> Clone for RegistrationId<R> {
73    fn clone(&self) -> Self {
74        Self::new(self.raw_id.index(), self.registry_index)
75    }
76}
77
78impl<R: Registry + ?Sized> Copy for RegistrationId<R> {}
79
80// Have to manually derive PartialEq, Eq, Debug, Display and Hash in presence of PhantomData.
81// Although the implementation of these traits for PhantomData<R> in no way depends on
82// implementations for R, the derive macro requires that R does implement them. We don't want to
83// burden implementations of Registry with implementing these traits (as all implementations of
84// Registry are ZSTs and therefore there is no non-trivial implementation).
85
86impl<R: Registry + ?Sized> Debug for RegistrationId<R> {
87    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
88        // TODO: Const formatting of type name?
89        f.debug_struct(&format!("RegistrationId<{}>", std::any::type_name::<R>()))
90            .field("raw_id", &self.raw_id)
91            .field("registry_index", &self.registry_index)
92            .field("registry", &R::name())
93            .finish()
94    }
95}
96
97impl<R: Registry + ?Sized> PartialEq for RegistrationId<R> {
98    fn eq(&self, other: &Self) -> bool {
99        self.raw_id == other.raw_id
100    }
101}
102
103impl<R: Registry + ?Sized> Eq for RegistrationId<R> {}
104
105impl<R: Registry + ?Sized> Hash for RegistrationId<R> {
106    fn hash<H: Hasher>(&self, state: &mut H) {
107        self.raw_id.hash(state)
108    }
109}
110
111impl<R: Registry + ?Sized> Display for RegistrationId<R> {
112    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
113        let index = self.registry_index;
114        let name = R::name();
115        f.write_fmt(format_args!("'{name}' registration ID #{index}"))
116    }
117}
118
119impl<R: Registry + ?Sized> From<RegistrationId<R>> for RawRegistrationId {
120    fn from(value: RegistrationId<R>) -> Self {
121        value.raw_id
122    }
123}
124
125impl<R: Registry + ?Sized> PartialEq<RawRegistrationId> for RegistrationId<R> {
126    fn eq(&self, other: &RawRegistrationId) -> bool {
127        &self.raw_id == other
128    }
129}
130
131impl<R: Registry + ?Sized> PartialEq<RegistrationId<R>> for RawRegistrationId {
132    fn eq(&self, other: &RegistrationId<R>) -> bool {
133        self == &other.raw_id
134    }
135}
136
137impl<R: Registry + ?Sized> Borrow<RawRegistrationId> for RegistrationId<R> {
138    fn borrow(&self) -> &RawRegistrationId {
139        &self.raw_id
140    }
141}