1use alloc::sync::Arc;
2
3use crate::{
4 id::Id,
5 identity::IdentityManager,
6 lock::{
7 rank::{self, LockRank},
8 RwLock, RwLockReadGuard,
9 },
10 storage::{Element, Storage, StorageItem},
11};
12
13#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
14pub struct RegistryReport {
15 pub num_allocated: usize,
21 pub num_kept_from_user: usize,
22 pub num_released_from_user: usize,
23 pub element_size: usize,
24}
25
26impl RegistryReport {
27 pub fn is_empty(&self) -> bool {
28 self.num_allocated + self.num_kept_from_user == 0
29 }
30}
31
32#[derive(Debug)]
44pub(crate) struct Registry<T: StorageItem> {
45 identity: Arc<IdentityManager<T::Marker>>,
47 storage: RwLock<Storage<T>>,
48}
49
50impl<T: StorageItem> Registry<T> {
51 pub(crate) fn new() -> Self {
52 Self::with_rank(rank::HUB_OTHER)
53 }
54
55 pub(crate) fn with_rank(rank: LockRank) -> Self {
56 Self {
57 identity: Arc::new(IdentityManager::new()),
58 storage: RwLock::new(rank, Storage::new()),
59 }
60 }
61}
62
63#[must_use]
64pub(crate) struct FutureId<'a, T: StorageItem> {
65 id: Id<T::Marker>,
66 data: &'a RwLock<Storage<T>>,
67}
68
69impl<T: StorageItem> FutureId<'_, T> {
70 pub fn assign(self, value: T) -> Id<T::Marker> {
74 let mut data = self.data.write();
75 data.insert(self.id, value);
76 self.id
77 }
78}
79
80impl<T: StorageItem> Registry<T> {
81 pub(crate) fn prepare(&self, id_in: Option<Id<T::Marker>>) -> FutureId<'_, T> {
82 FutureId {
83 id: match id_in {
84 Some(id_in) => {
85 self.identity.mark_as_used(id_in);
86 id_in
87 }
88 None => self.identity.process(),
89 },
90 data: &self.storage,
91 }
92 }
93
94 #[track_caller]
95 pub(crate) fn read<'a>(&'a self) -> RwLockReadGuard<'a, Storage<T>> {
96 self.storage.read()
97 }
98 pub(crate) fn remove(&self, id: Id<T::Marker>) -> T {
99 let value = self.storage.write().remove(id);
100 self.identity.free(id);
104 value
106 }
107
108 pub(crate) fn generate_report(&self) -> RegistryReport {
109 let mut report = RegistryReport {
110 element_size: size_of::<T>(),
111 ..Default::default()
112 };
113
114 report.num_allocated = self.identity.values.lock().count();
119
120 let storage = self.storage.read();
121 for element in storage.map.iter() {
122 match *element {
123 Element::Occupied(..) => report.num_kept_from_user += 1,
124 Element::Vacant => report.num_released_from_user += 1,
125 }
126 }
127 report
128 }
129}
130
131impl<T: StorageItem + Clone> Registry<T> {
132 pub(crate) fn get(&self, id: Id<T::Marker>) -> T {
133 self.read().get(id)
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use super::Registry;
140 use crate::{id::Marker, resource::ResourceType, storage::StorageItem};
141 use alloc::sync::Arc;
142
143 struct TestData;
144 struct TestDataId;
145 impl Marker for TestDataId {
146 const TYPE: &'static str = "TestData";
147 }
148
149 impl ResourceType for TestData {
150 const TYPE: &'static str = "TestData";
151 }
152 impl StorageItem for TestData {
153 type Marker = TestDataId;
154 }
155
156 #[test]
157 fn simultaneous_registration() {
158 let registry = Registry::new();
159 std::thread::scope(|s| {
160 for _ in 0..5 {
161 s.spawn(|| {
162 for _ in 0..1000 {
163 let value = Arc::new(TestData);
164 let new_id = registry.prepare(None);
165 let id = new_id.assign(value);
166 registry.remove(id);
167 }
168 });
169 }
170 })
171 }
172}