wgpu_core/
storage.rs

1use std::ops;
2use std::sync::Arc;
3
4use wgt::Backend;
5
6use crate::id::Id;
7use crate::resource::Resource;
8use crate::{Epoch, Index};
9
10/// An entry in a `Storage::map` table.
11#[derive(Debug)]
12pub(crate) enum Element<T> {
13    /// There are no live ids with this index.
14    Vacant,
15
16    /// There is one live id with this index, allocated at the given
17    /// epoch.
18    Occupied(Arc<T>, Epoch),
19
20    /// Like `Occupied`, but an error occurred when creating the
21    /// resource.
22    ///
23    /// The given `String` is the resource's descriptor label.
24    Error(Epoch, String),
25}
26
27#[derive(Clone, Debug)]
28pub(crate) struct InvalidId;
29
30/// A table of `T` values indexed by the id type `I`.
31///
32/// `Storage` implements [`std::ops::Index`], accepting `Id` values as
33/// indices.
34///
35/// The table is represented as a vector indexed by the ids' index
36/// values, so you should use an id allocator like `IdentityManager`
37/// that keeps the index values dense and close to zero.
38#[derive(Debug)]
39pub(crate) struct Storage<T>
40where
41    T: Resource,
42{
43    pub(crate) map: Vec<Element<T>>,
44    kind: &'static str,
45}
46
47impl<T> ops::Index<Id<T::Marker>> for Storage<T>
48where
49    T: Resource,
50{
51    type Output = Arc<T>;
52    fn index(&self, id: Id<T::Marker>) -> &Arc<T> {
53        self.get(id).unwrap()
54    }
55}
56impl<T> Storage<T>
57where
58    T: Resource,
59{
60    pub(crate) fn new() -> Self {
61        Self {
62            map: Vec::new(),
63            kind: T::TYPE,
64        }
65    }
66}
67
68impl<T> Storage<T>
69where
70    T: Resource,
71{
72    #[allow(dead_code)]
73    pub(crate) fn contains(&self, id: Id<T::Marker>) -> bool {
74        let (index, epoch, _) = id.unzip();
75        match self.map.get(index as usize) {
76            Some(&Element::Vacant) => false,
77            Some(&Element::Occupied(_, storage_epoch) | &Element::Error(storage_epoch, _)) => {
78                storage_epoch == epoch
79            }
80            None => false,
81        }
82    }
83
84    /// Attempts to get a reference to an item behind a potentially invalid ID.
85    ///
86    /// Returns [`None`] if there is an epoch mismatch, or the entry is empty.
87    ///
88    /// This function is primarily intended for the `as_hal` family of functions
89    /// where you may need to fallibly get a object backed by an id that could
90    /// be in a different hub.
91    pub(crate) fn try_get(&self, id: Id<T::Marker>) -> Result<Option<&Arc<T>>, InvalidId> {
92        let (index, epoch, _) = id.unzip();
93        let (result, storage_epoch) = match self.map.get(index as usize) {
94            Some(&Element::Occupied(ref v, epoch)) => (Ok(Some(v)), epoch),
95            Some(&Element::Vacant) => return Ok(None),
96            Some(&Element::Error(epoch, ..)) => (Err(InvalidId), epoch),
97            None => return Err(InvalidId),
98        };
99        assert_eq!(
100            epoch, storage_epoch,
101            "{}[{:?}] is no longer alive",
102            self.kind, id
103        );
104        result
105    }
106
107    /// Get a reference to an item behind a potentially invalid ID.
108    /// Panics if there is an epoch mismatch, or the entry is empty.
109    pub(crate) fn get(&self, id: Id<T::Marker>) -> Result<&Arc<T>, InvalidId> {
110        let (index, epoch, _) = id.unzip();
111        let (result, storage_epoch) = match self.map.get(index as usize) {
112            Some(&Element::Occupied(ref v, epoch)) => (Ok(v), epoch),
113            Some(&Element::Vacant) => panic!("{}[{:?}] does not exist", self.kind, id),
114            Some(&Element::Error(epoch, ..)) => (Err(InvalidId), epoch),
115            None => return Err(InvalidId),
116        };
117        assert_eq!(
118            epoch, storage_epoch,
119            "{}[{:?}] is no longer alive",
120            self.kind, id
121        );
122        result
123    }
124
125    /// Get an owned reference to an item behind a potentially invalid ID.
126    /// Panics if there is an epoch mismatch, or the entry is empty.
127    pub(crate) fn get_owned(&self, id: Id<T::Marker>) -> Result<Arc<T>, InvalidId> {
128        Ok(Arc::clone(self.get(id)?))
129    }
130
131    pub(crate) fn label_for_invalid_id(&self, id: Id<T::Marker>) -> &str {
132        let (index, _, _) = id.unzip();
133        match self.map.get(index as usize) {
134            Some(Element::Error(_, label)) => label,
135            _ => "",
136        }
137    }
138
139    fn insert_impl(&mut self, index: usize, epoch: Epoch, element: Element<T>) {
140        if index >= self.map.len() {
141            self.map.resize_with(index + 1, || Element::Vacant);
142        }
143        match std::mem::replace(&mut self.map[index], element) {
144            Element::Vacant => {}
145            Element::Occupied(_, storage_epoch) => {
146                assert_ne!(
147                    epoch,
148                    storage_epoch,
149                    "Index {index:?} of {} is already occupied",
150                    T::TYPE
151                );
152            }
153            Element::Error(storage_epoch, _) => {
154                assert_ne!(
155                    epoch,
156                    storage_epoch,
157                    "Index {index:?} of {} is already occupied with Error",
158                    T::TYPE
159                );
160            }
161        }
162    }
163
164    pub(crate) fn insert(&mut self, id: Id<T::Marker>, value: Arc<T>) {
165        log::trace!("User is inserting {}{:?}", T::TYPE, id);
166        let (index, epoch, _backend) = id.unzip();
167        self.insert_impl(index as usize, epoch, Element::Occupied(value, epoch))
168    }
169
170    pub(crate) fn insert_error(&mut self, id: Id<T::Marker>, label: &str) {
171        log::trace!("User is inserting as error {}{:?}", T::TYPE, id);
172        let (index, epoch, _) = id.unzip();
173        self.insert_impl(
174            index as usize,
175            epoch,
176            Element::Error(epoch, label.to_string()),
177        )
178    }
179
180    pub(crate) fn replace_with_error(&mut self, id: Id<T::Marker>) -> Result<Arc<T>, InvalidId> {
181        let (index, epoch, _) = id.unzip();
182        match std::mem::replace(
183            &mut self.map[index as usize],
184            Element::Error(epoch, String::new()),
185        ) {
186            Element::Vacant => panic!("Cannot access vacant resource"),
187            Element::Occupied(value, storage_epoch) => {
188                assert_eq!(epoch, storage_epoch);
189                Ok(value)
190            }
191            _ => Err(InvalidId),
192        }
193    }
194
195    pub(crate) fn force_replace(&mut self, id: Id<T::Marker>, value: T) {
196        log::trace!("User is replacing {}{:?}", T::TYPE, id);
197        let (index, epoch, _) = id.unzip();
198        self.map[index as usize] = Element::Occupied(Arc::new(value), epoch);
199    }
200
201    pub(crate) fn remove(&mut self, id: Id<T::Marker>) -> Option<Arc<T>> {
202        log::trace!("User is removing {}{:?}", T::TYPE, id);
203        let (index, epoch, _) = id.unzip();
204        match std::mem::replace(&mut self.map[index as usize], Element::Vacant) {
205            Element::Occupied(value, storage_epoch) => {
206                assert_eq!(epoch, storage_epoch);
207                Some(value)
208            }
209            Element::Error(..) => None,
210            Element::Vacant => panic!("Cannot remove a vacant resource"),
211        }
212    }
213
214    pub(crate) fn iter(&self, backend: Backend) -> impl Iterator<Item = (Id<T::Marker>, &Arc<T>)> {
215        self.map
216            .iter()
217            .enumerate()
218            .filter_map(move |(index, x)| match *x {
219                Element::Occupied(ref value, storage_epoch) => {
220                    Some((Id::zip(index as Index, storage_epoch, backend), value))
221                }
222                _ => None,
223            })
224    }
225
226    pub(crate) fn kind(&self) -> &str {
227        self.kind
228    }
229
230    pub(crate) fn len(&self) -> usize {
231        self.map.len()
232    }
233}