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