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