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}