wgpu_core/
registry.rs
1use alloc::sync::Arc;
2
3use crate::{
4 id::Id,
5 identity::IdentityManager,
6 lock::{rank, RwLock, RwLockReadGuard},
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 #[cfg(feature = "trace")]
59 pub fn id(&self) -> Id<T::Marker> {
60 self.id
61 }
62
63 pub fn assign(self, value: T) -> Id<T::Marker> {
67 let mut data = self.data.write();
68 data.insert(self.id, value);
69 self.id
70 }
71}
72
73impl<T: StorageItem> Registry<T> {
74 pub(crate) fn prepare(&self, id_in: Option<Id<T::Marker>>) -> FutureId<'_, T> {
75 FutureId {
76 id: match id_in {
77 Some(id_in) => {
78 self.identity.mark_as_used(id_in);
79 id_in
80 }
81 None => self.identity.process(),
82 },
83 data: &self.storage,
84 }
85 }
86
87 #[track_caller]
88 pub(crate) fn read<'a>(&'a self) -> RwLockReadGuard<'a, Storage<T>> {
89 self.storage.read()
90 }
91 pub(crate) fn remove(&self, id: Id<T::Marker>) -> T {
92 let value = self.storage.write().remove(id);
93 self.identity.free(id);
97 value
99 }
100
101 pub(crate) fn generate_report(&self) -> RegistryReport {
102 let storage = self.storage.read();
103 let mut report = RegistryReport {
104 element_size: size_of::<T>(),
105 ..Default::default()
106 };
107 report.num_allocated = self.identity.values.lock().count();
108 for element in storage.map.iter() {
109 match *element {
110 Element::Occupied(..) => report.num_kept_from_user += 1,
111 Element::Vacant => report.num_released_from_user += 1,
112 }
113 }
114 report
115 }
116}
117
118impl<T: StorageItem + Clone> Registry<T> {
119 pub(crate) fn get(&self, id: Id<T::Marker>) -> T {
120 self.read().get(id)
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 use super::Registry;
127 use crate::{id::Marker, resource::ResourceType, storage::StorageItem};
128 use alloc::sync::Arc;
129
130 struct TestData;
131 struct TestDataId;
132 impl Marker for TestDataId {}
133
134 impl ResourceType for TestData {
135 const TYPE: &'static str = "TestData";
136 }
137 impl StorageItem for TestData {
138 type Marker = TestDataId;
139 }
140
141 #[test]
142 fn simultaneous_registration() {
143 let registry = Registry::new();
144 std::thread::scope(|s| {
145 for _ in 0..5 {
146 s.spawn(|| {
147 for _ in 0..1000 {
148 let value = Arc::new(TestData);
149 let new_id = registry.prepare(None);
150 let id = new_id.assign(value);
151 registry.remove(id);
152 }
153 });
154 }
155 })
156 }
157}