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// }