Skip to main content

spru_util/storage/
standalone.rs

1use 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/// A standalone item storage.
14#[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}