spru_util/storage/
standalone.rs1use std::{
2 any,
3 collections::{HashMap, hash_map},
4 marker::PhantomData,
5};
6
7use derive_where::derive_where;
8use spru::{
9 Item,
10 item::{self, IdT},
11};
12
13#[derive_where(Debug, Default; )]
15pub struct Standalone<State> {
16 map: HashMap<any::TypeId, Box<dyn any::Any>>,
17 _state: PhantomData<fn() -> State>,
18}
19
20impl<State> Standalone<State> {
21 pub fn new() -> Self {
22 Self::default()
23 }
24}
25
26impl<State: spru::State> spru::item::Storage for Standalone<State> {
27 type State = State;
28
29 fn get<T>(&self, id: IdT<T>) -> spru::item::storage::Result<&Item<T>>
30 where
31 T: item::storage::Storable<Self::State>,
32 {
33 let type_id = any::TypeId::of::<T>();
34 let item = if let Some(inner_map) = self.map.get(&type_id) {
35 let inner_map = inner_map
36 .downcast_ref::<HashMap<item::IdT<T>, Item<T>>>()
37 .expect("Internal type mismatch");
38
39 inner_map.get(&id)
40 } else {
41 None
42 };
43 item.ok_or(Error::IdNotFound(id.untyped()))
44 .map_err(Into::into)
45 }
46
47 #[allow(refining_impl_trait)]
48 fn get_mut<T>(&mut self, id: IdT<T>) -> spru::item::storage::Result<&mut spru::Item<T>>
49 where
50 T: item::storage::Storable<Self::State>,
51 {
52 let type_id = any::TypeId::of::<T>();
53 let item = if let Some(inner_map) = self.map.get_mut(&type_id) {
54 let inner_map = inner_map
55 .downcast_mut::<InnerMap<T>>()
56 .expect("Interal type mismatch");
57
58 inner_map.get_mut(&id)
59 } else {
60 None
61 };
62 item.ok_or(Error::IdNotFound(id.untyped()))
63 .map_err(Into::into)
64 }
65
66 fn create<T>(&mut self, value: spru::Item<T>) -> spru::item::storage::Result<()>
67 where
68 T: item::storage::Storable<Self::State>,
69 {
70 let id = value.id();
71 let type_id = any::TypeId::of::<T>();
72 let inner_map = self
73 .map
74 .entry(type_id)
75 .or_insert(Box::new(InnerMap::<T>::new()));
76
77 let inner_map = inner_map
78 .downcast_mut::<InnerMap<T>>()
79 .expect("Interal type mismatch");
80 if let hash_map::Entry::Vacant(v) = inner_map.entry(id) {
81 v.insert(value);
82 Ok(())
83 } else {
84 Err(Error::IdAlreadyExists(id.untyped()).into())
85 }
86 }
87
88 fn destroy<T>(&mut self, id: IdT<T>) -> spru::item::storage::Result<spru::Item<T>>
89 where
90 T: item::storage::Storable<Self::State>,
91 {
92 let type_id = any::TypeId::of::<T>();
93 let item = if let Some(inner_map) = self.map.get_mut(&type_id) {
94 let inner_map = inner_map
95 .downcast_mut::<InnerMap<T>>()
96 .expect("Interal type mismatch");
97
98 inner_map.remove(&id)
99 } else {
100 None
101 };
102
103 item.ok_or(Error::IdNotFound(id.untyped()).into())
104 }
105}
106
107type InnerMap<T> = HashMap<item::IdT<T>, Item<T>>;
108
109#[derive(Debug, thiserror::Error)]
110pub enum Error {
111 #[error("Id '{0}' was not found")]
112 IdNotFound(item::Id),
113 #[error("Id '{0}' already exists")]
114 IdAlreadyExists(item::Id),
115}
116
117#[cfg(test)]
118mod test {
119 use super::*;
120
121 #[tagset::tagset(impl spru::State)]
122 #[tagset(String)]
123 struct State;
124
125 #[test]
126 fn standalone() {
127 use spru::item::storage::Storage as _;
128 let mut storage = Standalone::<State>::new();
129
130 let id0 = spru::item::IdT::test_new(0);
131 let id1 = spru::item::IdT::test_new(1);
132 let id2 = spru::item::IdT::test_new(2);
133
134 storage
135 .create(spru::Item::test_new(id0.clone(), "zero".to_string()))
136 .unwrap();
137
138 storage
139 .create(spru::Item::test_new(id1.clone(), "one".to_string()))
140 .unwrap();
141
142 storage
143 .create(spru::Item::test_new(id2.clone(), "two".to_string()))
144 .unwrap();
145
146 let s0 = storage.get_mut(id0).unwrap().test_get_mut();
147
148 *s0 = "ZERO".to_string();
149
150 let s0 = storage.get(id0).unwrap().get();
151 assert_eq!(s0, &"ZERO");
152
153 let s1 = storage.get(id1).unwrap().get();
154 assert_eq!(s1, &"one");
155
156 storage.destroy(id2).unwrap();
157 }
158}