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