borderless_kv_store/
lib.rs

1use thiserror::Error;
2
3pub mod backend;
4
5/// Prelude module to automatically include all necessary traits
6pub mod prelude {
7    pub use super::{
8        Db, KvDatabase, KvHandle, RawRead, RawWrite, RoCursor, RoTx, RwCursor, RwTx, ToCursorOp,
9    };
10}
11
12#[derive(Debug, Error)]
13pub enum Error {
14    #[error("The key already exists.")]
15    KeyExist,
16    #[error("The data is corrupted.")]
17    Corrupted,
18    #[error("The database '{0}' was not found.")]
19    DbNotFound(String),
20    #[error("The argument is invalid.")]
21    InvalidArgument,
22    #[error("An I/O error occurred.")]
23    IOError,
24    #[error("The operation timed out.")]
25    TimedOut,
26    #[error("The resource is busy - {0}")]
27    Busy(String),
28    #[error("An unknown error occurred.")]
29    Unknown,
30    #[error("Other error: {0}")]
31    Other(String),
32}
33
34#[derive(Debug, Clone)]
35pub enum CursorOp {
36    First,
37    Last,
38    Next,
39    Prev,
40    Current,
41}
42
43pub trait ToCursorOp<DB: KvDatabase> {
44    fn to_op(&self) -> u32;
45}
46
47/// Marker trait representing a key-value database.
48///
49/// This trait does not define any methods and serves as a placeholder
50/// for types that represent a database in this abstraction.
51/// Implementing this trait indicates that a type can function as a database
52/// within the key-value store system.
53pub trait KvDatabase {}
54
55/// Trait representing a generic transaction.
56///
57/// Transactions provide a context for executing a series of database operations atomically.
58/// This trait offers methods to commit or abort a transaction, ensuring that all operations
59/// within the transaction are either fully applied or completely discarded.
60pub trait Tx: Sized {
61    /// Commits the transaction.
62    ///
63    /// Applies all changes made during the transaction to the database.
64    /// If the commit is successful, returns `Ok(())`.
65    /// If the commit fails (e.g., due to a conflict or I/O error), returns an error of type `E`.
66    fn commit(self) -> Result<(), Error>;
67
68    /// Aborts the transaction.
69    ///
70    /// Discards all changes made during the transaction.
71    /// After calling `abort`, the transaction is considered terminated,
72    /// and further operations on it may not be valid.
73    fn abort(self);
74}
75
76/// Trait for reading raw data from the database within a transaction.
77///
78/// Provides a method to read the raw byte value associated with a given key.
79/// The use of lifetimes and generics ensures data safety and flexibility across different database implementations.
80pub trait RawRead<'env, DB>
81where
82    DB: KvDatabase,
83{
84    /// Reads the raw bytes associated with the given key from the database.
85    ///
86    /// - `db`: Reference to the database handle where the key is stored.
87    /// - `key`: Reference to the key to be read.
88    ///
89    /// Returns a slice of bytes if the key exists, or an error if the key does not exist
90    /// or if the operation fails.
91    fn read(&self, db: &impl KvHandle<DB>, key: &impl AsRef<[u8]>) -> Result<Option<&[u8]>, Error>;
92}
93
94/// Trait for writing raw data to the database within a transaction.
95///
96/// Provides methods to write and delete key-value pairs.
97/// This trait extends the capabilities of a transaction to modify data within the database.
98pub trait RawWrite<'env, DB>
99where
100    DB: KvDatabase,
101{
102    /// Writes raw bytes to the database associated with the given key.
103    ///
104    /// - `db`: Reference to the database handle where the data will be written.
105    /// - `key`: Reference to the key under which the data will be stored.
106    /// - `data`: Slice of bytes representing the data to be stored.
107    ///
108    /// If the key already exists, its value is overwritten.
109    /// Returns `Ok(())` if the operation is successful, or an error of type `E` if it fails.
110    fn write(
111        &mut self,
112        db: &impl KvHandle<DB>,
113        key: &impl AsRef<[u8]>,
114        data: &impl AsRef<[u8]>,
115    ) -> Result<(), Error>;
116
117    /// Deletes the key-value pair associated with the given key from the database.
118    ///
119    /// - `db`: Reference to the database handle from which the key will be deleted.
120    /// - `key`: Reference to the key to be deleted.
121    ///
122    /// Returns `Ok(())` if the deletion is successful, or an error of type `E` if it fails.
123    fn delete(&mut self, db: &impl KvHandle<DB>, key: &impl AsRef<[u8]>) -> Result<(), Error>;
124}
125
126/// Trait representing a read-write cursor over the database within a transaction.
127///
128/// A cursor allows sequential access over key-value pairs in the database,
129/// which can be efficient for iterating over large datasets or performing range queries.
130/// This trait provides an iterator that yields mutable references to the data.
131pub trait RwCursor<'txn, DB: KvDatabase> {
132    /// Iterator type over key-value pairs, yielding references to keys and values.
133    ///
134    /// The iterator borrows data for the lifetime `'txn`, ensuring that data
135    /// remains valid for the duration of the transaction.
136    type Iter: Iterator<Item = (&'txn [u8], &'txn [u8])>;
137
138    // Retrieves a key/data pair from the cursor. Depending on the cursor op,
139    // the current key may be returned.
140    fn get<K, V>(
141        &self,
142        key: Option<&K>,
143        value: Option<&V>,
144        op: impl ToCursorOp<DB>,
145    ) -> Result<(Option<&'txn [u8]>, &'txn [u8]), Error>
146    where
147        K: AsRef<[u8]>,
148        V: AsRef<[u8]>;
149
150    // Puts a key/data pair into the database. The cursor will be positioned
151    // at the new data item, or on failure usually near it.
152    fn put<K, V>(&mut self, key: &K, value: &V) -> Result<(), Error>
153    where
154        K: AsRef<[u8]>,
155        V: AsRef<[u8]>;
156
157    /// Deletes the current key/data pair.
158    fn del(&mut self) -> Result<(), Error>;
159
160    /// Returns an iterator over key-value pairs starting from the current cursor position.
161    ///
162    /// May return an error if the cursor is invalid or if an I/O error occurs.
163    fn iter(&mut self) -> Self::Iter;
164
165    /// Iterate over database items starting from the beginning of the database.
166    fn iter_start(&mut self) -> Self::Iter;
167
168    /// Iterate over database items starting from the given key.
169    fn iter_from<K>(&mut self, key: &K) -> Self::Iter
170    where
171        K: AsRef<[u8]>;
172}
173
174/// Trait representing a read-only cursor over the database within a transaction.
175///
176/// Similar to `RwCursor`, but does not allow modification of the data.
177/// Useful for read-only transactions where data integrity must be preserved.
178/// Provides an iterator that yields references to the data without permitting changes.
179pub trait RoCursor<'txn, DB: KvDatabase> {
180    /// Iterator type over key-value pairs, yielding references to keys and values.
181    ///
182    /// The iterator borrows data for the lifetime `'txn`.
183    type Iter: Iterator<Item = (&'txn [u8], &'txn [u8])>;
184
185    fn get<K, V>(
186        &self,
187        key: Option<&K>,
188        value: Option<&V>,
189        op: impl ToCursorOp<DB>,
190    ) -> Result<(Option<&'txn [u8]>, &'txn [u8]), Error>
191    where
192        K: AsRef<[u8]>,
193        V: AsRef<[u8]>;
194
195    /// Iterate over database items. The iterator will begin with item next after the cursor,
196    /// and continue until the end of the database. For new cursors,
197    /// the iterator will begin with the first item in the database.
198    fn iter(&mut self) -> Self::Iter;
199
200    // Iterate over database items starting from the beginning of the database.
201    fn iter_start(&mut self) -> Self::Iter;
202
203    // Iterate over database items starting from the given key.
204    fn iter_from<K>(&mut self, key: &K) -> Self::Iter
205    where
206        K: AsRef<[u8]>;
207}
208
209/// Trait representing a read-only transaction.
210///
211/// Extends the `Tx` and `RawRead` traits and provides cursor functionality.
212/// Read-only transactions ensure that data cannot be modified during the transaction,
213/// which can optimize performance and allow for higher concurrency.
214pub trait RoTx<'env, DB>: Tx + RawRead<'env, DB>
215where
216    DB: KvDatabase,
217{
218    /// Cursor type for iterating over key-value pairs within the transaction.
219    ///
220    /// The cursor is bound by the lifetime `'txn`, which cannot outlive the transaction.
221    type Cursor<'txn>: RoCursor<'txn, DB>
222    where
223        Self: 'txn;
224
225    /// Creates a read-only cursor for the given database handle.
226    ///
227    /// - `db`: Reference to the database handle for which the cursor is created.
228    ///
229    /// Returns a cursor that allows iteration over the data in a read-only fashion.
230    /// May return an error if the cursor cannot be created.
231    fn ro_cursor<'txn>(&'txn self, db: &impl KvHandle<DB>) -> Result<Self::Cursor<'txn>, Error>;
232}
233
234// TODO: The function names clash with those of RawRead !!
235/// Trait representing a read-write transaction.
236///
237/// Extends `Tx`, `RawWrite`, `RawRead`, and `CRUD` traits and provides cursor functionality.
238/// Read-write transactions allow for both reading and modifying data within the database.
239/// This trait also supports nested transactions and mutable cursors.
240pub trait RwTx<'env, DB>: Tx + RawWrite<'env, DB> + RawRead<'env, DB>
241where
242    DB: KvDatabase,
243{
244    /// Cursor type for iterating over key-value pairs within the transaction.
245    ///
246    /// The cursor allows for modifying data as it iterates.
247    type Cursor<'txn>: RwCursor<'txn, DB>
248    where
249        Self: 'txn;
250
251    /// Nested transaction type.
252    ///
253    /// Allows for creating nested transactions within the current transaction,
254    /// which can be committed or aborted independently of the parent transaction.
255    type RwTx<'txn>: RwTx<'txn, DB>
256    where
257        Self: 'txn;
258
259    /// Creates a read-write cursor for the given database handle.
260    ///
261    /// - `db`: Reference to the database handle for which the cursor is created.
262    ///
263    /// Returns a cursor that allows for iterating and modifying data within the database.
264    /// May return an error if the cursor cannot be created.
265    fn rw_cursor<'txn>(&'txn mut self, db: &impl KvHandle<DB>)
266        -> Result<Self::Cursor<'txn>, Error>;
267
268    /// Begins a nested read-write transaction.
269    ///
270    /// Nested transactions can be useful for batching operations or handling
271    /// transactions within transactions, providing finer control over commits and rollbacks.
272    ///
273    /// Returns a new read-write transaction that is nested within the current one.
274    /// May return an error if the nested transaction cannot be created.
275    fn nested_txn(&mut self) -> Result<Self::RwTx<'_>, Error>;
276}
277
278/// Trait representing the key-value database.
279///
280/// Provides methods to open databases and begin transactions.
281/// The environment encapsulates the overall state of the database system,
282/// managing resources and providing access to databases and transactions.
283pub trait Db: Clone + std::marker::Send + std::marker::Sync {
284    type DB: KvDatabase;
285
286    /// Handle type for a database.
287    ///
288    /// The handle provides access to a specific database within the environment.
289    type Handle: KvHandle<Self::DB>;
290
291    /// Read-only transaction type.
292    ///
293    /// Allows for creating read-only transactions within the environment.
294    type RoTx<'env>: RoTx<'env, Self::DB>
295    where
296        Self: 'env;
297
298    /// Read-write transaction type.
299    ///
300    /// Allows for creating read-write transactions within the environment.
301    type RwTx<'env>: RwTx<'env, Self::DB>
302    where
303        Self: 'env;
304
305    /// Opens a database with the given name.
306    ///
307    /// - `name`: Name of the database to open.
308    ///
309    /// Returns a handle to the database if it exists, or an error if it does not
310    /// or if the operation fails.
311    fn open_sub_db(&self, name: &str) -> Result<Self::Handle, Error>;
312
313    /// Creates a database with the given name.
314    /// If the database is already created, this function will open the database.
315    ///
316    /// - `name`: Name of the database to open.
317    ///
318    /// Returns a handle to the database if it exists, or an error if it does not
319    /// or if the operation fails.
320    fn create_sub_db(&self, name: &str) -> Result<Self::Handle, Error>;
321
322    /// Begins a new read-only transaction.
323    ///
324    /// Read-only transactions are optimized for situations where data integrity is critical,
325    /// and no modifications are required.
326    ///
327    /// Returns a new read-only transaction, or an error if the transaction cannot be started.
328    fn begin_ro_txn(&self) -> Result<Self::RoTx<'_>, Error>;
329
330    /// Begins a new read-write transaction.
331    ///
332    /// Read-write transactions allow for both reading and modifying data.
333    ///
334    /// Returns a new read-write transaction, or an error if the transaction cannot be started.
335    fn begin_rw_txn(&self) -> Result<Self::RwTx<'_>, Error>;
336}
337
338/// Trait representing a handle to a database.
339///
340/// Provides access to the database name and the underlying database object.
341/// The handle is used in transaction operations to specify which database to interact with.
342/// This abstraction allows the same transaction methods to operate on different databases.
343pub trait KvHandle<DB>: std::marker::Send + std::marker::Sync
344where
345    DB: KvDatabase,
346{
347    /// Returns a reference to the underlying database object.
348    ///
349    /// This can be used to access database-specific functionality if needed.
350    /// The lifetime `'env` ensures that the database reference does not outlive the environment.
351    fn db(&self) -> &DB;
352}
353
354// /// Trait providing CRUD (Create, Read, Update, Delete) operations.
355// ///
356// /// Extends functionality for read-write transactions.
357// /// These methods provide a higher-level abstraction over `RawRead` and `RawWrite`,
358// /// working with `Option` types and `Vec<u8>` for more ergonomic usage.
359// pub trait CRUD<'env, DB>: RwTx<'env, DB>
360// where
361//     DB: KvDatabase,
362// {
363//     /// Reads the value associated with the given key.
364//     ///
365//     /// - `db`: Reference to the database handle.
366//     /// - `key`: Reference to the key to be read.
367//     ///
368//     /// Returns:
369//     /// - `Ok(Some(Vec<u8>))` if the key exists, containing the value.
370//     /// - `Ok(None)` if the key does not exist.
371//     /// - `Err(E)` if an error occurs during the operation.
372//     fn read(
373//         &self,
374//         db: &impl KvHandle<DB>,
375//         key: &impl AsRef<[u8]>,
376//     ) -> Result<Option<Vec<u8>>, Error> {
377//         let val = <Self as RawRead<DB>>::read(self, db, key)?.map(|v| v.to_vec());
378
379//         Ok(val)
380//     }
381
382//     /// Creates a new key-value pair in the database.
383//     /// This method overwrite an existing key!
384//     ///
385//     /// - `db`: Reference to the database handle.
386//     /// - `key`: Reference to the key under which the data will be stored.
387//     /// - `data`: Slice of bytes representing the data to be stored.
388//     ///
389//     /// Returns:
390//     /// - `Ok(())` if the key-value pair was successfully created.
391//     /// - `Err(E)` if the key already exists or if an error occurs.
392//     fn create(
393//         &mut self,
394//         db: &impl KvHandle<DB>,
395//         key: &impl AsRef<[u8]>,
396//         data: &impl AsRef<[u8]>,
397//     ) -> Result<(), Error> {
398//         <Self as RawWrite<DB>>::write(self, db, key, data)?;
399//         Ok(())
400//     }
401
402//     /// Updates the value associated with the given key.
403//     ///
404//     /// - `db`: Reference to the database handle.
405//     /// - `key`: Reference to the key to be updated.
406//     /// - `data`: Slice of bytes representing the new data to be stored.
407//     ///
408//     /// Returns:
409//     /// - `Ok(Some(Vec<u8>))` containing the old value if the key existed and was updated.
410//     /// - `Ok(None)` if the key did not exist.
411//     /// - `Err(E)` if an error occurs during the operation.
412//     fn update(
413//         &mut self,
414//         db: &impl KvHandle<DB>,
415//         key: &impl AsRef<[u8]>,
416//         data: &impl AsRef<[u8]>,
417//     ) -> Result<Option<Vec<u8>>, Error> {
418//         let old = <Self as CRUD<DB>>::read(self, db, key)?;
419//         <Self as RawWrite<DB>>::write(self, db, key, data)?;
420//         Ok(old)
421//     }
422
423//     /// Deletes the key-value pair associated with the given key.
424//     ///
425//     /// - `db`: Reference to the database handle.
426//     /// - `key`: Reference to the key to be deleted.
427//     ///
428//     /// Returns:
429//     /// - `Ok(Some(Vec<u8>))` containing the old value if the key existed and was deleted.
430//     /// - `Ok(None)` if the key did not exist.
431//     /// - `Err(E)` if an error occurs during the operation.
432//     fn delete(
433//         &mut self,
434//         db: &impl KvHandle<DB>,
435//         key: &impl AsRef<[u8]>,
436//     ) -> Result<Option<Vec<u8>>, Error> {
437//         let old = <Self as CRUD<DB>>::read(self, db, key)?;
438//         <Self as RawWrite<DB>>::delete(self, db, key)?;
439//         Ok(old)
440//     }
441// }
442
443// /// Implement the CRUD Interface for all Types T
444// /// implementing the RwTx super trait.
445// impl<'env, DB, T> CRUD<'env, DB> for T
446// where
447//     DB: KvDatabase,
448//     T: RwTx<'env, DB>,
449// {
450// }