wgpu_core/registry.rs
1use std::marker::PhantomData;
2
3use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
4use wgt::Backend;
5
6use crate::{
7 hub::{Access, Token},
8 id,
9 identity::{IdentityHandler, IdentityHandlerFactory},
10 resource::Resource,
11 storage::Storage,
12};
13
14#[derive(Debug)]
15pub struct Registry<T: Resource, I: id::TypedId, F: IdentityHandlerFactory<I>> {
16 identity: F::Filter,
17 pub(crate) data: RwLock<Storage<T, I>>,
18 backend: Backend,
19}
20
21impl<T: Resource, I: id::TypedId, F: IdentityHandlerFactory<I>> Registry<T, I, F> {
22 pub(crate) fn new(backend: Backend, factory: &F) -> Self {
23 Self {
24 identity: factory.spawn(),
25 data: RwLock::new(Storage {
26 map: Vec::new(),
27 kind: T::TYPE,
28 _phantom: PhantomData,
29 }),
30 backend,
31 }
32 }
33
34 pub(crate) fn without_backend(factory: &F, kind: &'static str) -> Self {
35 Self {
36 identity: factory.spawn(),
37 data: RwLock::new(Storage {
38 map: Vec::new(),
39 kind,
40 _phantom: PhantomData,
41 }),
42 backend: Backend::Empty,
43 }
44 }
45}
46
47#[must_use]
48pub(crate) struct FutureId<'a, I: id::TypedId, T> {
49 id: I,
50 data: &'a RwLock<Storage<T, I>>,
51}
52
53impl<I: id::TypedId + Copy, T> FutureId<'_, I, T> {
54 #[cfg(feature = "trace")]
55 pub fn id(&self) -> I {
56 self.id
57 }
58
59 pub fn into_id(self) -> I {
60 self.id
61 }
62
63 pub fn assign<'a, A: Access<T>>(self, value: T, _: &'a mut Token<A>) -> id::Valid<I> {
64 self.data.write().insert(self.id, value);
65 id::Valid(self.id)
66 }
67
68 pub fn assign_error<'a, A: Access<T>>(self, label: &str, _: &'a mut Token<A>) -> I {
69 self.data.write().insert_error(self.id, label);
70 self.id
71 }
72}
73
74impl<T: Resource, I: id::TypedId + Copy, F: IdentityHandlerFactory<I>> Registry<T, I, F> {
75 pub(crate) fn prepare(
76 &self,
77 id_in: <F::Filter as IdentityHandler<I>>::Input,
78 ) -> FutureId<I, T> {
79 FutureId {
80 id: self.identity.process(id_in, self.backend),
81 data: &self.data,
82 }
83 }
84
85 /// Acquire read access to this `Registry`'s contents.
86 ///
87 /// The caller must present a mutable reference to a `Token<A>`,
88 /// for some type `A` that comes before this `Registry`'s resource
89 /// type `T` in the lock ordering. A `Token<Root>` grants
90 /// permission to lock any field; see [`Token::root`].
91 ///
92 /// Once the read lock is acquired, return a new `Token<T>`, along
93 /// with a read guard for this `Registry`'s [`Storage`], which can
94 /// be indexed by id to get at the actual resources.
95 ///
96 /// The borrow checker ensures that the caller cannot again access
97 /// its `Token<A>` until it has dropped both the guard and the
98 /// `Token<T>`.
99 ///
100 /// See the [`Hub`] type for more details on locking.
101 ///
102 /// [`Hub`]: crate::hub::Hub
103 pub(crate) fn read<'a, A: Access<T>>(
104 &'a self,
105 _token: &'a mut Token<A>,
106 ) -> (RwLockReadGuard<'a, Storage<T, I>>, Token<'a, T>) {
107 (self.data.read(), Token::new())
108 }
109
110 /// Acquire write access to this `Registry`'s contents.
111 ///
112 /// The caller must present a mutable reference to a `Token<A>`,
113 /// for some type `A` that comes before this `Registry`'s resource
114 /// type `T` in the lock ordering. A `Token<Root>` grants
115 /// permission to lock any field; see [`Token::root`].
116 ///
117 /// Once the lock is acquired, return a new `Token<T>`, along with
118 /// a write guard for this `Registry`'s [`Storage`], which can be
119 /// indexed by id to get at the actual resources.
120 ///
121 /// The borrow checker ensures that the caller cannot again access
122 /// its `Token<A>` until it has dropped both the guard and the
123 /// `Token<T>`.
124 ///
125 /// See the [`Hub`] type for more details on locking.
126 ///
127 /// [`Hub`]: crate::hub::Hub
128 pub(crate) fn write<'a, A: Access<T>>(
129 &'a self,
130 _token: &'a mut Token<A>,
131 ) -> (RwLockWriteGuard<'a, Storage<T, I>>, Token<'a, T>) {
132 (self.data.write(), Token::new())
133 }
134
135 /// Unregister the resource at `id`.
136 ///
137 /// The caller must prove that it already holds a write lock for
138 /// this `Registry` by passing a mutable reference to this
139 /// `Registry`'s storage, obtained from the write guard returned
140 /// by a previous call to [`write`], as the `guard` parameter.
141 pub fn unregister_locked(&self, id: I, guard: &mut Storage<T, I>) -> Option<T> {
142 let value = guard.remove(id);
143 //Note: careful about the order here!
144 self.identity.free(id);
145 //Returning None is legal if it's an error ID
146 value
147 }
148
149 /// Unregister the resource at `id` and return its value, if any.
150 ///
151 /// The caller must present a mutable reference to a `Token<A>`,
152 /// for some type `A` that comes before this `Registry`'s resource
153 /// type `T` in the lock ordering.
154 ///
155 /// This returns a `Token<T>`, but it's almost useless, because it
156 /// doesn't return a lock guard to go with it: its only effect is
157 /// to make the token you passed to this function inaccessible.
158 /// However, the `Token<T>` can be used to satisfy some functions'
159 /// bureacratic expectations that you will have one available.
160 ///
161 /// The borrow checker ensures that the caller cannot again access
162 /// its `Token<A>` until it has dropped both the guard and the
163 /// `Token<T>`.
164 ///
165 /// See the [`Hub`] type for more details on locking.
166 ///
167 /// [`Hub`]: crate::hub::Hub
168 pub(crate) fn unregister<'a, A: Access<T>>(
169 &self,
170 id: I,
171 _token: &'a mut Token<A>,
172 ) -> (Option<T>, Token<'a, T>) {
173 let value = self.data.write().remove(id);
174 //Note: careful about the order here!
175 self.identity.free(id);
176 //Returning None is legal if it's an error ID
177 (value, Token::new())
178 }
179
180 pub fn label_for_resource(&self, id: I) -> String {
181 let guard = self.data.read();
182
183 let type_name = guard.kind;
184 match guard.get(id) {
185 Ok(res) => {
186 let label = res.label();
187 if label.is_empty() {
188 format!("<{}-{:?}>", type_name, id.unzip())
189 } else {
190 label.to_string()
191 }
192 }
193 Err(_) => format!(
194 "<Invalid-{} label={}>",
195 type_name,
196 guard.label_for_invalid_id(id)
197 ),
198 }
199 }
200}