1use std::sync::Arc;
2
3use wgt::Backend;
4
5use crate::{
6 id::Id,
7 identity::IdentityManager,
8 lock::{rank, RwLock, RwLockReadGuard, RwLockWriteGuard},
9 resource::Resource,
10 storage::{Element, InvalidId, Storage},
11};
12
13#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
14pub struct RegistryReport {
15 pub num_allocated: usize,
16 pub num_kept_from_user: usize,
17 pub num_released_from_user: usize,
18 pub num_error: usize,
19 pub element_size: usize,
20}
21
22impl RegistryReport {
23 pub fn is_empty(&self) -> bool {
24 self.num_allocated + self.num_kept_from_user == 0
25 }
26}
27
28#[derive(Debug)]
40pub(crate) struct Registry<T: Resource> {
41 identity: Arc<IdentityManager<T::Marker>>,
43 storage: RwLock<Storage<T>>,
44 backend: Backend,
45}
46
47impl<T: Resource> Registry<T> {
48 pub(crate) fn new(backend: Backend) -> Self {
49 Self {
50 identity: Arc::new(IdentityManager::new()),
51 storage: RwLock::new(rank::REGISTRY_STORAGE, Storage::new()),
52 backend,
53 }
54 }
55
56 pub(crate) fn without_backend() -> Self {
57 Self::new(Backend::Empty)
58 }
59}
60
61#[must_use]
62pub(crate) struct FutureId<'a, T: Resource> {
63 id: Id<T::Marker>,
64 data: &'a RwLock<Storage<T>>,
65}
66
67impl<T: Resource> FutureId<'_, T> {
68 #[allow(dead_code)]
69 pub fn id(&self) -> Id<T::Marker> {
70 self.id
71 }
72
73 pub fn into_id(self) -> Id<T::Marker> {
74 self.id
75 }
76
77 pub fn init(&self, mut value: T) -> Arc<T> {
78 value.as_info_mut().set_id(self.id);
79 Arc::new(value)
80 }
81
82 pub fn init_in_place(&self, mut value: Arc<T>) -> Arc<T> {
83 Arc::get_mut(&mut value)
84 .unwrap()
85 .as_info_mut()
86 .set_id(self.id);
87 value
88 }
89
90 pub fn assign(self, value: Arc<T>) -> (Id<T::Marker>, Arc<T>) {
94 let mut data = self.data.write();
95 data.insert(self.id, self.init_in_place(value));
96 (self.id, data.get(self.id).unwrap().clone())
97 }
98
99 pub fn assign_existing(self, value: &Arc<T>) -> Id<T::Marker> {
103 let mut data = self.data.write();
104 debug_assert!(!data.contains(self.id));
105 data.insert(self.id, value.clone());
106 self.id
107 }
108
109 pub fn assign_error(self, label: &str) -> Id<T::Marker> {
110 self.data.write().insert_error(self.id, label);
111 self.id
112 }
113}
114
115impl<T: Resource> Registry<T> {
116 pub(crate) fn prepare(&self, id_in: Option<Id<T::Marker>>) -> FutureId<T> {
117 FutureId {
118 id: match id_in {
119 Some(id_in) => {
120 self.identity.mark_as_used(id_in);
121 id_in
122 }
123 None => self.identity.process(self.backend),
124 },
125 data: &self.storage,
126 }
127 }
128
129 pub(crate) fn request(&self) -> FutureId<T> {
130 FutureId {
131 id: self.identity.process(self.backend),
132 data: &self.storage,
133 }
134 }
135 pub(crate) fn try_get(&self, id: Id<T::Marker>) -> Result<Option<Arc<T>>, InvalidId> {
136 self.read().try_get(id).map(|o| o.cloned())
137 }
138 pub(crate) fn get(&self, id: Id<T::Marker>) -> Result<Arc<T>, InvalidId> {
139 self.read().get_owned(id)
140 }
141 pub(crate) fn read<'a>(&'a self) -> RwLockReadGuard<'a, Storage<T>> {
142 self.storage.read()
143 }
144 pub(crate) fn write<'a>(&'a self) -> RwLockWriteGuard<'a, Storage<T>> {
145 self.storage.write()
146 }
147 pub(crate) fn unregister_locked(
148 &self,
149 id: Id<T::Marker>,
150 storage: &mut Storage<T>,
151 ) -> Option<Arc<T>> {
152 self.identity.free(id);
153 storage.remove(id)
154 }
155 pub(crate) fn force_replace(&self, id: Id<T::Marker>, mut value: T) {
156 let mut storage = self.storage.write();
157 value.as_info_mut().set_id(id);
158 storage.force_replace(id, value)
159 }
160 pub(crate) fn force_replace_with_error(&self, id: Id<T::Marker>, label: &str) {
161 let mut storage = self.storage.write();
162 storage.remove(id);
163 storage.insert_error(id, label);
164 }
165 pub(crate) fn unregister(&self, id: Id<T::Marker>) -> Option<Arc<T>> {
166 let value = self.storage.write().remove(id);
167 self.identity.free(id);
171 value
173 }
174
175 pub(crate) fn label_for_resource(&self, id: Id<T::Marker>) -> String {
176 let guard = self.storage.read();
177
178 let type_name = guard.kind();
179 match guard.get(id) {
180 Ok(res) => {
181 let label = res.label();
182 if label.is_empty() {
183 format!("<{}-{:?}>", type_name, id.unzip())
184 } else {
185 label
186 }
187 }
188 Err(_) => format!(
189 "<Invalid-{} label={}>",
190 type_name,
191 guard.label_for_invalid_id(id)
192 ),
193 }
194 }
195
196 pub(crate) fn generate_report(&self) -> RegistryReport {
197 let storage = self.storage.read();
198 let mut report = RegistryReport {
199 element_size: std::mem::size_of::<T>(),
200 ..Default::default()
201 };
202 report.num_allocated = self.identity.values.lock().count();
203 for element in storage.map.iter() {
204 match *element {
205 Element::Occupied(..) => report.num_kept_from_user += 1,
206 Element::Vacant => report.num_released_from_user += 1,
207 Element::Error(..) => report.num_error += 1,
208 }
209 }
210 report
211 }
212}
213
214#[cfg(test)]
215mod tests {
216 use std::sync::Arc;
217
218 use crate::{
219 id::Marker,
220 resource::{Resource, ResourceInfo, ResourceType},
221 };
222
223 use super::Registry;
224 struct TestData {
225 info: ResourceInfo<TestData>,
226 }
227 struct TestDataId;
228 impl Marker for TestDataId {}
229
230 impl Resource for TestData {
231 type Marker = TestDataId;
232
233 const TYPE: ResourceType = "Test data";
234
235 fn as_info(&self) -> &ResourceInfo<Self> {
236 &self.info
237 }
238
239 fn as_info_mut(&mut self) -> &mut ResourceInfo<Self> {
240 &mut self.info
241 }
242 }
243
244 #[test]
245 fn simultaneous_registration() {
246 let registry = Registry::without_backend();
247 std::thread::scope(|s| {
248 for _ in 0..5 {
249 s.spawn(|| {
250 for _ in 0..1000 {
251 let value = Arc::new(TestData {
252 info: ResourceInfo::new("Test data", None),
253 });
254 let new_id = registry.prepare(None);
255 let (id, _) = new_id.assign(value);
256 registry.unregister(id);
257 }
258 });
259 }
260 })
261 }
262}