1use std::{marker::PhantomData, mem, ops};
2
3use wgt::Backend;
4
5use crate::{id, Epoch, Index};
6
7#[derive(Debug)]
9pub(crate) enum Element<T> {
10 Vacant,
12
13 Occupied(T, Epoch),
16
17 Error(Epoch, String),
22}
23
24#[derive(Clone, Debug, Default)]
25pub struct StorageReport {
26 pub num_occupied: usize,
27 pub num_vacant: usize,
28 pub num_error: usize,
29 pub element_size: usize,
30}
31
32impl StorageReport {
33 pub fn is_empty(&self) -> bool {
34 self.num_occupied + self.num_vacant + self.num_error == 0
35 }
36}
37
38#[derive(Clone, Debug)]
39pub(crate) struct InvalidId;
40
41#[derive(Debug)]
47pub struct Storage<T, I: id::TypedId> {
48 pub(crate) map: Vec<Element<T>>,
49 pub(crate) kind: &'static str,
50 pub(crate) _phantom: PhantomData<I>,
51}
52
53impl<T, I: id::TypedId> ops::Index<id::Valid<I>> for Storage<T, I> {
54 type Output = T;
55 fn index(&self, id: id::Valid<I>) -> &T {
56 self.get(id.0).unwrap()
57 }
58}
59
60impl<T, I: id::TypedId> ops::IndexMut<id::Valid<I>> for Storage<T, I> {
61 fn index_mut(&mut self, id: id::Valid<I>) -> &mut T {
62 self.get_mut(id.0).unwrap()
63 }
64}
65
66impl<T, I: id::TypedId> Storage<T, I> {
67 pub(crate) fn contains(&self, id: I) -> bool {
68 let (index, epoch, _) = id.unzip();
69 match self.map.get(index as usize) {
70 Some(&Element::Vacant) => false,
71 Some(&Element::Occupied(_, storage_epoch) | &Element::Error(storage_epoch, _)) => {
72 storage_epoch == epoch
73 }
74 None => false,
75 }
76 }
77
78 pub(crate) fn try_get(&self, id: I) -> Result<Option<&T>, InvalidId> {
86 let (index, epoch, _) = id.unzip();
87 let (result, storage_epoch) = match self.map.get(index as usize) {
88 Some(&Element::Occupied(ref v, epoch)) => (Ok(Some(v)), epoch),
89 Some(&Element::Vacant) => return Ok(None),
90 Some(&Element::Error(epoch, ..)) => (Err(InvalidId), epoch),
91 None => return Err(InvalidId),
92 };
93 assert_eq!(
94 epoch, storage_epoch,
95 "{}[{}] is no longer alive",
96 self.kind, index
97 );
98 result
99 }
100
101 pub(crate) fn get(&self, id: I) -> Result<&T, InvalidId> {
104 let (index, epoch, _) = id.unzip();
105 let (result, storage_epoch) = match self.map.get(index as usize) {
106 Some(&Element::Occupied(ref v, epoch)) => (Ok(v), epoch),
107 Some(&Element::Vacant) => panic!("{}[{}] does not exist", self.kind, index),
108 Some(&Element::Error(epoch, ..)) => (Err(InvalidId), epoch),
109 None => return Err(InvalidId),
110 };
111 assert_eq!(
112 epoch, storage_epoch,
113 "{}[{}] is no longer alive",
114 self.kind, index
115 );
116 result
117 }
118
119 pub(crate) fn get_mut(&mut self, id: I) -> Result<&mut T, InvalidId> {
122 let (index, epoch, _) = id.unzip();
123 let (result, storage_epoch) = match self.map.get_mut(index as usize) {
124 Some(&mut Element::Occupied(ref mut v, epoch)) => (Ok(v), epoch),
125 Some(&mut Element::Vacant) | None => panic!("{}[{}] does not exist", self.kind, index),
126 Some(&mut Element::Error(epoch, ..)) => (Err(InvalidId), epoch),
127 };
128 assert_eq!(
129 epoch, storage_epoch,
130 "{}[{}] is no longer alive",
131 self.kind, index
132 );
133 result
134 }
135
136 pub(crate) unsafe fn get_unchecked(&self, id: u32) -> &T {
137 match self.map[id as usize] {
138 Element::Occupied(ref v, _) => v,
139 Element::Vacant => panic!("{}[{}] does not exist", self.kind, id),
140 Element::Error(_, _) => panic!(""),
141 }
142 }
143
144 pub(crate) fn label_for_invalid_id(&self, id: I) -> &str {
145 let (index, _, _) = id.unzip();
146 match self.map.get(index as usize) {
147 Some(&Element::Error(_, ref label)) => label,
148 _ => "",
149 }
150 }
151
152 fn insert_impl(&mut self, index: usize, element: Element<T>) {
153 if index >= self.map.len() {
154 self.map.resize_with(index + 1, || Element::Vacant);
155 }
156 match std::mem::replace(&mut self.map[index], element) {
157 Element::Vacant => {}
158 _ => panic!("Index {index:?} is already occupied"),
159 }
160 }
161
162 pub(crate) fn insert(&mut self, id: I, value: T) {
163 let (index, epoch, _) = id.unzip();
164 self.insert_impl(index as usize, Element::Occupied(value, epoch))
165 }
166
167 pub(crate) fn insert_error(&mut self, id: I, label: &str) {
168 let (index, epoch, _) = id.unzip();
169 self.insert_impl(index as usize, Element::Error(epoch, label.to_string()))
170 }
171
172 pub(crate) fn force_replace(&mut self, id: I, value: T) {
173 let (index, epoch, _) = id.unzip();
174 self.map[index as usize] = Element::Occupied(value, epoch);
175 }
176
177 pub(crate) fn remove(&mut self, id: I) -> Option<T> {
178 let (index, epoch, _) = id.unzip();
179 match std::mem::replace(&mut self.map[index as usize], Element::Vacant) {
180 Element::Occupied(value, storage_epoch) => {
181 assert_eq!(epoch, storage_epoch);
182 Some(value)
183 }
184 Element::Error(..) => None,
185 Element::Vacant => panic!("Cannot remove a vacant resource"),
186 }
187 }
188
189 pub(crate) fn _try_remove(&mut self, id: I) -> Option<T> {
191 let (index, epoch, _) = id.unzip();
192 if index as usize >= self.map.len() {
193 None
194 } else if let Element::Occupied(value, storage_epoch) =
195 std::mem::replace(&mut self.map[index as usize], Element::Vacant)
196 {
197 assert_eq!(epoch, storage_epoch);
198 Some(value)
199 } else {
200 None
201 }
202 }
203
204 pub(crate) fn iter(&self, backend: Backend) -> impl Iterator<Item = (I, &T)> {
205 self.map
206 .iter()
207 .enumerate()
208 .filter_map(move |(index, x)| match *x {
209 Element::Occupied(ref value, storage_epoch) => {
210 Some((I::zip(index as Index, storage_epoch, backend), value))
211 }
212 _ => None,
213 })
214 }
215
216 pub(crate) fn len(&self) -> usize {
217 self.map.len()
218 }
219
220 pub(crate) fn generate_report(&self) -> StorageReport {
221 let mut report = StorageReport {
222 element_size: mem::size_of::<T>(),
223 ..Default::default()
224 };
225 for element in self.map.iter() {
226 match *element {
227 Element::Occupied(..) => report.num_occupied += 1,
228 Element::Vacant => report.num_vacant += 1,
229 Element::Error(..) => report.num_error += 1,
230 }
231 }
232 report
233 }
234}