composable_indexes/core/
collection.rs

1use crate::core::store::Store;
2
3use super::{
4    QueryResult, QueryResultDistinct,
5    index::{Index, Insert, Remove, Update},
6};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
9pub struct Key {
10    pub id: u64,
11}
12
13#[cfg(not(feature = "std"))]
14pub type DefaultStore<In> = alloc::collections::BTreeMap<Key, In>;
15
16#[cfg(feature = "std")]
17pub type DefaultStore<In> = std::collections::HashMap<Key, In>;
18
19/// A collection of items, with an index that is automatically kept up-to-date.
20pub struct Collection<In, Ix, S = DefaultStore<In>> {
21    index: Ix,
22    data: S,
23    next_key_id: u64,
24    _marker: core::marker::PhantomData<fn() -> In>,
25}
26
27impl<In, Ix> Collection<In, Ix> {
28    /// Create an empty collection.
29    pub fn new(ix: Ix) -> Self
30    where
31        In: 'static,
32        Ix: Index<In>,
33        DefaultStore<In>: Store<In>,
34    {
35        Collection::new_with_empty_store(ix)
36    }
37}
38
39impl<In, Ix, S: Default> Collection<In, Ix, S> {
40    /// Create an empty collection.
41    pub fn new_with_empty_store(ix: Ix) -> Self {
42        Collection::new_with_store(S::default(), ix)
43    }
44}
45
46impl<In, Ix, S> Collection<In, Ix, S> {
47    /// Create an empty collection with a custom store.
48    pub fn new_with_store(store: S, ix: Ix) -> Self {
49        Collection {
50            data: store,
51            next_key_id: 0,
52            index: ix,
53            _marker: core::marker::PhantomData,
54        }
55    }
56}
57
58impl<In, Ix, S> Collection<In, Ix, S>
59where
60    In: 'static,
61    Ix: Index<In>,
62    S: Store<In>,
63{
64    /// Lookup an item in the collection by its key.
65    pub fn get_by_key(&self, key: Key) -> Option<&In> {
66        self.data.get(key)
67    }
68
69    /// Insert a new item into the collection.
70    pub fn insert(&mut self, value: In) -> Key {
71        let key = self.mk_key();
72        let existing = self.data.insert(key, value);
73
74        // There shouldn't be an existing key, as we just generated it
75        debug_assert!(existing.is_none());
76
77        self.index.insert(&Insert {
78            key,
79            new: self.data.get_unwrapped(key),
80        });
81
82        key
83    }
84
85    /// Iterate over all items in the collection.
86    pub fn iter(&self) -> impl IntoIterator<Item = (Key, &In)> {
87        self.data.iter()
88    }
89
90    /// Mutate (or alter the presence of) the item in the collection.
91    pub fn update_by_key_mut<F>(&mut self, key: Key, f: F)
92    where
93        F: FnOnce(&mut Option<In>),
94    {
95        let mut existing = self.delete_by_key(key);
96        f(&mut existing);
97
98        if let Some(existing) = existing {
99            self.data.insert(key, existing);
100            self.index.insert(&Insert {
101                key,
102                new: self.data.get_unwrapped(key),
103            });
104        }
105    }
106
107    /// Update the item in the collection.
108    pub fn update_by_key<F>(&mut self, key: Key, f: F)
109    where
110        F: FnOnce(Option<&In>) -> In,
111    {
112        let existing = self.data.get(key);
113        let new = f(existing);
114
115        match existing {
116            Some(existing) => {
117                self.index.update(&Update {
118                    key,
119                    new: &new,
120                    existing,
121                });
122                self.data.insert(key, new);
123            }
124            None => {
125                self.index.insert(&Insert { key, new: &new });
126                self.data.insert(key, new);
127            }
128        };
129    }
130
131    /// Mutate the item in the collection, if it exists.
132    pub fn adjust_by_key_mut<F>(&mut self, key: Key, f: F)
133    where
134        F: FnOnce(&mut In),
135    {
136        if let Some(mut existing) = self.delete_by_key(key) {
137            f(&mut existing);
138            self.data.insert(key, existing);
139            self.index.insert(&Insert {
140                key,
141                new: self.data.get_unwrapped(key),
142            });
143        }
144    }
145
146    /// Adjust the item in the collection, if it exists.
147    pub fn adjust_by_key<F>(&mut self, key: Key, f: F)
148    where
149        F: FnOnce(&In) -> In,
150    {
151        if let Some(existing) = self.data.get(key) {
152            let new = f(existing);
153            self.index.update(&Update {
154                key,
155                new: &new,
156                existing,
157            });
158            self.data.insert(key, new);
159        }
160    }
161
162    /// Remove an item from the collection, returning it if it exists.
163    pub fn delete_by_key(&mut self, key: Key) -> Option<In> {
164        let existing = self.data.remove(key);
165
166        if let Some(ref existing) = existing {
167            self.index.remove(&Remove { key, existing });
168        }
169
170        existing
171    }
172
173    /// Query the collection using its index(es).
174    pub fn query<Res>(&self, f: impl FnOnce(&Ix) -> Res) -> Res::Resolved<&In>
175    where
176        Res: QueryResult,
177    {
178        let res = f(&self.index);
179        res.map(|k| self.data.get_unwrapped(k))
180    }
181
182    pub fn delete<Res>(&mut self, f: impl FnOnce(&Ix) -> Res) -> usize
183    where
184        Res: QueryResult,
185    {
186        let mut affected_count = 0;
187        let res = f(&self.index);
188        res.map(|key| {
189            self.delete_by_key(key);
190            affected_count += 1;
191        });
192        affected_count
193    }
194
195    pub fn update<Res, F>(
196        &mut self,
197        f: impl FnOnce(&Ix) -> Res,
198        update_fn: impl Fn(&In) -> In,
199    ) -> Res::Resolved<()>
200    where
201        Res: QueryResultDistinct,
202    {
203        let res = f(&self.index);
204        res.map(|key| {
205            self.data.update(key, |existing| {
206                let new = update_fn(existing);
207                self.index.update(&Update {
208                    key,
209                    new: &new,
210                    existing,
211                });
212                new
213            });
214        })
215    }
216
217    pub fn take<Res>(&mut self, f: impl FnOnce(&Ix) -> Res) -> Res::Resolved<In>
218    where
219        Res: QueryResultDistinct,
220    {
221        let res = f(&self.index);
222        res.map(|k| self.delete_by_key(k).unwrap())
223    }
224
225    /// Number of items in the collection.
226    pub fn len(&self) -> usize {
227        self.data.len()
228    }
229
230    pub fn is_empty(&self) -> bool {
231        self.data.is_empty()
232    }
233
234    fn mk_key(&mut self) -> Key {
235        let k = Key {
236            id: self.next_key_id,
237        };
238        self.next_key_id += 1;
239        k
240    }
241}
242
243#[cfg(test)]
244mod tests {
245    use super::*;
246
247    struct TrivialIndex;
248    impl<In> Index<In> for TrivialIndex {
249        fn insert(&mut self, _op: &Insert<In>) {}
250        fn remove(&mut self, _op: &Remove<In>) {}
251    }
252
253    #[test]
254    fn test_len() {
255        let mut collection = Collection::new(TrivialIndex);
256        assert_eq!(collection.len(), 0);
257
258        collection.insert(1);
259        assert_eq!(collection.len(), 1);
260
261        collection.insert(2);
262        assert_eq!(collection.len(), 2);
263
264        let key = collection.insert(3);
265        assert_eq!(collection.len(), 3);
266
267        collection.delete_by_key(key);
268        assert_eq!(collection.len(), 2);
269    }
270
271    // See composable-indexes/src/lib.rs for more tests
272}