composable_indexes_core/
collection.rs

1use std::collections::HashMap;
2
3use crate::index::{Index, QueryEnv};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6pub struct Key {
7    pub id: u64,
8}
9
10/// A collection of items, with an index that is automatically kept up-to-date.
11pub struct Collection<In, Ix> {
12    index: Ix,
13    data: HashMap<Key, In>,
14    next_key_id: u64,
15}
16
17impl<In, Ix> Collection<In, Ix>
18where
19    Ix: Index<In>,
20{
21    /// Create an empty collection.
22    pub fn new(ix: Ix) -> Self {
23        Collection {
24            data: HashMap::new(),
25            next_key_id: 0,
26            index: ix,
27        }
28    }
29
30    /// Lookup an item in the collection by its key.
31    pub fn get(&self, key: Key) -> Option<&In> {
32        self.data.get(&key)
33    }
34
35    /// Insert a new item into the collection.
36    pub fn insert(&mut self, value: In) -> Key {
37        let key = self.mk_key();
38        let existing = self.data.insert(key, value);
39
40        // There shouldn't be an existing key, as we just generated it
41        debug_assert!(existing.is_none());
42
43        self.index.insert(&Insert {
44            key,
45            new: &self.data[&key],
46        });
47
48        key
49    }
50
51    /// Iterate over all items in the collection.
52    pub fn iter(&self) -> impl Iterator<Item = (&Key, &In)> {
53        self.data.iter()
54    }
55
56    /// Mutate (or alter the presence of) the item in the collection.
57    pub fn update_mut<F>(&mut self, key: Key, f: F)
58    where
59        F: FnOnce(&mut Option<In>),
60    {
61        let mut existing = self.delete(&key);
62        f(&mut existing);
63
64        if let Some(existing) = existing {
65            self.data.insert(key, existing);
66            self.index.insert(&Insert {
67                key,
68                new: &self.data[&key],
69            });
70        }
71    }
72
73    /// Update the item in the collection.
74    pub fn update<F>(&mut self, key: Key, f: F)
75    where
76        F: FnOnce(Option<&In>) -> In,
77    {
78        let existing = self.data.get(&key);
79        let new = f(existing);
80
81        match existing {
82            Some(existing) => {
83                self.index.update(&Update {
84                    key,
85                    new: &new,
86                    existing,
87                });
88                self.data.insert(key, new);
89            }
90            None => {
91                self.index.insert(&Insert { key, new: &new });
92                self.data.insert(key, new);
93            }
94        };
95    }
96
97    /// Mutate the item in the collection, if it exists.
98    pub fn adjust_mut<F>(&mut self, key: Key, f: F)
99    where
100        F: FnOnce(&mut In),
101    {
102        if let Some(mut existing) = self.delete(&key) {
103            f(&mut existing);
104            self.data.insert(key, existing);
105            self.index.insert(&Insert {
106                key,
107                new: &self.data[&key],
108            });
109        }
110    }
111
112    /// Adjust the item in the collection, if it exists.
113    pub fn adjust<F>(&mut self, key: Key, f: F)
114    where
115        F: FnOnce(&In) -> In,
116    {
117        if let Some(existing) = self.data.get(&key) {
118            let new = f(existing);
119            self.index.update(&Update {
120                key,
121                new: &new,
122                existing,
123            });
124            self.data.insert(key, new);
125        }
126    }
127
128    /// Remove an item from the collection, returning it if it exists.
129    pub fn delete(&mut self, key: &Key) -> Option<In> {
130        let existing = self.data.remove_entry(key);
131        if let Some((key, ref existing)) = existing {
132            self.index.remove(&Remove { key, existing });
133        }
134        existing.map(|(_, v)| v)
135    }
136
137    /// Query the collection using its index(es).
138    pub fn query(&self) -> Ix::Query<'_, In> {
139        let env = QueryEnv { data: &self.data };
140        self.index.query(env)
141    }
142
143    /// Number of items in the collection.
144    pub fn len(&self) -> usize {
145        self.data.len()
146    }
147
148    pub fn is_empty(&self) -> bool {
149        self.data.is_empty()
150    }
151
152    fn mk_key(&mut self) -> Key {
153        let k = Key {
154            id: self.next_key_id,
155        };
156        self.next_key_id += 1;
157        k
158    }
159}
160
161#[derive(Clone)]
162pub struct Insert<'t, In> {
163    pub key: Key,
164    pub new: &'t In,
165}
166
167#[derive(Clone)]
168pub struct Update<'t, In> {
169    pub key: Key,
170    pub new: &'t In,
171    pub existing: &'t In,
172}
173
174#[derive(Clone)]
175pub struct Remove<'t, In> {
176    pub key: Key,
177    pub existing: &'t In,
178}
179
180#[cfg(test)]
181mod tests {
182    use super::*;
183
184    struct TrivialIndex;
185    impl<In> Index<In> for TrivialIndex {
186        type Query<'t, Out>
187            = ()
188        where
189            Out: 't,
190            Self: 't;
191
192        fn insert(&mut self, _op: &Insert<In>) {}
193        fn remove(&mut self, _op: &Remove<In>) {}
194
195        fn query<'t, Out: 't>(&'t self, _env: QueryEnv<'t, Out>) -> Self::Query<'t, Out> {}
196    }
197
198    #[test]
199    fn test_len() {
200        let mut collection = Collection::new(TrivialIndex);
201        assert_eq!(collection.len(), 0);
202
203        collection.insert(1);
204        assert_eq!(collection.len(), 1);
205
206        collection.insert(2);
207        assert_eq!(collection.len(), 2);
208
209        let key = collection.insert(3);
210        assert_eq!(collection.len(), 3);
211
212        collection.delete(&key);
213        assert_eq!(collection.len(), 2);
214    }
215
216    // See composable-indexes/src/lib.rs for more tests
217}