wgpu_core/
storage.rs
1use alloc::{sync::Arc, vec::Vec};
2use core::mem;
3
4use crate::id::{Id, Marker};
5use crate::resource::ResourceType;
6use crate::{Epoch, Index};
7
8#[derive(Debug)]
10pub(crate) enum Element<T>
11where
12 T: StorageItem,
13{
14 Vacant,
16
17 Occupied(T, Epoch),
20}
21
22pub(crate) trait StorageItem: ResourceType {
23 type Marker: Marker;
24}
25
26impl<T: ResourceType> ResourceType for Arc<T> {
27 const TYPE: &'static str = T::TYPE;
28}
29
30impl<T: StorageItem> StorageItem for Arc<T> {
31 type Marker = T::Marker;
32}
33
34#[macro_export]
35macro_rules! impl_storage_item {
36 ($ty:ident) => {
37 impl $crate::storage::StorageItem for $ty {
38 type Marker = $crate::id::markers::$ty;
39 }
40 };
41}
42
43#[derive(Debug)]
52pub(crate) struct Storage<T>
53where
54 T: StorageItem,
55{
56 pub(crate) map: Vec<Element<T>>,
57 kind: &'static str,
58}
59
60impl<T> Storage<T>
61where
62 T: StorageItem,
63{
64 pub(crate) fn new() -> Self {
65 Self {
66 map: Vec::new(),
67 kind: T::TYPE,
68 }
69 }
70}
71
72impl<T> Storage<T>
73where
74 T: StorageItem,
75{
76 pub(crate) fn insert(&mut self, id: Id<T::Marker>, value: T) {
77 let (index, epoch) = id.unzip();
78 let index = index as usize;
79 if index >= self.map.len() {
80 self.map.resize_with(index + 1, || Element::Vacant);
81 }
82 match mem::replace(&mut self.map[index], Element::Occupied(value, epoch)) {
83 Element::Vacant => {}
84 Element::Occupied(_, storage_epoch) => {
85 assert_ne!(
86 epoch,
87 storage_epoch,
88 "Index {index:?} of {} is already occupied",
89 T::TYPE
90 );
91 }
92 }
93 }
94
95 pub(crate) fn remove(&mut self, id: Id<T::Marker>) -> T {
96 let (index, epoch) = id.unzip();
97 let stored = self
98 .map
99 .get_mut(index as usize)
100 .unwrap_or_else(|| panic!("{}[{:?}] does not exist", self.kind, id));
101 match mem::replace(stored, Element::Vacant) {
102 Element::Occupied(value, storage_epoch) => {
103 assert_eq!(epoch, storage_epoch, "id epoch mismatch");
104 value
105 }
106 Element::Vacant => panic!("Cannot remove a vacant resource"),
107 }
108 }
109
110 pub(crate) fn iter(&self) -> impl Iterator<Item = (Id<T::Marker>, &T)> {
111 self.map
112 .iter()
113 .enumerate()
114 .filter_map(move |(index, x)| match *x {
115 Element::Occupied(ref value, storage_epoch) => {
116 Some((Id::zip(index as Index, storage_epoch), value))
117 }
118 _ => None,
119 })
120 }
121}
122
123impl<T> Storage<T>
124where
125 T: StorageItem + Clone,
126{
127 pub(crate) fn get(&self, id: Id<T::Marker>) -> T {
130 let (index, epoch) = id.unzip();
131 let (result, storage_epoch) = match self.map.get(index as usize) {
132 Some(&Element::Occupied(ref v, epoch)) => (v.clone(), epoch),
133 None | Some(&Element::Vacant) => panic!("{}[{:?}] does not exist", self.kind, id),
134 };
135 assert_eq!(
136 epoch, storage_epoch,
137 "{}[{:?}] is no longer alive",
138 self.kind, id
139 );
140 result
141 }
142}