cuprate_database/database.rs
1//! Abstracted database table operations; `trait DatabaseRo` & `trait DatabaseRw`.
2
3//---------------------------------------------------------------------------------------------------- Import
4use crate::{
5 error::{DbResult, RuntimeError},
6 table::Table,
7};
8
9//---------------------------------------------------------------------------------------------------- DatabaseIter
10/// Generic post-fix documentation for `DatabaseIter` methods.
11macro_rules! doc_iter {
12 () => {
13 r"Although the returned iterator itself is tied to the lifetime
14of `&self`, the returned values from the iterator are _owned_.
15
16# Errors
17The construction of the iterator itself may error.
18
19Each iteration of the iterator has the potential to error as well."
20 };
21}
22
23/// Database (key-value store) read-only iteration abstraction.
24///
25/// These are read-only iteration-related operations that
26/// can only be called from [`DatabaseRo`] objects.
27///
28/// # Hack
29/// This is a HACK to get around the fact [`DatabaseRw`] tables
30/// cannot safely return values returning lifetimes, as such,
31/// only read-only tables implement this trait.
32///
33/// - <https://github.com/Cuprate/cuprate/pull/102#discussion_r1548695610>
34/// - <https://github.com/Cuprate/cuprate/pull/104>
35pub trait DatabaseIter<T: Table> {
36 /*
37 FIXME: <https://github.com/Cuprate/cuprate/issues/348>
38
39 /// Get an [`Iterator`] of value's corresponding to a range of keys.
40 ///
41 /// For example:
42 /// ```rust,ignore
43 /// // This will return all 100 values corresponding
44 /// // to the keys `{0, 1, 2, ..., 100}`.
45 /// self.get_range(0..100);
46 /// ```
47 ///
48 /// Although the returned iterator itself is tied to the lifetime
49 /// of `&'a self`, the returned values from the iterator are _owned_.
50 ///
51 #[doc = doc_iter!()]
52 fn get_range<'a, Range>(
53 &'a self,
54 range: Range,
55 ) -> DbResult<impl Iterator<Item = DbResult<T::Value>> + 'a>
56 where
57 Range: RangeBounds<T::Key> + 'a;
58
59 */
60
61 /// Get an [`Iterator`] that returns the `(key, value)` types for this database.
62 #[doc = doc_iter!()]
63 #[expect(clippy::iter_not_returning_iterator)]
64 fn iter(&self) -> DbResult<impl Iterator<Item = DbResult<(T::Key, T::Value)>> + '_>;
65
66 /// Get an [`Iterator`] that returns _only_ the `key` type for this database.
67 #[doc = doc_iter!()]
68 fn keys(&self) -> DbResult<impl Iterator<Item = DbResult<T::Key>> + '_>;
69
70 /// Get an [`Iterator`] that returns _only_ the `value` type for this database.
71 #[doc = doc_iter!()]
72 fn values(&self) -> DbResult<impl Iterator<Item = DbResult<T::Value>> + '_>;
73}
74
75//---------------------------------------------------------------------------------------------------- DatabaseRo
76/// Generic post-fix documentation for `DatabaseR{o,w}` methods.
77macro_rules! doc_database {
78 () => {
79 r"# Errors
80This will return [`crate::RuntimeError::KeyNotFound`] if:
81- Input does not exist OR
82- Database is empty"
83 };
84}
85
86/// Database (key-value store) read abstraction.
87///
88/// This is a read-only database table,
89/// write operations are defined in [`DatabaseRw`].
90///
91/// # Safety
92/// The table type that implements this MUST be `Send`.
93///
94/// However if the table holds a reference to a transaction:
95/// - only the transaction only has to be `Send`
96/// - the table cannot implement `Send`
97///
98/// For example:
99///
100/// `heed`'s transactions are `Send` but `HeedTableRo` contains a `&`
101/// to the transaction, as such, if `Send` were implemented on `HeedTableRo`
102/// then 1 transaction could be used to open multiple tables, then sent to
103/// other threads - this would be a soundness hole against `HeedTableRo`.
104///
105/// `&T` is only `Send` if `T: Sync`.
106///
107/// `heed::RoTxn: !Sync`, therefore our table
108/// holding `&heed::RoTxn` must NOT be `Send`.
109///
110/// - <https://doc.rust-lang.org/std/marker/trait.Sync.html>
111/// - <https://doc.rust-lang.org/nomicon/send-and-sync.html>
112pub unsafe trait DatabaseRo<T: Table> {
113 /// Get the value corresponding to a key.
114 #[doc = doc_database!()]
115 fn get(&self, key: &T::Key) -> DbResult<T::Value>;
116
117 /// Returns `true` if the database contains a value for the specified key.
118 ///
119 /// # Errors
120 /// Note that this will _never_ return `Err(RuntimeError::KeyNotFound)`,
121 /// as in that case, `Ok(false)` will be returned.
122 ///
123 /// Other errors may still occur.
124 fn contains(&self, key: &T::Key) -> DbResult<bool> {
125 match self.get(key) {
126 Ok(_) => Ok(true),
127 Err(RuntimeError::KeyNotFound) => Ok(false),
128 Err(e) => Err(e),
129 }
130 }
131
132 /// Returns the number of `(key, value)` pairs in the database.
133 ///
134 /// # Errors
135 /// This will never return [`RuntimeError::KeyNotFound`].
136 fn len(&self) -> DbResult<u64>;
137
138 /// Returns the first `(key, value)` pair in the database.
139 #[doc = doc_database!()]
140 fn first(&self) -> DbResult<(T::Key, T::Value)>;
141
142 /// Returns the last `(key, value)` pair in the database.
143 #[doc = doc_database!()]
144 fn last(&self) -> DbResult<(T::Key, T::Value)>;
145
146 /// Returns `true` if the database contains no `(key, value)` pairs.
147 ///
148 /// # Errors
149 /// This can only return [`RuntimeError::Io`] on errors.
150 fn is_empty(&self) -> DbResult<bool>;
151}
152
153//---------------------------------------------------------------------------------------------------- DatabaseRw
154/// Database (key-value store) read/write abstraction.
155///
156/// All [`DatabaseRo`] functions are also callable by [`DatabaseRw`].
157pub trait DatabaseRw<T: Table>: DatabaseRo<T> {
158 /// Insert a key-value pair into the database.
159 ///
160 /// This will overwrite any existing key-value pairs.
161 ///
162 #[doc = doc_database!()]
163 ///
164 /// This will never [`RuntimeError::KeyExists`].
165 fn put(&mut self, key: &T::Key, value: &T::Value) -> DbResult<()>;
166
167 /// Delete a key-value pair in the database.
168 ///
169 /// This will return `Ok(())` if the key does not exist.
170 ///
171 #[doc = doc_database!()]
172 ///
173 /// This will never [`RuntimeError::KeyExists`].
174 fn delete(&mut self, key: &T::Key) -> DbResult<()>;
175
176 /// Delete and return a key-value pair in the database.
177 ///
178 /// This is the same as [`DatabaseRw::delete`], however,
179 /// it will serialize the `T::Value` and return it.
180 ///
181 #[doc = doc_database!()]
182 fn take(&mut self, key: &T::Key) -> DbResult<T::Value>;
183
184 /// Fetch the value, and apply a function to it - or delete the entry.
185 ///
186 /// This will call [`DatabaseRo::get`] and call your provided function `f` on it.
187 ///
188 /// The [`Option`] `f` returns will dictate whether `update()`:
189 /// - Updates the current value OR
190 /// - Deletes the `(key, value)` pair
191 ///
192 /// - If `f` returns `Some(value)`, that will be [`DatabaseRw::put`] as the new value
193 /// - If `f` returns `None`, the entry will be [`DatabaseRw::delete`]d
194 ///
195 #[doc = doc_database!()]
196 fn update<F>(&mut self, key: &T::Key, mut f: F) -> DbResult<()>
197 where
198 F: FnMut(T::Value) -> Option<T::Value>,
199 {
200 let value = DatabaseRo::get(self, key)?;
201
202 match f(value) {
203 Some(value) => DatabaseRw::put(self, key, &value),
204 None => DatabaseRw::delete(self, key),
205 }
206 }
207
208 /// Removes and returns the first `(key, value)` pair in the database.
209 ///
210 #[doc = doc_database!()]
211 fn pop_first(&mut self) -> DbResult<(T::Key, T::Value)>;
212
213 /// Removes and returns the last `(key, value)` pair in the database.
214 ///
215 #[doc = doc_database!()]
216 fn pop_last(&mut self) -> DbResult<(T::Key, T::Value)>;
217}