mmtkvdb/
lib.rs

1//! Key-value database using LMDB
2//!
3//! # Caveats / Safety
4//!
5//! Because of how memory-mapped I/O is being used and also because of certain
6//! assumptions of the underlying LMDB API, opening environments and databases
7//! requires `unsafe` Rust when using this library.
8//!
9//! Do not open the same environment twice in the same process at the same time
10//! (see documentation of [`EnvBuilder`]). The file format is platform
11//! specific, so endianness and word size must not change across use.
12//!
13//! When opening an already existing database, all options must be compatible
14//! with the previously used options (see documentation of [`DbBuilder`]).
15//!
16//! Stale readers might need to be cleared manually, see
17//! [`Env::clear_stale_readers`].
18//!
19//! # Example
20//!
21//! ```
22//! # fn doit() -> std::io::Result<()> {
23//! // question mark operator may return with `std::io::Error`
24//! use mmtkvdb::{self as kv, traits::*};
25//! use tempfile::tempdir;
26//! let location = tempdir()?;
27//! let db1_opts = kv::DbBuilder::new().name("db1");
28//! let db2_opts = kv::DbBuilder::new().key_type::<str>().value_type::<i32>().name("db2");
29//! let env_builder = kv::EnvBuilder::new().dir(location.path()).max_dbs(2);
30//! {
31//!     // SAFETY:
32//!     // * database isn't opened twice in this process at the same time
33//!     // * it is assumed no other processes access the environment
34//!     // * since environment is newly created, it matches the platform
35//!     let mut env = unsafe { env_builder.open_rw()? };
36//!     // SAFETY: database doesn't exist yet (or would need compatible options)
37//!     let db1 = unsafe { env.create_db(&db1_opts)? };
38//!     // SAFETY: database doesn't exist yet (or would need compatible options)
39//!     let db2 = unsafe { env.create_db(&db2_opts)? };
40//!     let mut txn = env.txn_rw()?;
41//!     txn.put(&db1, "key1".as_bytes(), "value1".as_bytes())?;
42//!     txn.put(&db2, "Prime", &17)?;
43//!     txn.commit()?;
44//! }
45//! {
46//!     // SAFETY:
47//!     // * database isn't opened twice in this process at the same time
48//!     // * it is assumed no other processes access the environment
49//!     // * the environment has been created above, thus it matches the platform
50//!     let env = unsafe { env_builder.open_ro()? };
51//!     // SAFETY: database options are compatible with the ones used when
52//!     // creating the database
53//!     let db1 = unsafe { env.open_db(&db1_opts)? };
54//!     // SAFETY: database options are compatible with the ones used when
55//!     // creating the database
56//!     let db2 = unsafe { env.open_db(&db2_opts)? };
57//!     let txn = env.txn_ro()?;
58//!     assert_eq!(txn.get(&db1, "key1".as_bytes())?, Some("value1".as_bytes()));
59//!     assert_eq!(txn.get_owned(&db2, "Prime")?, Some(17));
60//! }
61//! location.close()?;
62//! # Ok(())
63//! # }
64//! # doit().expect("error during database access")
65//! ```
66
67#![deny(unsafe_op_in_unsafe_fn)]
68#![warn(missing_docs)]
69#![allow(unused_macro_rules)]
70
71pub mod cow;
72mod helpers;
73pub mod lmdb;
74pub mod storable;
75mod syncutils;
76
77#[cfg(test)]
78mod tests;
79
80pub use cow::{GenericCow, Owned};
81use helpers::*;
82pub use storable::{BorrowStorable, NoKey, NoValue, Storable, StorableConstBytesLen, StorableRef};
83use syncutils::*;
84
85use std::cell::UnsafeCell;
86use std::collections::{HashMap, HashSet};
87use std::ffi::{c_int, c_uint, CStr, CString};
88use std::fmt;
89use std::hash::{Hash, Hasher};
90use std::io;
91use std::marker::PhantomData;
92use std::mem::{forget, take, MaybeUninit};
93use std::ops::{Deref, DerefMut};
94use std::path::Path;
95use std::ptr::{null, null_mut};
96use std::slice;
97use std::str;
98use std::sync::atomic::{AtomicBool, AtomicU64, Ordering::Relaxed};
99use std::sync::{Arc, Mutex, Weak};
100
101// TODO: Ensure that `usize` is really `c_size_t` without depending on unstable
102// features.
103#[allow(non_camel_case_types)]
104type c_size_t = usize;
105/*
106// Compile-time check enforcing `usize` is same size as `c_size_t`
107const _: fn() = || {
108    let _ = core::mem::transmute::<usize, std::ffi::c_size_t>;
109};
110*/
111
112/// Important traits re-exported without name
113pub mod traits {
114    pub use super::Env as _;
115    pub use super::EnvRef as _;
116    pub use super::Txn as _;
117}
118
119/// Converts an error code from LMDB into a `Result`
120///
121/// # Safety
122///
123/// * If `code` is negative, it must be a valid LMDB error code.
124/// * `lmdb::mdb_strerror` is assumed to be thread-safe for valid negative LMDB
125///   error codes. This is currently not guaranteed by LMDB's API
126///   documentation. See also: `https://bugs.openldap.org/show_bug.cgi?id=8361`
127unsafe fn check_err_code(code: c_int) -> io::Result<()> {
128    if code > 0 {
129        Err(io::Error::from_raw_os_error(code))
130    } else if code < 0 {
131        Err(io::Error::new(
132            io::ErrorKind::Other,
133            // SAFETY: because `code` is negative and an existent LMDB error
134            // code, `lmdb::mdb_strerror` returns a pointer to a static
135            // C string (not guaranteed by the API docs, but believed to not
136            // change in future versions of LMDB)
137            unsafe { CStr::from_ptr(lmdb::mdb_strerror(code)) }
138                .to_str()
139                .unwrap_or("unknown error (LMDB error string is not valid UTF-8)"),
140        ))
141    } else {
142        Ok(())
143    }
144}
145
146/// Type alias for [`c_uint`] as used by LMDB to specify flags
147type LmdbFlags = c_uint;
148
149/// Macro checking if an `lmdb_flags` field has a certain flag set
150macro_rules! flag_get {
151    ($self:ident, $flag:ident) => {
152        ($self.lmdb_flags & (lmdb::$flag as LmdbFlags) != 0)
153    };
154}
155
156/// Macro setting or clearing a flag in the `lmdb_flags` field
157macro_rules! flag_set {
158    ($self:ident, $flag:ident, $value:expr) => {
159        if $value {
160            $self.lmdb_flags |= lmdb::$flag as LmdbFlags;
161        } else {
162            $self.lmdb_flags &= !(lmdb::$flag as LmdbFlags);
163        }
164    };
165}
166
167static ENV_COUNTER: AtomicU64 = AtomicU64::new(0);
168
169/// Internal struct with LMDB environment handle as raw pointer
170///
171/// On drop, the environment is closed. Contains an additional mutex to
172/// synchronize opening/creating/closing databases.
173#[derive(Debug)]
174struct EnvBackend {
175    inner: *mut lmdb::MDB_env,
176    id: u64,
177    max_keysize: usize,
178    nestable_txns: bool,
179    /// `Mutex` ensures synchronization of `lmdb::mdb_dbi_open` and contained
180    /// `HashMap` avoids re-creating a new `DbBackend` for a database that is
181    /// already open (because databases must not be closed more than once)
182    dbis: Mutex<HashMap<lmdb::MDB_dbi, Weak<DbBackend>>>,
183}
184
185// SAFETY: `lmdb::MDB_env` is generally thread-safe, but particular function
186// must be synchronized
187unsafe impl Send for EnvBackend {}
188// SAFETY: `lmdb::MDB_env` is generally thread-safe, but particular function
189// must be synchronized
190unsafe impl Sync for EnvBackend {}
191
192impl PartialEq for EnvBackend {
193    fn eq(&self, other: &Self) -> bool {
194        self.inner == other.inner
195    }
196}
197
198impl Eq for EnvBackend {}
199
200impl Hash for EnvBackend {
201    fn hash<H: Hasher>(&self, state: &mut H) {
202        self.inner.hash(state);
203    }
204}
205
206impl Drop for EnvBackend {
207    fn drop(&mut self) {
208        // LMDB's API specification is contradictory and claims both that
209        // databases must be closed before calling `mdb_env_close` and that
210        // "closing a database handle is not necessary". We close them anyway,
211        // just to be sure:
212        for dbi in take(&mut *self.dbis.lock().unwrap()).into_keys() {
213            // SAFETY:
214            //  *  due to `&mut self`, it is not possible to call this function
215            //     (for a given environment) from different threads at the same
216            //     time
217            //  *  the database can't have been closed already, because the
218            //     `lmdb::MDB_dbi` is always removed from `EnvBackend::dbis` in
219            //     that case
220            //  *  all transactions have been closed at this point because
221            //     `TxnRo<'a>` and `TxnRw<'a>` have a lifetime `'a` which has
222            //     ended by now
223            //  *  all cursors have been closed at this point because closing
224            //     all transactions also closes all cursors
225            unsafe {
226                lmdb::mdb_dbi_close(self.inner, dbi);
227            }
228        }
229        // SAFETY:
230        //  *  due to `&mut self`, it is not possible to call this function
231        //     (for a given environment) from different threads at the same
232        //     time
233        //  *  all transactions, cursors, and databases have been closed (see
234        //     above)
235        unsafe { lmdb::mdb_env_close(self.inner) }
236    }
237}
238
239/// Read-only handle for accessing environment that stores key-value databases
240///
241/// An environment can be opened using [`EnvBuilder`].
242///
243/// The methods for read-only access are accessible through the [`Env`] trait
244/// (which is implemented by `EnvRo` and [`EnvRw`]).
245///
246/// Use [`Env::open_db`] to retrieve database handles and [`Env::txn_ro`] to
247/// start a read-only transaction.
248///
249/// It's possible to clone the handle, in which case the environment will be
250/// closed when the last handle is dropped. It's also possible to create a
251/// read-only handle from a read-write handle ([`EnvRw`]) by invoking
252/// [`Env::clone_ro`].
253#[derive(Clone, PartialEq, Eq, Hash, Debug)]
254pub struct EnvRo {
255    backend: Arc<EnvBackend>,
256}
257
258/// Read-write handle for accessing environment that stores key-value databases
259///
260/// An environment can be opened using [`EnvBuilder`].
261///
262/// The methods for read-only access are accessible through the [`Env`] trait
263/// (which is implemented by [`EnvRo`] and `EnvRw`).
264/// Methods for write access, however, are available directly on the `EnvRw`
265/// struct.
266///
267/// Use [`Env::open_db`] or [`EnvRw::create_db`] to retrieve database handles
268/// and [`EnvRw::txn_rw`] to start a read-write transaction.
269///
270/// It's also possible to create a read-only handle from a read-write handle by
271/// invoking [`Env::clone_ro`].
272#[derive(PartialEq, Eq, Hash, Debug)]
273pub struct EnvRw {
274    env_ro: EnvRo,
275}
276
277impl AsRef<EnvRo> for EnvRo {
278    fn as_ref(&self) -> &EnvRo {
279        &self
280    }
281}
282
283impl AsRef<EnvRo> for EnvRw {
284    fn as_ref(&self) -> &EnvRo {
285        &self.env_ro
286    }
287}
288
289/// Abstraction over [`&EnvRo`](EnvRo) and [`&mut EnvRw`](EnvRw), which allows
290/// creating databases in the latter case if non-existing
291///
292/// This trait is only needed if you want to create generic code which works on
293/// either `&EnvRo` or `&mut EnvRw` and creates databases in the latter case if
294/// non-existing.
295/// In most cases, `EnvRo` or `EnvRw` can be used directly. (Note that you can
296/// call `EnvRo`'s methods on `EnvRw` automatically due to [`Deref`] coercion.)
297pub trait EnvRef {
298    /// Open database in environment and, if possible, create if non-existing
299    ///
300    /// Note that the implementation of `EnvRef` for [`&EnvRo`]() does *not*
301    /// create any database if non-existing.
302    ///
303    /// # Safety
304    ///
305    /// * If a database exists already, it must have been created with
306    ///   compatible options.
307    /// * Implementation of [`Storable`] for the used
308    ///   [keys](DbBuilder::key_type) and [values](DbBuilder::value_type) must
309    ///   behave the same as when the database was created.
310    unsafe fn open_or_create_db<K, V, C>(
311        &mut self,
312        options: &DbSpec<K, V, C>,
313    ) -> io::Result<Db<K, V, C>>
314    where
315        K: Storable + ?Sized,
316        V: Storable + ?Sized,
317        C: Constraint;
318}
319
320impl<T: Env> EnvRef for &T {
321    unsafe fn open_or_create_db<K, V, C>(
322        &mut self,
323        options: &DbSpec<K, V, C>,
324    ) -> io::Result<Db<K, V, C>>
325    where
326        K: Storable + ?Sized,
327        V: Storable + ?Sized,
328        C: Constraint,
329    {
330        // SAFETY: all requirements of `EnvRo::open_db` are listed in
331        // documentation of `EnvRef:open_or_create_db` as well
332        unsafe { self.open_db(options) }
333    }
334}
335
336impl EnvRef for &mut EnvRw {
337    unsafe fn open_or_create_db<K, V, C>(
338        &mut self,
339        options: &DbSpec<K, V, C>,
340    ) -> io::Result<Db<K, V, C>>
341    where
342        K: Storable + ?Sized,
343        V: Storable + ?Sized,
344        C: Constraint,
345    {
346        // SAFETY: all requirements of `EnvRw::create_db` are listed in
347        // documentation of `EnvRef:open_or_create_db` as well
348        unsafe { self.create_db(options) }
349    }
350}
351
352/// Internal struct with LMDB transaction handle as raw pointer
353///
354/// On drop, all associated cursors (which haven't been dropped and thus closed
355/// yet) will be closed.
356#[derive(Debug)]
357struct TxnBackend<'a> {
358    env_ro: &'a EnvRo,
359    inner: *mut lmdb::MDB_txn,
360    cursors: WeakVec<CursorBackend>,
361}
362
363impl<'a> TxnBackend<'a> {
364    fn close_cursors(&mut self) {
365        for cursor in take(&mut self.cursors).iter() {
366            cursor.closed.store(true, Relaxed);
367            // SAFETY:
368            //  *  Holding a shared reference to `cursor` means that its drop
369            //     handler did not run yet. Thus the cursor has not been closed
370            //     by the drop handler. Storing `true` in `closed` ensures that
371            //     when the drop handler later obtains a mutable reference, it
372            //     will read `true` and doesn't close the cursor twice.
373            //  *  The cursor also won't be closed by this method twice,
374            //     because `self.cursors` is emptied above.
375            //  *  There is no other place where the cursor could have been
376            //     closed.
377            //  *  All callers of `TxnBackend::close_cursors` will drop or
378            //     forget the `TxnBackend` afterwards. Thus the cursor can't be
379            //     used after calling `lmdb::mdb_cursor_close` below, because
380            //     using the cursor requires a `TxnRo` or `TxnRw` handle. In
381            //     this context, `CursorBackend::assert_txn_backend` ensures
382            //     that a cursor handle really belongs to the transaction for
383            //     which it has been created. Even a `Relaxed` store of `true`
384            //     to `cursor.closed` will happen-before subsequent `Relaxed`
385            //     loads in `CursorBackend::assert_txn_backend` if the address
386            //     `TxnBackend.inner` has been reused. That is because
387            //     releasing the allocated memory in LMDB synchronizes-with an
388            //     allocation from within the same memory region.
389            unsafe {
390                lmdb::mdb_cursor_close(cursor.inner);
391            }
392        }
393    }
394    /// Drop without aborting the transaction (closes all cursors)
395    fn dont_abort(mut self) {
396        self.close_cursors();
397        // NOTE: doesn't leak because `self.cursors` isn't holding any
398        // allocation
399        forget(self);
400    }
401}
402
403impl<'a> Drop for TxnBackend<'a> {
404    fn drop(&mut self) {
405        self.close_cursors();
406        // SAFETY: transaction cannot be used further and all cursors have been
407        // closed
408        unsafe {
409            lmdb::mdb_txn_abort(self.inner);
410        }
411    }
412}
413
414/// Read-only transaction
415///
416/// A read-only transaction can be started with [`Env::txn_ro`].
417///
418/// The methods for read-only access to the database are accessible through the
419/// [`Txn`] trait (which is implemented by `TxnRo` and [`TxnRw`]).
420///
421/// Read-only transactions do not need to be committed or aborted; their
422/// handles can be simply dropped when not needed anymore.
423///
424/// Opposed to read-write transactions ([`TxnRw`]), read-only transactions
425/// (`TxnRo`) are [`Send`]. However, they are not [`Sync`]. Thus, if you want
426/// to use a read-only transaction from several threads concurrently, you have
427/// to synchronize the use, e.g. by wrapping the `TxnRo` in a [`Mutex`].
428#[derive(Debug)]
429pub struct TxnRo<'a> {
430    backend: UnsafeCell<TxnBackend<'a>>,
431}
432
433// SAFETY: Option `lmdb::MDB_NOTLS` is used, thus `TxnRo` can be used from
434// different threads. However, the `UnsafeCell` demands `!Sync`.
435unsafe impl<'a> Send for TxnRo<'a> {}
436
437/// Helper type to store `HashSet<ArcByAddr<DbBackend>>` as owned value or
438/// mutable reference
439#[derive(Debug)]
440enum UsedDbs<'a> {
441    Toplevel(HashSet<ArcByAddr<DbBackend>>),
442    Nested(&'a mut HashSet<ArcByAddr<DbBackend>>),
443}
444
445impl<'a> Deref for UsedDbs<'a> {
446    type Target = HashSet<ArcByAddr<DbBackend>>;
447    fn deref(&self) -> &Self::Target {
448        match self {
449            UsedDbs::Toplevel(x) => x,
450            UsedDbs::Nested(x) => x,
451        }
452    }
453}
454
455impl<'a> DerefMut for UsedDbs<'a> {
456    fn deref_mut(&mut self) -> &mut Self::Target {
457        match self {
458            UsedDbs::Toplevel(x) => x,
459            UsedDbs::Nested(x) => x,
460        }
461    }
462}
463
464/// Read-write transaction
465///
466/// A read-write transaction can be started with [`EnvRw::txn_rw`].
467///
468/// The methods for read-only access to the database are accessible through the
469/// [`Txn`] trait (which is implemented by [`TxnRo`] and `TxnRw`).
470/// Methods for write access, however, are available directly on the `TxnRw`
471/// struct.
472///
473/// Read-write transactions are [aborted](TxnRw::abort) when dropped. To make
474/// changes permanent, [`TxnRw::commit`] must be called.
475///
476/// Read-write transactions are neither [`Send`] nor [`Sync`].
477pub struct TxnRw<'a> {
478    backend: UnsafeCell<TxnBackend<'a>>,
479    used_dbs: UsedDbs<'a>,
480    commit_handlers: Vec<Box<dyn FnOnce(&mut Self) -> io::Result<()> + 'a>>,
481}
482
483impl<'a> fmt::Debug for TxnRw<'a> {
484    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
485        f.debug_struct("Point")
486            .field("backend", &self.backend)
487            .field("used_dbs", &self.used_dbs)
488            .finish_non_exhaustive()
489    }
490}
491
492/// Internal struct with LMDB database handle
493///
494/// `DbBackend` can be wrapped in an [`ArcByAddr`] to allow for equality checks
495/// and hashing.
496///
497/// There is no strong reference to [`EnvBackend`] to avoid a lifetime argument
498/// (particularly such that databases can persist beyond mutation of
499/// [`EnvRw`]).
500///
501/// It is an error if a database handle is used on a different environment.
502/// Method [`DbBackend::assert_env_backend`] can be used to panic in that case.
503///
504/// Note that `DbBackend`s must not be dropped while there is an open
505/// transaction which modified the respective database. Hence clones of
506/// `ArcByAddr<DbBackend>` must be stored in [`TxnRw::used_dbs`] before
507/// modifying any data in the database. This will defer invocation of
508/// [`DbBackend::drop`] and [`lmdb::mdb_dbi_close`].
509#[derive(Debug)]
510struct DbBackend {
511    env_backend: Weak<EnvBackend>,
512    env_id: u64,
513    inner: lmdb::MDB_dbi,
514}
515
516impl DbBackend {
517    /// Drop without running normal destructor
518    fn dont_close(mut self) {
519        self.env_backend = Default::default();
520        // NOTE: doesn't leak because `self.env_backend` doesn't hold any
521        // allocation
522        forget(self);
523    }
524    /// Panic if database handle does not belong to environment
525    fn assert_env_backend(&self, env_backend: &EnvBackend) {
526        if self.env_id != env_backend.id {
527            panic!("database does not belong to environment");
528        }
529    }
530}
531
532impl Drop for DbBackend {
533    fn drop(&mut self) {
534        if let Some(env_backend) = Weak::upgrade(&self.env_backend) {
535            let mut dbis = env_backend.dbis.lock().unwrap();
536            // If `env_backend.dbis` does not contain the `lmdb::MDB_dbi`, then
537            // `lmdb::mdb_dbi_close` has already been called.
538            if let Some(weak) = dbis.get(&self.inner) {
539                // If `weak.strong_count` is not zero, then the database has
540                // been reopened after the last `Arc<DbBackend> was dropped.
541                if weak.strong_count() == 0 {
542                    // Removing the `lmdb::MDB_dbi` from `dbis` ensures that
543                    // the database doesn't get closed twice.
544                    dbis.remove(&self.inner);
545                    // SAFETY:
546                    //  *  due to `env_backend.dbis.lock()`, it is not possible
547                    //     to call this function (for a given environment) from
548                    //     different threads at the same time
549                    //  *  because `weak.strong_count()` is zero, no new
550                    //     `DbBackend` (which is still in use) with the same
551                    //     `DbBackend::inner` may have been created by
552                    //     `EnvRo::open_or_opt_create_db`
553                    //  *  removing the `lmdb::MDB_dbi` from `dbis` ensures that
554                    //     `mdb_dbi_close` isn't called twice, even if a
555                    //     recreated `DbBackend` gets dropped later
556                    //  *  `mdb_cursor_close` isn't called later because all
557                    //     `CursorBackend`s must have been dropped before the last
558                    //     `Db` handle and before thus the `DbBackend` is dropped
559                    //     (see SAFETY comment on `CursorBackend`)
560                    unsafe {
561                        lmdb::mdb_dbi_close(env_backend.inner, self.inner);
562                    }
563                }
564            }
565        }
566    }
567}
568
569/// Database handle
570///
571/// These handles are created using [`DbBuilder`] builder, which can be passed
572/// by (shared) reference to [`Env::open_db`] or [`EnvRw::create_db`].
573///
574/// The type arguments `K`, `V`, and `C` reflect the type used for keys and
575/// values, and whether duplicate keys are allowed (`C` being [`KeysUnique`] or
576/// [`KeysDuplicate`]), respectively.
577///
578/// Operations on databases is done using the methods of the [`Txn`] trait or
579/// [`TxnRw`] struct. The database handle must be passed to these methods by
580/// (shared) reference.
581///
582/// Using a [`Db`] handle in a different environment (or in an environment that
583/// has been closed and re-opened) will cause a panic.
584#[derive(Debug)]
585pub struct Db<K: ?Sized, V: ?Sized, C> {
586    key: PhantomData<fn(&K) -> &K>,
587    value: PhantomData<fn(&V) -> &V>,
588    constraint: C,
589    backend: ArcByAddr<DbBackend>,
590}
591
592impl<K: ?Sized, V: ?Sized, C> Clone for Db<K, V, C>
593where
594    C: Constraint,
595{
596    fn clone(&self) -> Self {
597        Db {
598            key: PhantomData,
599            value: PhantomData,
600            constraint: self.constraint,
601            backend: self.backend.clone(),
602        }
603    }
604}
605
606impl<K: ?Sized, V: ?Sized, C> PartialEq for Db<K, V, C> {
607    fn eq(&self, other: &Self) -> bool {
608        self.backend == other.backend
609    }
610}
611
612impl<K: ?Sized, V: ?Sized, C> Eq for Db<K, V, C> {}
613
614/// Internal struct with LMDB cursor handle
615///
616/// There is no lifetime argument, but cursors will be closed when
617/// [`TxnBackend`] gets dropped. In that case, this struct will be marked as
618/// closed by setting [`CursorBackend::closed`] to true.
619///
620/// `CursorBackend` can be wrapped in an [`ArcByAddr`] to allow for equality
621/// checks and hashing. (Equality can't be checked by comparing the inner raw
622/// pointer because the address behind the raw pointer could be reused after
623/// the cursor has been closed.)
624///
625/// Like database handles, cursor handles have no lifetime argument.
626///
627/// It is an error if a cursor handle is used on a different transaction.
628/// Method [`CursorBackend::assert_txn_backend`] can be used to panic in that
629/// case.
630///
631/// This struct implements `Send` and `Sync`, thus proper synchronization must
632/// be ensured when using it (which is done by making operations work on
633/// transaction handles).
634//
635// SAFETY: Creators must ensure that a corresponding `Db` handle exists which
636// gets dropped after `CursorBackend` gets dropped. See `CursorBackend::drop`.
637#[derive(Debug)]
638struct CursorBackend {
639    inner: *mut lmdb::MDB_cursor,
640    closed: AtomicBool,
641    inner_txn: *mut lmdb::MDB_txn,
642}
643
644// SAFETY: `Cursor`s can only be used with a `TxnRo` or `TxnRw`. Those
645// transaction handles implement `Send` or `!Send` as necessary.
646unsafe impl Send for CursorBackend {}
647// SAFETY: `Cursor`s can only be used with a `TxnRo` or `TxnRw`. Those
648// transaction handles implement `Sync` or `!Sync` as necessary.
649unsafe impl Sync for CursorBackend {}
650
651impl CursorBackend {
652    /// Panic if cursor handle does not belong to transaction
653    fn assert_txn_backend(&self, txn_backend: &TxnBackend) {
654        if self.closed.load(Relaxed) || self.inner_txn != txn_backend.inner {
655            panic!("cursor does not belong to transaction");
656        }
657    }
658}
659
660impl Drop for CursorBackend {
661    fn drop(&mut self) {
662        // NOTE: mutex should never be poisoned
663        if !*self.closed.get_mut() {
664            // SAFETY:
665            //  *  If the cursor was closed before, then
666            //     `TxnBackend::close_cursors` would read as `true` because
667            //     the only other place where the cursor might have been closed
668            //     is `TxnBackend::close_cursors`.
669            //  *  `CursorBackend` is always dropped before the last associated
670            //     `Db` handle and thus before the `DbBackend` is dropped.  See
671            //     SAFETY comment on `CursorBackend`. Therefore,
672            //     `lmdb::mdb_cursor_close` gets called before
673            //     `lmdb::mdb_dbi_close`. Note that the LMDB API specification
674            //     is unclear about whether this is a requirement for read-only
675            //     transactions. For read-write transactions where there has
676            //     been an actual write to the database, this is ensured also
677            //     additionally due to storing the `DbBackend` in
678            //     `TxnRw:used_dbs`.
679            unsafe {
680                lmdb::mdb_cursor_close(self.inner);
681            }
682        }
683    }
684}
685
686#[derive(Debug)]
687/// Cursor for reading from or writing to a particular database
688///
689/// A new cursor can be created using [`Txn::new_cursor`]. It is used by
690/// invoking one of the cursor methods in [`Txn`] or [`TxnRw`].
691pub struct Cursor<K: ?Sized, V: ?Sized, C> {
692    // SAFETY: field order matters, see `CursorBackend::drop`
693    backend: ArcByAddr<CursorBackend>,
694    db: Db<K, V, C>,
695}
696
697impl<K: ?Sized, V: ?Sized, C> Clone for Cursor<K, V, C>
698where
699    C: Constraint,
700{
701    fn clone(&self) -> Self {
702        Cursor {
703            db: self.db.clone(),
704            backend: self.backend.clone(),
705        }
706    }
707}
708
709impl<K: ?Sized, V: ?Sized, C> PartialEq for Cursor<K, V, C> {
710    fn eq(&self, other: &Self) -> bool {
711        self.backend == other.backend
712    }
713}
714
715impl<K: ?Sized, V: ?Sized, C> Eq for Cursor<K, V, C> {}
716
717/// Options for opening an environment
718///
719/// This struct follows the builder pattern. Start with [`EnvBuilder::new`] and
720/// open the environment with [`EnvBuilder::open_ro`] (for read-only access) or
721/// [`EnvBuilder::open_rw`] (for read-write access).
722///
723/// # Caveats / Safety
724///
725/// Do not open the same environment twice in the same process at the same
726/// time.
727///
728/// Since this cannot be easily ensured (and because the environment must be
729/// free of corruption on the storage medium), [`open_ro`](EnvBuilder::open_ro)
730/// and [`open_rw`](EnvBuilder::open_rw) are marked as `unsafe`.
731/// Use [`Env::clone_ro`] to (re-)open an already open environment in read-only
732/// mode.
733///
734/// The file format is platform specific, so endianness and word size must not
735/// change across use.
736///
737/// # Example
738///
739/// ```
740/// # fn doit() -> std::io::Result<()> {
741/// // question mark operator may return with `std::io::Error`
742/// use mmtkvdb::{self as kv, traits::*};
743/// use tempfile::tempdir;
744/// let location = tempdir()?;
745/// let env_builder = kv::EnvBuilder::new().dir(location.path()).max_dbs(1);
746/// // SAFETY:
747/// // * database isn't opened twice in this process at the same time
748/// // * it is assumed no other processes access the environment
749/// // * since environment is newly created, it matches the platform
750/// let mut env_rw = unsafe { env_builder.open_rw() }?;
751/// let env_ro = env_rw.clone_ro();
752/// # Ok(())
753/// # }
754/// # doit().expect("error during database access")
755/// ```
756#[derive(Clone, Debug)]
757pub struct EnvBuilder<P> {
758    path: P,
759    lmdb_flags: LmdbFlags,
760    max_size: usize,
761    max_readers: usize,
762    max_dbs: usize,
763    unix_file_mode: u32,
764}
765
766/// Constraints on database (type argument `C` to [`DbBuilder`] and [`Db`])
767pub trait Constraint: Copy + 'static {
768    /// Duplicate keys allowed?
769    const DUPLICATE_KEYS: bool;
770}
771
772/// Type argument to [`DbBuilder`] and [`Db`] indicating unique keys
773#[derive(Clone, Copy, Debug)]
774pub struct KeysUnique;
775
776impl Constraint for KeysUnique {
777    const DUPLICATE_KEYS: bool = false;
778}
779
780/// Type argument to [`DbBuilder`] and [`Db`] indicating non-unique keys
781#[derive(Clone, Copy, Debug)]
782pub struct KeysDuplicate;
783
784impl Constraint for KeysDuplicate {
785    const DUPLICATE_KEYS: bool = true;
786}
787
788/// Type alias for `DbBuilder` which has a [name](DbBuilder::name) set (or
789/// unnamed database selected)
790///
791/// Values of type `DbSpec<K, V, C>` are created by creating a new
792/// [`DbBuilder`] with [`DbBuilder::new`], setting the desired options, and
793/// then invoking [`DbBuilder::name`] or [`DbBuilder::unnamed`].
794///
795/// Values of type `DbSpec<K, V, C>` can be passed to the following methods in
796/// order to create and/or open databases:
797///
798/// * [`Env::open_db`]
799/// * [`EnvRw::create_db`] (same as `Env::open_db` but creates the database if
800///   not existent)
801/// * [`EnvRef::open_or_create_db`] (never creates the database if called on
802///   `&EnvRo`)
803pub type DbSpec<K, V, C> = DbBuilder<K, V, C, Option<CString>>;
804
805/// Options for opening a database
806///
807/// This struct follows the builder pattern. Start with [`DbBuilder::new`] and
808/// pass completed builder by (shared) reference to [`Env::open_db`] or
809/// [`EnvRw::create_db`] to open or create a database.
810///
811/// # Caveats / Safety
812///
813/// When opening an already existing database, all options must be compatible
814/// with the previously used options. It has be be ensured by the caller that
815/// this is true. Thus [`Env::open_db`] and [`EnvRw::create_db`] are marked as
816/// `unsafe`.
817///
818/// [`DbBuilder::name`] has to be called last (after setting all other
819/// options). This is due to some restrictions regarding `const fn`s.
820/// A compiler error will be reported if the methods are invoked in the wrong
821/// order.
822///
823/// # Type arguments
824///
825/// The type arguments `K`, `V`, and `C` reflect the type used for keys and
826/// values, and whether duplicate keys are allowed (`C` being [`KeysUnique`] or
827/// [`KeysDuplicate`]), respectively.
828///
829/// The fourth type parameter `N` determines if a [name](DbBuilder::name)
830/// <small>(or the [unnamed database](DbBuilder::unnamed))</small>
831/// has been set, or if a name must be selected yet. `N` is `()` if no database
832/// name has been selected yet. Once a name has been selected, you can use the
833/// type alias [`DbSpec<K, V, C>`] to refer to the completed builder.
834///
835/// # Example
836///
837/// ```
838/// # fn doit() -> std::io::Result<()> {
839/// // question mark operator may return with `std::io::Error`
840/// use mmtkvdb::{self as kv, Txn as _};
841/// use tempfile::tempdir;
842/// let location = tempdir()?;
843/// let env_builder = kv::EnvBuilder::new().dir(location.path()).max_dbs(1);
844/// // SAFETY:
845/// // * database isn't opened twice in this process at the same time
846/// // * it is assumed no other processes access the environment
847/// // * since environment is newly created, it matches the platform
848/// let mut env_rw = unsafe { env_builder.open_rw() }?;
849/// let db_opts = kv::DbBuilder::new()
850///     .key_type::<str>()
851///     .value_type::<i32>()
852///     .name("account_balance");
853/// // SAFETY: database doesn't exist yet (or would need compatible options)
854/// let db = unsafe { env_rw.create_db(&db_opts) }?;
855/// # Ok(())
856/// # }
857/// # doit().expect("error during database access")
858/// ```
859#[derive(Clone, Debug)]
860pub struct DbBuilder<K: ?Sized, V: ?Sized, C, N> {
861    key: PhantomData<fn(&K) -> &K>,
862    value: PhantomData<fn(&V) -> &V>,
863    constraint: C,
864    lmdb_flags: LmdbFlags,
865    name: N,
866}
867
868/// Some default values used for [`EnvBuilder`]
869pub mod env_builder_defaults {
870    /// Default value for `max_size`
871    pub const MAX_SIZE: usize = 1024 * 1024 * 1024;
872    /// Default value for `max_readers`
873    pub const MAX_READERS: usize = 126;
874    /// Default value for `max_dbs`
875    pub const MAX_DBS: usize = 0;
876    /// Default value for `unix_file_mode`
877    pub const UNIX_FILE_MODE: u32 = 0o600;
878}
879
880impl EnvBuilder<()> {
881    /// Default options for environment
882    pub const fn new() -> Self {
883        Self {
884            path: (),
885            // SAFETY: `lmdb::MDB_NOTLS` is required for `TxnRo` to be `Send`
886            // and for `EnvRo::open_or_opt_create_db` to be called with its
887            // `create` argument set to `false` while other transactions are
888            // open
889            lmdb_flags: lmdb::MDB_NORDAHEAD as LmdbFlags | lmdb::MDB_NOTLS as LmdbFlags,
890            max_size: env_builder_defaults::MAX_SIZE,
891            max_readers: env_builder_defaults::MAX_READERS,
892            max_dbs: env_builder_defaults::MAX_DBS,
893            unix_file_mode: env_builder_defaults::UNIX_FILE_MODE,
894        }
895    }
896}
897
898impl<P> EnvBuilder<P> {
899    /// Set directory location
900    ///
901    /// Overwrites a previously set directory or file location.
902    pub fn dir<'a>(mut self, path: &'a (impl AsRef<Path> + ?Sized)) -> EnvBuilder<&'a Path> {
903        flag_set!(self, MDB_NOSUBDIR, false);
904        EnvBuilder {
905            path: path.as_ref(),
906            lmdb_flags: self.lmdb_flags,
907            max_size: self.max_size,
908            max_readers: self.max_readers,
909            max_dbs: self.max_dbs,
910            unix_file_mode: self.unix_file_mode,
911        }
912    }
913    /// Set file location
914    ///
915    /// Overwrites a previously set directory or file location.
916    pub fn file<'a>(mut self, path: &'a (impl AsRef<Path> + ?Sized)) -> EnvBuilder<&'a Path> {
917        flag_set!(self, MDB_NOSUBDIR, true);
918        EnvBuilder {
919            path: path.as_ref(),
920            lmdb_flags: self.lmdb_flags,
921            max_size: self.max_size,
922            max_readers: self.max_readers,
923            max_dbs: self.max_dbs,
924            unix_file_mode: self.unix_file_mode,
925        }
926    }
927    /// Get write-map option
928    pub const fn get_writemap(&self) -> bool {
929        flag_get!(self, MDB_WRITEMAP)
930    }
931    /// Set or clear write-map option
932    ///
933    /// Enabling this option is incompatible with nested transactions
934    /// (see [`TxnRw::nested`]).
935    pub const fn writemap(mut self, flag: bool) -> Self {
936        flag_set!(self, MDB_WRITEMAP, flag);
937        self
938    }
939    /// Get no-meta-sync option
940    pub const fn get_nometasync(&self) -> bool {
941        flag_get!(self, MDB_NOMETASYNC)
942    }
943    /// Set or clear no-meta-sync option
944    pub const fn nometasync(mut self, flag: bool) -> Self {
945        flag_set!(self, MDB_NOMETASYNC, flag);
946        self
947    }
948    /// Get no-sync option
949    pub const fn get_nosync(&self) -> bool {
950        flag_get!(self, MDB_NOSYNC)
951    }
952    /// Set or clear no-sync option
953    pub const fn nosync(mut self, flag: bool) -> Self {
954        flag_set!(self, MDB_NOSYNC, flag);
955        self
956    }
957    /// Get map-async option
958    pub const fn get_mapasync(&self) -> bool {
959        flag_get!(self, MDB_MAPASYNC)
960    }
961    /// Set or clear map-async option
962    pub const fn mapasync(mut self, flag: bool) -> Self {
963        flag_set!(self, MDB_MAPASYNC, flag);
964        self
965    }
966    /// Get no-read-ahead option
967    pub const fn get_nordahead(&self) -> bool {
968        flag_get!(self, MDB_NORDAHEAD)
969    }
970    /// Set or clear no-read-ahead option
971    pub const fn nordahead(mut self, flag: bool) -> Self {
972        flag_set!(self, MDB_NORDAHEAD, flag);
973        self
974    }
975    /// Get maximum environment size
976    pub const fn get_max_size(&self) -> usize {
977        self.max_size
978    }
979    /// Set maximum environment size
980    pub const fn max_size(mut self, max_size: usize) -> Self {
981        self.max_size = max_size;
982        self
983    }
984    /// Get maximum number of concurrent readers
985    pub const fn get_max_readers(&self) -> usize {
986        self.max_readers
987    }
988    /// Set maximum number of concurrent readers
989    pub const fn max_readers(mut self, max_readers: usize) -> Self {
990        self.max_readers = max_readers;
991        self
992    }
993    /// Get maximum number of named databases
994    pub const fn get_max_dbs(&self) -> usize {
995        self.max_dbs
996    }
997    /// Set maximum number of named databases
998    pub const fn max_dbs(mut self, max_dbs: usize) -> Self {
999        self.max_dbs = max_dbs;
1000        self
1001    }
1002    /// Get file mode
1003    pub const fn get_unix_file_mode(&self) -> u32 {
1004        self.unix_file_mode
1005    }
1006    /// Set file mode
1007    pub const fn unix_file_mode(mut self, mode: u32) -> Self {
1008        self.unix_file_mode = mode;
1009        self
1010    }
1011    /// Check if transactions are nestable with current options
1012    ///
1013    /// See [`TxnRw::nested`].
1014    pub const fn nestable_txns(&self) -> bool {
1015        !self.get_writemap()
1016    }
1017}
1018
1019impl<'a> EnvBuilder<&'a Path> {
1020    /// Open environment
1021    ///
1022    /// # Safety
1023    ///
1024    /// See [`EnvBuilder::open_ro`] and [`EnvBuilder::open_rw`]
1025    unsafe fn open_with_readonly_flag(&self, readonly: bool) -> io::Result<EnvRo> {
1026        let path = path_to_cstring(self.path)?;
1027        let mut inner = MaybeUninit::<*mut lmdb::MDB_env>::uninit();
1028        // SAFETY:
1029        //  *  `lmdb::mdb_env_create` doesn't have any requirements
1030        //  *  the status passed to `check_err_code` is valid
1031        unsafe {
1032            check_err_code(lmdb::mdb_env_create(inner.as_mut_ptr()))?;
1033        }
1034        // SAFETY: call to `lmdb::mdb_env_create` above has been successful as
1035        // otherwise `check_err_code` would have returned an `Err` resulting in
1036        // early return from this function
1037        let inner = unsafe { inner.assume_init() };
1038        let backend = EnvBackend {
1039            inner: inner,
1040            id: ENV_COUNTER.fetch_add(1, Relaxed),
1041            max_keysize: unsafe { lmdb::mdb_env_get_maxkeysize(inner) }
1042                .try_into()
1043                .unwrap_or(usize::MAX),
1044            nestable_txns: self.nestable_txns(),
1045            dbis: Default::default(),
1046        };
1047        // SAFETY:
1048        //  *  `lmdb::mdb_env_set_mapsize` doesn't have any requirements
1049        //  *  the status passed to `check_err_code` is valid
1050        unsafe {
1051            check_err_code(lmdb::mdb_env_set_mapsize(
1052                backend.inner,
1053                self.max_size.try_into().map_err(|_| {
1054                    io::Error::new(io::ErrorKind::InvalidInput, "maximum size invalid")
1055                })?,
1056            ))?;
1057        }
1058        // SAFETY:
1059        //  *  `lmdb::mdb_env_set_maxreaders` doesn't have any requirements
1060        //     (other than being called before `mdb_env_open` which is the case
1061        //     and would otherwise only result in EINVAL being returned)
1062        //  *  the status passed to `check_err_code` is valid
1063        unsafe {
1064            check_err_code(lmdb::mdb_env_set_maxreaders(
1065                backend.inner,
1066                self.max_readers.try_into().map_err(|_| {
1067                    io::Error::new(io::ErrorKind::InvalidInput, "maximum reader count invalid")
1068                })?,
1069            ))?;
1070        }
1071        // SAFETY:
1072        //  *  `lmdb::mdb_env_set_maxdbs` doesn't have any requirements
1073        //     (other than being called before `mdb_env_open` which is the case
1074        //     and would otherwise only result in EINVAL being returned)
1075        //  *  the status passed to `check_err_code` is valid
1076        unsafe {
1077            check_err_code(lmdb::mdb_env_set_maxdbs(
1078                backend.inner,
1079                self.max_dbs.try_into().map_err(|_| {
1080                    io::Error::new(
1081                        io::ErrorKind::InvalidInput,
1082                        "maximum number of named databases invalid",
1083                    )
1084                })?,
1085            ))?;
1086        }
1087        // SAFETY:
1088        //  *  safety requirements are documented in `EnvBuilder::env_ro` and
1089        //     `EnvBuilder::env_rw`
1090        //  *  the status passed to `check_err_code` is valid
1091        unsafe {
1092            check_err_code(lmdb::mdb_env_open(
1093                backend.inner,
1094                path.as_ptr(),
1095                if readonly {
1096                    self.lmdb_flags | lmdb::MDB_RDONLY as LmdbFlags
1097                } else {
1098                    self.lmdb_flags
1099                },
1100                self.unix_file_mode.try_into().map_err(|_| {
1101                    io::Error::new(
1102                        io::ErrorKind::InvalidInput,
1103                        "file mode bits integer invalid",
1104                    )
1105                })?,
1106            ))?;
1107        }
1108        Ok(EnvRo {
1109            backend: Arc::new(backend),
1110        })
1111    }
1112    /// Open environment in read-only mode
1113    ///
1114    /// # Safety
1115    ///
1116    /// * Do not open the same environment twice in the same process at the
1117    ///   same time.
1118    /// * The environment must be free of corruption on the storage medium and
1119    ///   no other processes may corrupt the environment on the storage medium.
1120    /// * The file format is platform specific, so endianness and word size
1121    ///   must not change across use.
1122    pub unsafe fn open_ro(&self) -> io::Result<EnvRo> {
1123        // SAFETY: requirements of `EnvBuilder::open_with_readonly_flag` are
1124        // the same as documented by `EnvBuilder::open_ro`
1125        Ok(unsafe { self.open_with_readonly_flag(true) }?)
1126    }
1127    /// Open environment in read-write mode
1128    ///
1129    /// # Safety
1130    ///
1131    /// * Do not open the same environment twice in the same process at the
1132    ///   same time.
1133    /// * The environment must be free of corruption on the storage medium and
1134    ///   no other processes may corrupt the environment on the storage medium.
1135    /// * The file format is platform specific, so endianness and word size
1136    ///   must not change across use.
1137    pub unsafe fn open_rw(&self) -> io::Result<EnvRw> {
1138        // SAFETY: requirements of `EnvBuilder::open_with_readonly_flag` are
1139        // the same as documented by `EnvBuilder::open_rw`
1140        Ok(EnvRw {
1141            env_ro: unsafe { self.open_with_readonly_flag(false) }?,
1142        })
1143    }
1144}
1145
1146impl DbBuilder<[u8], [u8], KeysUnique, ()> {
1147    /// Default options for database
1148    pub const fn new() -> Self {
1149        Self {
1150            key: PhantomData,
1151            value: PhantomData,
1152            constraint: KeysUnique,
1153            lmdb_flags: 0,
1154            name: (),
1155        }
1156    }
1157}
1158
1159impl<K: ?Sized, V: ?Sized, C> DbBuilder<K, V, C, ()>
1160where
1161    C: Constraint,
1162{
1163    /// Clear `dupsort` option (also clears `reversedup` option)
1164    ///
1165    /// See [`DbBuilder::keys_duplicate`] for setting `dupsort` option and
1166    /// [`DbBuilder::has_duplicate_keys`] for getting current state of flag.
1167    pub const fn keys_unique(mut self) -> DbBuilder<K, V, KeysUnique, ()> {
1168        flag_set!(self, MDB_DUPSORT, false);
1169        flag_set!(self, MDB_REVERSEDUP, false);
1170        DbBuilder {
1171            constraint: KeysUnique,
1172            key: PhantomData,
1173            value: PhantomData,
1174            lmdb_flags: self.lmdb_flags,
1175            name: self.name,
1176        }
1177    }
1178    /// Set `dupsort` option
1179    ///
1180    /// Note: Using this option will put an additional constraint on the size
1181    /// of each value stored in the database (see [`Env::max_keysize`]).
1182    ///
1183    /// See [`DbBuilder::keys_unique`] for clearing `dupsort` option and
1184    /// [`DbBuilder::has_duplicate_keys`] for getting current state of flag.
1185    pub const fn keys_duplicate(mut self) -> DbBuilder<K, V, KeysDuplicate, ()> {
1186        flag_set!(self, MDB_DUPSORT, true);
1187        DbBuilder {
1188            constraint: KeysDuplicate,
1189            key: PhantomData,
1190            value: PhantomData,
1191            lmdb_flags: self.lmdb_flags,
1192            name: self.name,
1193        }
1194    }
1195    /// Set stored key type
1196    ///
1197    /// It's possible to use [`NoKey`] as type parameter for databases which
1198    /// contain only a single value.
1199    pub const fn key_type<T>(mut self) -> DbBuilder<T, V, C, ()>
1200    where
1201        T: ?Sized + Storable,
1202    {
1203        flag_set!(self, MDB_INTEGERKEY, T::OPTIMIZE_INT);
1204        DbBuilder {
1205            key: PhantomData,
1206            value: PhantomData,
1207            constraint: self.constraint,
1208            lmdb_flags: self.lmdb_flags,
1209            name: self.name,
1210        }
1211    }
1212    /// Set stored value type
1213    ///
1214    /// It's possible to use [`NoValue`] as type parameter for databases which
1215    /// only contain keys but no values.
1216    pub const fn value_type<T>(mut self) -> DbBuilder<K, T, C, ()>
1217    where
1218        T: ?Sized + Storable,
1219    {
1220        flag_set!(self, MDB_DUPFIXED, T::CONST_BYTES_LEN);
1221        flag_set!(self, MDB_INTEGERDUP, T::OPTIMIZE_INT);
1222        DbBuilder {
1223            value: PhantomData,
1224            key: PhantomData,
1225            constraint: self.constraint,
1226            lmdb_flags: self.lmdb_flags,
1227            name: self.name,
1228        }
1229    }
1230}
1231
1232impl<K: ?Sized, V: ?Sized, C, N> DbBuilder<K, V, C, N>
1233where
1234    C: Constraint,
1235{
1236    /// Get `reversekey` option
1237    pub const fn get_reversekey(&self) -> bool {
1238        flag_get!(self, MDB_REVERSEKEY)
1239    }
1240    /// Set or clear `reversekey` option
1241    pub const fn reversekey(mut self, flag: bool) -> Self {
1242        flag_set!(self, MDB_REVERSEKEY, flag);
1243        self
1244    }
1245    /// Return sanitized flags for LMDB
1246    /// (clear flags that are only used for for databases with duplicate keys
1247    /// if unique keys have been selected)
1248    const fn cleansed_lmdb_flags(&self) -> LmdbFlags {
1249        if flag_get!(self, MDB_DUPSORT) {
1250            self.lmdb_flags
1251        } else {
1252            self.lmdb_flags
1253                & !((lmdb::MDB_REVERSEDUP | lmdb::MDB_DUPFIXED | lmdb::MDB_INTEGERDUP) as LmdbFlags)
1254        }
1255    }
1256    /// Use unnamed database
1257    ///
1258    /// Should be used as last builder method because some other builder
1259    /// methods are not available anymore after calling this method.
1260    pub fn unnamed(self) -> DbSpec<K, V, C> {
1261        DbBuilder {
1262            value: PhantomData,
1263            key: PhantomData,
1264            constraint: self.constraint,
1265            lmdb_flags: self.lmdb_flags,
1266            name: None,
1267        }
1268    }
1269    /// Use named database (name must not contain a null byte)
1270    ///
1271    /// Should be used as last builder method because some other builder
1272    /// methods are not available anymore after calling this method.
1273    pub fn name<T: Into<Vec<u8>>>(self, name: T) -> DbSpec<K, V, C> {
1274        let name = CString::new(name).expect("database name must not contain NULL byte");
1275        DbBuilder {
1276            value: PhantomData,
1277            key: PhantomData,
1278            constraint: self.constraint,
1279            lmdb_flags: self.lmdb_flags,
1280            name: Some(name),
1281        }
1282    }
1283    /// Remove name information
1284    ///
1285    /// NOTE: This does not select the unnamed database. To select the unnamed
1286    /// database, use [`DbBuilder::unnamed`].
1287    pub fn strip_name<T: Into<Vec<u8>>>(self) -> DbBuilder<K, V, C, ()> {
1288        DbBuilder {
1289            value: PhantomData,
1290            key: PhantomData,
1291            constraint: self.constraint,
1292            lmdb_flags: self.lmdb_flags,
1293            name: (),
1294        }
1295    }
1296}
1297
1298impl<K: ?Sized, V: ?Sized, C: Constraint, N> DbBuilder<K, V, C, N> {
1299    /// Returns true if duplicate keys are allowed (i.e. is `dupsort` option set?)
1300    ///
1301    /// See [`DbBuilder::keys_unique`] and [`DbBuilder::keys_duplicate`].
1302    pub fn has_duplicate_keys(&self) -> bool {
1303        C::DUPLICATE_KEYS
1304    }
1305}
1306
1307impl<K: ?Sized, V: ?Sized, N> DbBuilder<K, V, KeysDuplicate, N> {
1308    /// Get `reversedup` option
1309    pub const fn get_reversedup(&self) -> bool {
1310        flag_get!(self, MDB_REVERSEDUP)
1311    }
1312    /// Set or clear `reversedup` option
1313    pub const fn reversedup(mut self, flag: bool) -> Self {
1314        flag_set!(self, MDB_REVERSEDUP, flag);
1315        self
1316    }
1317}
1318
1319/// Function passed to [`lmdb::mdb_set_compare`] to compare two keys or values
1320/// in the database
1321///
1322/// # Safety
1323///
1324/// * Pointers `a` and `b` must be valid.
1325/// * For each `a` and `b`, [`lmdb::MDB_val::mv_data`] must be valid for reads
1326///   for the corresponding [`lmdb::MDB_val::mv_size`] bytes (no alignment
1327///   required and `mv_size` may differ for `a` and `b`) until the function
1328///   returns.
1329/// * The pointed to bytes must have been created with
1330///   [`<T as Storable>::to_bytes`](Storable::to_bytes) on the same platform
1331///   (same endianess / word size).
1332///
1333/// Note: Regardless of whether it is considered to be UB to unwind from an
1334/// `extern "C" fn`, this function can never unwind if implementors of
1335/// [`Storable::cmp_bytes_unchecked`] ensure that `cmp_bytes_unchecked` never
1336/// unwinds (which is demanded by the corresponding `unsafe` trait
1337/// documentation).
1338unsafe extern "C" fn compare_function<T>(a: *const lmdb::MDB_val, b: *const lmdb::MDB_val) -> c_int
1339where
1340    T: ?Sized + Storable,
1341{
1342    // SAFETY: `a` and `b` fulfill the documented requirements of
1343    // `compare_function`
1344    unsafe {
1345        let a: &[u8] = slice::from_raw_parts((*a).mv_data as *const u8, (*a).mv_size);
1346        let b: &[u8] = slice::from_raw_parts((*b).mv_data as *const u8, (*b).mv_size);
1347        T::cmp_bytes_unchecked(a, b) as c_int
1348    }
1349}
1350
1351impl EnvRo {
1352    /// Return true if given size (in bytes) is valid for a key (or value in a
1353    /// database with duplicate keys)
1354    fn size_valid_keysize(&self, size: usize) -> bool {
1355        (1..=self.max_keysize()).contains(&size)
1356    }
1357    /// Return true if given slice has valid size/length as key (or value in a
1358    /// database with duplicate keys)
1359    fn slice_valid_keysize(&self, key: &[u8]) -> bool {
1360        self.size_valid_keysize(key.len())
1361    }
1362    /// Return error if slice doesn't have valid size/length as key
1363    fn assert_valid_keysize(&self, key: &[u8]) -> io::Result<()> {
1364        if self.slice_valid_keysize(key) {
1365            Ok(())
1366        } else {
1367            Err(io::Error::new(
1368                io::ErrorKind::InvalidData,
1369                "invalid key size",
1370            ))
1371        }
1372    }
1373    /// Return error if slice doesn't have valid size/length as value in a
1374    /// database with duplicate keys
1375    fn assert_valid_valuesize(&self, value: &[u8]) -> io::Result<()> {
1376        if self.slice_valid_keysize(value) {
1377            Ok(())
1378        } else {
1379            Err(io::Error::new(
1380                io::ErrorKind::InvalidData,
1381                "invalid value size",
1382            ))
1383        }
1384    }
1385    /// Opens several databases at once (which must be of the same key and
1386    /// value type and key constraint)
1387    ///
1388    /// # Safety
1389    ///
1390    /// * If a database exists already, it must have been created with
1391    /// compatible options.
1392    /// * Implementation of [`Storable`] for the used
1393    ///   [keys](DbBuilder::key_type) and [values](DbBuilder::value_type) must
1394    ///   behave the same as when the database was created.
1395    /// * If `create` is true, then this method call must be synchronized and
1396    ///   no write transaction must be currently open by the current thread.
1397    unsafe fn open_or_opt_create_db<'a, K, V, C>(
1398        &self,
1399        db_spec: &DbSpec<K, V, C>,
1400        create: bool,
1401    ) -> io::Result<Db<K, V, C>>
1402    where
1403        K: ?Sized + Storable + 'a,
1404        V: ?Sized + Storable + 'a,
1405        C: Constraint,
1406    {
1407        let mut dbis = self.backend.dbis.lock().unwrap();
1408        let mut txn_inner = MaybeUninit::<*mut lmdb::MDB_txn>::uninit();
1409        // SAFETY:
1410        //  *  It's allowed to open several read-only transactions (`create` is
1411        //     `false`).
1412        //  *  If `create` is true, then documentation requires that this
1413        //     method is synchronized and no write transaction must be
1414        //     currently open by the current thread.
1415        //  *  The transaction is only used by the current thread (only within
1416        //     this function as `TxnBackend` is dropped before this function
1417        //     returns or panics).
1418        //  *  There are no cursors created here which could be used by other
1419        //     threads or span transactions.
1420        //  *  The status passed to `check_err_code` is valid.
1421        unsafe {
1422            check_err_code(lmdb::mdb_txn_begin(
1423                self.backend.inner,
1424                null_mut(),
1425                if create {
1426                    0 as LmdbFlags
1427                } else {
1428                    lmdb::MDB_RDONLY as LmdbFlags
1429                },
1430                txn_inner.as_mut_ptr(),
1431            ))?;
1432        }
1433        // SAFETY: call to `lmdb::mdb_txn_begin` above has been successful as
1434        // otherwise `check_err_code` would have returned an `Err` resulting in
1435        // early return from this function
1436        let txn_inner = unsafe { txn_inner.assume_init() };
1437        let txn = TxnBackend {
1438            env_ro: self,
1439            inner: txn_inner,
1440            cursors: Default::default(),
1441        };
1442        let mut db_inner = MaybeUninit::<lmdb::MDB_dbi>::uninit();
1443        let mut flags = db_spec.cleansed_lmdb_flags();
1444        if create {
1445            flags |= lmdb::MDB_CREATE as LmdbFlags;
1446        }
1447        // SAFETY:
1448        //  *  Mutex `EnvBackend::dbis` is locked and ensures that
1449        //     `lmdb::mdb_dbi_close` is not called concurrently. This is
1450        //     important because we must determine below if the returned
1451        //     `lmdb::MDB_dbi` integer belongs to an already open database,
1452        //     in which case it must be ensured that it is only closed
1453        //     once.
1454        //  *  The database handle, if a new one, can only be used by other
1455        //     transactions after the corresponding transaction is
1456        //     successfully committed below.
1457        //  *  If the transaction is aborted, `lmdb::mdb_dbi_close` will not be
1458        //     called because the database handle will be closed automatically.
1459        //  *  If and only if the transaction is committed (and the
1460        //     `lmdb::MDB_dbi` handle is a new handle), a `DbBackend` is
1461        //     created which will take care of closing the database handle when
1462        //     dropped.
1463        //  *  `lmdb::mdb_dbi_open` is only called here and the locked mutex
1464        //     `EnvBackend::dbis` ensures that `lmdb::mdb_dbi_open` is not
1465        //     called from multiple concurrent transactions in the same process
1466        //     (for the same environment).
1467        //  *  Documentation of this function (`open_or_opt_create_db`) demands
1468        //     that if a database exists already, it must have been created
1469        //     with compatible options. Documentation of `EnvBuilder::open_ro`
1470        //     and `EnvBuilder::open_rw` makes additional demands in regard to
1471        //     the database being free of corruption and having been
1472        //     created on a compatible platform. In addition with the
1473        //     requirements for implementing the unsafe trait `Storable` for
1474        //     key and value types, as well as invoking
1475        //     `DbBuilder::cleansed_lmdb_flags` above, it is ensured that the
1476        //     `flags` are valid and that they match any previous creation of
1477        //     the database.
1478        //  *  The status passed to `check_err_code` is valid.
1479        unsafe {
1480            check_err_code(lmdb::mdb_dbi_open(
1481                txn.inner,
1482                db_spec.name.as_ref().map_or(null(), |x| x.as_ptr()),
1483                flags,
1484                db_inner.as_mut_ptr(),
1485            ))?;
1486        }
1487        // SAFETY: call to `lmdb::mdb_dbi_open` above has been successful as
1488        // otherwise `check_err_code` would have returned an `Err` resulting in
1489        // early return from this function
1490        let db_inner = unsafe { db_inner.assume_init() };
1491        let backend = match dbis.get(&db_inner).and_then(Weak::upgrade) {
1492            Some(arc) => {
1493                txn.commit()?;
1494                arc
1495            }
1496            None => {
1497                // SAFETY:
1498                //  *  Functions `mdb_set_compare` and `mdb_set_dupsort` are
1499                //     always called before any data access through the
1500                //     database handle can happen.
1501                //  *  Documentation of this function (`open_or_opt_create_db`)
1502                //     demands that if a database exists already, it must have
1503                //     been created with compatible options. Documentation of
1504                //     `EnvBuilder::open_ro` and `EnvBuilder::open_rw` makes
1505                //     additional demands in regard to the database being free
1506                //     of corruption and having been created on a compatible
1507                //     platform. This ensures that `mdb_set_compare` and
1508                //     `mdb_set_dupsort` are set consistently in regard to when
1509                //     the database was created.
1510                //  *  `mdb_set_compare` and `mdb_set_dupsort` are expected to
1511                //     ensure that only valid pointers are passed to the
1512                //     `compare_function`.
1513                //  *  `compare_function` does not unwind. (If it would unwind,
1514                //     it could leave the environment in an invalid state.
1515                //     TODO: Adjust this remark, the corresponding comment on
1516                //     `compare_function`, and the `Storable` trait when/if
1517                //     Rust implements an abort-on-panic shim for
1518                //     `extern "C" fn`.)
1519                //  *  The status passed to `check_err_code` is valid.
1520                unsafe {
1521                    if !K::TRIVIAL_CMP && !K::OPTIMIZE_INT {
1522                        check_err_code(lmdb::mdb_set_compare(
1523                            txn.inner,
1524                            db_inner,
1525                            Some(compare_function::<K>),
1526                        ))?;
1527                    }
1528                    if !V::TRIVIAL_CMP && !V::OPTIMIZE_INT && C::DUPLICATE_KEYS {
1529                        check_err_code(lmdb::mdb_set_dupsort(
1530                            txn.inner,
1531                            db_inner,
1532                            Some(compare_function::<V>),
1533                        ))?;
1534                    }
1535                }
1536                let env_backend = Arc::downgrade(&self.backend);
1537                let env_id = self.backend.id;
1538                txn.commit()?;
1539                let db_backend = DbBackend {
1540                    env_backend,
1541                    env_id,
1542                    inner: db_inner,
1543                };
1544                let arc = Arc::new(db_backend);
1545                dbis.insert(db_inner, Arc::downgrade(&arc));
1546                arc
1547            }
1548        };
1549        let db = Db {
1550            key: PhantomData,
1551            value: PhantomData,
1552            constraint: db_spec.constraint,
1553            backend: ArcByAddr::from(backend),
1554        };
1555        drop(dbis);
1556        Ok(db)
1557    }
1558}
1559
1560/// Read-write or read-only handle for accessing environment that stores
1561/// key-value databases
1562///
1563/// This trait is implemented by [`EnvRo`] and [`EnvRw`] and provides the
1564/// methods for read-only access to the environment. Read-write access is
1565/// performed by methods directly implemented on `EnvRw`.
1566pub trait Env: AsRef<EnvRo> {
1567    /// Reference conversion to [`EnvRo`]
1568    ///
1569    /// To obtain an owned [`EnvRo`], you can use [`Env::clone_ro`] as a
1570    /// shorthand for `.as_env_ro().clone()`.
1571    fn as_env_ro(&self) -> &EnvRo {
1572        self.as_ref()
1573    }
1574    /// Clone as [`EnvRo`]
1575    fn clone_ro(&self) -> EnvRo {
1576        self.as_env_ro().clone()
1577    }
1578    /// Start read-only transaction
1579    fn txn_ro(&self) -> io::Result<TxnRo<'_>>;
1580    /// Get maximum size of keys and duplicate data
1581    fn max_keysize(&self) -> usize;
1582    /// Checks if key or duplicate data has valid size
1583    fn valid_keysize<'kr, K, KRef>(&self, key: KRef) -> bool
1584    where
1585        K: ?Sized + Storable + 'kr,
1586        KRef: StorableRef<'kr, K>;
1587    /// Open database in environment
1588    ///
1589    /// # Safety
1590    ///
1591    /// * If a database exists already, it must have been created with
1592    /// compatible options.
1593    /// * Implementation of [`Storable`] for the used
1594    ///   [keys](DbBuilder::key_type) and [values](DbBuilder::value_type) must
1595    ///   behave the same as when the database was created.
1596    unsafe fn open_db<K, V, C>(&self, options: &DbSpec<K, V, C>) -> io::Result<Db<K, V, C>>
1597    where
1598        K: ?Sized + Storable,
1599        V: ?Sized + Storable,
1600        C: Constraint;
1601    /// Clear stale readers
1602    ///
1603    /// Refer to LMDB's documentation when to clear stale readers
1604    fn clear_stale_readers(&self) -> io::Result<usize>;
1605}
1606
1607impl Env for EnvRo {
1608    fn txn_ro(&self) -> io::Result<TxnRo<'_>> {
1609        unsafe {
1610            let mut inner_txn = MaybeUninit::<*mut lmdb::MDB_txn>::uninit();
1611            // SAFETY:
1612            //  *  `mdb_txn_begin` doesn't have any special requirements for
1613            //     read-only transactions because `lmdb::MDB_NOTLS` is set
1614            //     (and no child transactions are created for read-only
1615            //     transactions either).
1616            //  *  The status passed to `check_err_code` is valid.
1617            check_err_code(lmdb::mdb_txn_begin(
1618                self.backend.inner,
1619                null_mut(),
1620                lmdb::MDB_RDONLY as LmdbFlags,
1621                inner_txn.as_mut_ptr(),
1622            ))?;
1623            // SAFETY: call to `lmdb::mdb_txn_begin` above has been successful
1624            // as otherwise `check_err_code` would have returned an `Err`
1625            // resulting in early return from this function
1626            let inner_txn = inner_txn.assume_init();
1627            Ok(TxnRo {
1628                backend: UnsafeCell::new(TxnBackend {
1629                    env_ro: &self,
1630                    inner: inner_txn,
1631                    cursors: Default::default(),
1632                }),
1633            })
1634        }
1635    }
1636    fn max_keysize(&self) -> usize {
1637        self.backend.max_keysize
1638    }
1639    fn valid_keysize<'kr, K, KRef>(&self, key: KRef) -> bool
1640    where
1641        K: ?Sized + Storable + 'kr,
1642        KRef: StorableRef<'kr, K>,
1643    {
1644        self.size_valid_keysize(key.ref_bytes_len())
1645    }
1646    unsafe fn open_db<K, V, C>(&self, options: &DbSpec<K, V, C>) -> io::Result<Db<K, V, C>>
1647    where
1648        K: ?Sized + Storable,
1649        V: ?Sized + Storable,
1650        C: Constraint,
1651    {
1652        // SAFETY:
1653        //  *  Documentation of `Env::open_db` demands that if the database
1654        //     exists already, it must have been created with compatible
1655        //     options.
1656        //  *  Second argument of `open_or_opt_create_db` is set to `false`.
1657        unsafe { self.open_or_opt_create_db(options, false) }
1658    }
1659    fn clear_stale_readers(&self) -> io::Result<usize> {
1660        unsafe {
1661            let mut dead = MaybeUninit::<c_int>::uninit();
1662            // SAFETY:
1663            //  *  `mdb_reader_check` doesn't have any special requirements
1664            //  *  status passed to `check_err_code` is valid
1665            check_err_code(lmdb::mdb_reader_check(
1666                self.backend.inner,
1667                dead.as_mut_ptr(),
1668            ))?;
1669            // SAFETY: call to `lmdb::mdb_reader_check` above has been
1670            // successful as otherwise `check_err_code` would have returned an
1671            // `Err` resulting in early return from this function
1672            let dead = dead.assume_init();
1673            Ok(dead
1674                .try_into()
1675                .expect("reported number of stale reader transactions does not fit into usize"))
1676        }
1677    }
1678}
1679
1680impl Env for EnvRw {
1681    fn txn_ro(&self) -> io::Result<TxnRo<'_>> {
1682        self.as_env_ro().txn_ro()
1683    }
1684    fn max_keysize(&self) -> usize {
1685        self.as_env_ro().max_keysize()
1686    }
1687    fn valid_keysize<'kr, K, KRef>(&self, key: KRef) -> bool
1688    where
1689        K: ?Sized + Storable + 'kr,
1690        KRef: StorableRef<'kr, K>,
1691    {
1692        self.as_env_ro().valid_keysize(key)
1693    }
1694    unsafe fn open_db<K, V, C>(&self, options: &DbSpec<K, V, C>) -> io::Result<Db<K, V, C>>
1695    where
1696        K: ?Sized + Storable,
1697        V: ?Sized + Storable,
1698        C: Constraint,
1699    {
1700        // SAFETY: calls same trait method which has the same requirements
1701        unsafe { self.as_env_ro().open_db(options) }
1702    }
1703    fn clear_stale_readers(&self) -> io::Result<usize> {
1704        self.as_env_ro().clear_stale_readers()
1705    }
1706}
1707
1708impl EnvRw {
1709    /// Check if transactions are nestable
1710    ///
1711    /// See [`TxnRw::nested`].
1712    pub fn nestable_txns(&self) -> bool {
1713        self.env_ro.backend.nestable_txns
1714    }
1715    /// Open database in environment and create if non-existing
1716    ///
1717    /// # Safety
1718    ///
1719    /// * If a database exists already, it must have been created with
1720    /// compatible options.
1721    /// * Implementation of [`Storable`] for the used
1722    ///   [keys](DbBuilder::key_type) and [values](DbBuilder::value_type) must
1723    ///   behave the same as when the database was created.
1724    pub unsafe fn create_db<K, V, C>(
1725        &mut self,
1726        options: &DbSpec<K, V, C>,
1727    ) -> io::Result<Db<K, V, C>>
1728    where
1729        K: ?Sized + Storable,
1730        V: ?Sized + Storable,
1731        C: Constraint,
1732    {
1733        // SAFETY:
1734        //  *  Documentation of `EnvRw::create_db` demands that if the database
1735        //     exists already, it must have been created with compatible
1736        //     options.
1737        //  *  Calling `EnvRo::open_or_opt_create_db` is synchronized due to
1738        //     `&mut self` reference.
1739        //  *  No write transaction can be open because `EnvRw::txn_rw` also
1740        //     requires `&mut self`.
1741        unsafe { self.env_ro.open_or_opt_create_db(options, true) }
1742    }
1743    /// Delete database in environment
1744    ///
1745    /// This method panics if there are clones of the [`Db`] handle.
1746    /// Use [`TxnRw::delete_all`] to only delete the contents of the database.
1747    pub fn drop_db<K, V, C>(&mut self, db: Db<K, V, C>) -> io::Result<()>
1748    where
1749        K: ?Sized + Storable,
1750        V: ?Sized + Storable,
1751        C: Constraint,
1752    {
1753        let db_backend = ArcByAddr::try_unwrap(db.backend).map_err(|_| {
1754            io::Error::new(io::ErrorKind::Other, "database in use by current process")
1755        })?;
1756        db_backend.assert_env_backend(&self.env_ro.backend);
1757        let dbis = self.env_ro.backend.dbis.lock().unwrap();
1758        unsafe {
1759            let mut txn_inner = MaybeUninit::<*mut lmdb::MDB_txn>::uninit();
1760            // SAFETY:
1761            //  *  `&mut self` ensures that no other write transaction (for the
1762            //     given environment) can be open by the current thread (and
1763            //     whole process).
1764            //  *  The transaction is only used by the current thread because
1765            //     it is only used within this function.
1766            //  *  There are no cursors created here which could be used by other
1767            //     threads or span transactions.
1768            //  *  The status passed to `check_err_code` is valid.
1769            check_err_code(lmdb::mdb_txn_begin(
1770                self.env_ro.backend.inner,
1771                null_mut(),
1772                0 as LmdbFlags,
1773                txn_inner.as_mut_ptr(),
1774            ))?;
1775            // SAFETY: call to `lmdb::mdb_txn_begin` above has been successful
1776            // as otherwise `check_err_code` would have returned an `Err`
1777            // resulting in early return from this function
1778            let txn_inner = txn_inner.assume_init();
1779            let txn = TxnBackend {
1780                env_ro: &self.env_ro,
1781                inner: txn_inner,
1782                cursors: Default::default(),
1783            };
1784            let db_inner = db_backend.inner;
1785            db_backend.dont_close();
1786            // SAFETY:
1787            //  *  `&mut self` ensures that `lmdb::mdb_drop` is only called by
1788            //     a single thread at the same time (for the given
1789            //     environment), because no write transaction can be open.
1790            //  *  No other threads can use the database or any of its cursors
1791            //     in a read-only transaction because the `DbBackend` was
1792            //     successfully unwrapped from the `Arc` above.
1793            //  *  No other write transaction which could have modified the
1794            //     database can be open because of holding a `&mut self` which
1795            //     ensures that no other write transaction is open.
1796            //  *  The above call of `DbBackend::dont_close` ensures that the
1797            //     database handle isn't closed twice.
1798            //  *  The status passed to `check_err_code` is valid.
1799            check_err_code(lmdb::mdb_drop(txn.inner, db_inner, 1))?;
1800            txn.commit()?;
1801        }
1802        drop(dbis);
1803        Ok(())
1804    }
1805    /// Start read-write transaction
1806    pub fn txn_rw(&mut self) -> io::Result<TxnRw<'_>> {
1807        let mut txn_inner = MaybeUninit::<*mut lmdb::MDB_txn>::uninit();
1808        // SAFETY:
1809        //  *  `&mut self` ensures that no other write transaction (for the
1810        //     given environment) can be open by the current thread (and
1811        //     whole process).
1812        //  *  The status passed to `check_err_code` is valid.
1813        unsafe {
1814            check_err_code(lmdb::mdb_txn_begin(
1815                self.env_ro.backend.inner,
1816                null_mut(),
1817                0,
1818                txn_inner.as_mut_ptr(),
1819            ))?;
1820        }
1821        // SAFETY: call to `lmdb::mdb_txn_begin` above has been successful as
1822        // otherwise `check_err_code` would have returned an `Err` resulting in
1823        // early return from this function
1824        let txn_inner = unsafe { txn_inner.assume_init() };
1825        Ok(TxnRw {
1826            backend: UnsafeCell::new(TxnBackend {
1827                env_ro: &self.env_ro,
1828                inner: txn_inner,
1829                cursors: Default::default(),
1830            }),
1831            used_dbs: UsedDbs::Toplevel(Default::default()),
1832            commit_handlers: Default::default(),
1833        })
1834    }
1835}
1836
1837impl<'a> TxnBackend<'a> {
1838    /// Commit transaction
1839    fn commit(self) -> io::Result<()> {
1840        let inner = self.inner;
1841        self.dont_abort();
1842        // SAFETY:
1843        //  *  transaction cannot be used further
1844        //  *  all cursors have been closed by `TxnBackend::dont_abort(self)`
1845        //  *  the status passed to `check_err_code` is valid
1846        unsafe {
1847            check_err_code(lmdb::mdb_txn_commit(inner))?;
1848        }
1849        Ok(())
1850    }
1851    /// Get reference to value in database
1852    ///
1853    /// # Safety
1854    ///
1855    /// * The value is only valid until end of a read-only transaction or, in
1856    ///   case of a read-write transaction, until the transaction ends or
1857    ///   modifies data. The caller has to ensure that the lifetime `'b` is
1858    ///   short enough.
1859    unsafe fn get_unsafe<'b, 'kr, K, V, C, KRef>(
1860        &mut self,
1861        db: &Db<K, V, C>,
1862        key: KRef,
1863    ) -> io::Result<Option<V::AlignedRef<'b>>>
1864    where
1865        K: ?Sized + Storable + 'kr,
1866        V: ?Sized + Storable,
1867        C: Constraint,
1868        KRef: StorableRef<'kr, K>,
1869    {
1870        db.backend.assert_env_backend(&self.env_ro.backend);
1871        let key: K::BytesRef<'_> = key.ref_to_bytes();
1872        let lmdb_key = lmdb::MDB_val {
1873            mv_size: key.len(),
1874            mv_data: key.as_ptr() as *mut _,
1875        };
1876        let mut lmdb_data = MaybeUninit::<lmdb::MDB_val>::uninit();
1877        Ok(
1878            // SAFETY:
1879            //  *  `lmdb_key.mv_data` is a valid pointer to `lmdb_key.mv_size`
1880            //     bytes of memory for reading.
1881            //  *  The memory pointed to by `lmdb_data.mv_data` is only read.
1882            //  *  Documentation requires that `'b` must not live longer than
1883            //     the end of the read-only transaction or until the read-write
1884            //     transaction ends or modifies data. The lifetime of the
1885            //     reference returned by `slice::from_raw_parts` below is
1886            //     inferred as being `'b`. Thus the memory won't be accessed
1887            //     afterwards.
1888            match unsafe {
1889                lmdb::mdb_get(
1890                    self.inner,
1891                    db.backend.inner,
1892                    &lmdb_key as *const _ as *mut lmdb::MDB_val,
1893                    lmdb_data.as_mut_ptr(),
1894                )
1895            } {
1896                lmdb::MDB_NOTFOUND => None,
1897                status => {
1898                    // SAFETY: `status` is a valid LMDB return code, and if
1899                    // negative, it is a valid LMDB error code
1900                    unsafe { check_err_code(status) }?;
1901                    // SAFETY: call to `lmdb::mdb_get` above has been
1902                    // successful as otherwise `check_err_code` would have
1903                    // returned an `Err` resulting in early return from this
1904                    // function
1905                    let lmdb_data = unsafe { lmdb_data.assume_init() };
1906                    // SAFETY:
1907                    //  *  The call to `lmdb::mdb_get` has been successful and
1908                    //     is expected to have written valid data to
1909                    //     `lmdb_data` (see SAFETY comment on `lmdb::mdb_get`
1910                    //     above regarding lifetimes).
1911                    //  *  Documentation of all methods opening databases
1912                    //     demand that if a database exists already, it must
1913                    //     have been created with compatible options.
1914                    //     Documentation of `EnvBuilder::open_ro` and
1915                    //     `EnvBuilder::open_rw` makes additional demands in
1916                    //     regard to the database being free of corruption and
1917                    //     having been created on a compatible platform. It is
1918                    //     thus safe to call `Storable::from_bytes_unchecked`.
1919                    Some(unsafe {
1920                        V::from_bytes_unchecked(slice::from_raw_parts(
1921                            lmdb_data.mv_data as *const u8,
1922                            lmdb_data.mv_size,
1923                        ))
1924                    })
1925                }
1926            },
1927        )
1928    }
1929    /// Create a new cursor
1930    fn new_cursor<K, V, C>(&mut self, db: &Db<K, V, C>) -> io::Result<Cursor<K, V, C>>
1931    where
1932        K: ?Sized,
1933        V: ?Sized,
1934        C: Constraint,
1935    {
1936        db.backend.assert_env_backend(&self.env_ro.backend);
1937        let mut inner_cursor = MaybeUninit::<*mut lmdb::MDB_cursor>::uninit();
1938        // SAFETY:
1939        //  *  Database handles are only closed when the `DbBackend` or
1940        //     `EnvBackend` is dropped. Because the `Cursor` struct contains a
1941        //     clone of the `Db` handle (after the `CursorBackend`, see SAFETY
1942        //     comment on `Cursor`), the database handle won't be closed while
1943        //     the cursor may be used.
1944        //  *  The cursor is not used after the transaction has ended because
1945        //     this modules API always requires a `TxnRo` or `TxnRw` for using
1946        //     the cursor. In regard to closing the cursor, see SAFETY comments
1947        //     where `lmdb::mdb_cursor_close` is invoked.
1948        unsafe {
1949            check_err_code(lmdb::mdb_cursor_open(
1950                self.inner,
1951                db.backend.inner,
1952                inner_cursor.as_mut_ptr(),
1953            ))?;
1954        }
1955        // SAFETY: call to `lmdb::mdb_cursor_open` above has been successful as
1956        // otherwise `check_err_code` would have returned an `Err` resulting in
1957        // early return from this function
1958        let inner_cursor = unsafe { inner_cursor.assume_init() };
1959        // SAFETY: clone `db` first, see `CursorBackend::drop`
1960        let db = db.clone();
1961        let cursor_backend = Arc::new(CursorBackend {
1962            inner: inner_cursor,
1963            closed: Default::default(),
1964            inner_txn: self.inner,
1965        });
1966        self.cursors.push(Arc::downgrade(&cursor_backend));
1967        Ok(Cursor {
1968            backend: ArcByAddr::from(cursor_backend),
1969            db,
1970        })
1971    }
1972    /// Execute cursor operation
1973    ///
1974    /// The returned key or value may be retrieved by calling an `FnOnce`
1975    /// closure when needed.
1976    ///
1977    /// # Safety
1978    ///
1979    /// * Any returned keys or values are only valid until end of a
1980    ///  read-only transaction or until a read-write transaction ends or
1981    ///  modifies data. The caller has to ensure that the lifetime `'b` is
1982    ///  short enough.
1983    unsafe fn cursor_op_unsafe<'b, 'kr, 'vr, K, V, C, KRef, VRef>(
1984        &mut self,
1985        cursor: &Cursor<K, V, C>,
1986        key: Option<KRef>,
1987        value: Option<VRef>,
1988        op: lmdb::MDB_cursor_op,
1989    ) -> io::Result<
1990        Option<(
1991            impl FnOnce() -> K::AlignedRef<'b>,
1992            impl FnOnce() -> V::AlignedRef<'b>,
1993        )>,
1994    >
1995    where
1996        K: ?Sized + Storable + 'kr,
1997        V: ?Sized + Storable + 'vr,
1998        C: Constraint,
1999        KRef: StorableRef<'kr, K>,
2000        VRef: StorableRef<'vr, V>,
2001    {
2002        cursor.backend.assert_txn_backend(self);
2003        let mut lmdb_key = match key {
2004            Some(key) => {
2005                let key: K::BytesRef<'_> = key.ref_to_bytes();
2006                lmdb::MDB_val {
2007                    mv_size: key.len(),
2008                    mv_data: key.as_ptr() as *mut _,
2009                }
2010            }
2011            None => lmdb::MDB_val {
2012                mv_size: 0,
2013                mv_data: null_mut(),
2014            },
2015        };
2016        let mut lmdb_data = match value {
2017            Some(value) => {
2018                let value: V::BytesRef<'_> = value.ref_to_bytes();
2019                lmdb::MDB_val {
2020                    mv_size: value.len(),
2021                    mv_data: value.as_ptr() as *mut _,
2022                }
2023            }
2024            None => lmdb::MDB_val {
2025                mv_size: 0,
2026                mv_data: null_mut(),
2027            },
2028        };
2029        Ok(
2030            // SAFETY:
2031            //  *  `lmdb_key.mv_data` and `lmdb_data.mv_data` are valid
2032            //     pointers to `lmdb_key.mv_size` and `lmdb_data.mv_size`
2033            //     bytes of memory, respectively, for reading.
2034            //  *  The memory pointed to by `lmdb_key.mv_data` and
2035            //     `lmdb_data.mv_data` is only read subsequently.
2036            //  *  Documentation requires that `'b` must not live longer than
2037            //     the end of the read-only transaction or until the read-write
2038            //     transaction ends or modifies data. The lifetime of the
2039            //     reference returned by `slice::from_raw_parts` below is
2040            //     inferred as being `'b`. Thus the memory won't be accessed
2041            //     afterwards.
2042            match unsafe {
2043                lmdb::mdb_cursor_get(cursor.backend.inner, &mut lmdb_key, &mut lmdb_data, op)
2044            } {
2045                lmdb::MDB_NOTFOUND => None,
2046                status => {
2047                    // SAFETY: `status` is a valid LMDB return code, and if
2048                    // negative, it is a valid LMDB error code
2049                    unsafe { check_err_code(status) }?;
2050                    // SAFETY:
2051                    //  *  The call to `lmdb::mdb_cursor_get` has been
2052                    //     successful and is expected to either have written
2053                    //     valid data to `lmdb_key` and `lmdb_data` or to not
2054                    //     have written anything to one or both of them (see
2055                    //     SAFETY comment on `lmdb::mdb_cursor_get` above
2056                    //     regarding lifetimes).
2057                    //  *  Documentation of all methods opening databases
2058                    //     demand that if a database exists already, it must
2059                    //     have been created with compatible options.
2060                    //     Documentation of `EnvBuilder::open_ro` and
2061                    //     `EnvBuilder::open_rw` makes additional demands in
2062                    //     regard to the database being free of corruption and
2063                    //     having been created on a compatible platform. It is
2064                    //     thus safe to call `Storable::from_bytes_unchecked`.
2065                    Some(unsafe {
2066                        (
2067                            move || {
2068                                K::from_bytes_unchecked(slice::from_raw_parts(
2069                                    lmdb_key.mv_data as *const u8,
2070                                    lmdb_key.mv_size,
2071                                ))
2072                            },
2073                            move || {
2074                                V::from_bytes_unchecked(slice::from_raw_parts(
2075                                    lmdb_data.mv_data as *const u8,
2076                                    lmdb_data.mv_size,
2077                                ))
2078                            },
2079                        )
2080                    })
2081                }
2082            },
2083        )
2084    }
2085    /// Get number of values for current cursor position
2086    fn cursor_get_current_value_count<K, V>(
2087        &mut self,
2088        cursor: &Cursor<K, V, KeysDuplicate>,
2089    ) -> io::Result<usize>
2090    where
2091        K: ?Sized + Storable,
2092        V: ?Sized + Storable,
2093    {
2094        cursor.backend.assert_txn_backend(self);
2095        let mut count = MaybeUninit::<usize>::uninit();
2096        // SAFETY:
2097        //  *  `lmdb::mdb_cursor_count` is only called on databases using
2098        //     `lmdb::MDB_DUPSORT` (because the third type parameter of
2099        //     `cursor` is `KeysDuplicate`).
2100        //  *  The status passed to `check_err_code` is valid.
2101        unsafe {
2102            check_err_code(lmdb::mdb_cursor_count(
2103                cursor.backend.inner,
2104                count.as_mut_ptr(),
2105            ))?;
2106        }
2107        // SAFETY: call to `lmdb::mdb_cursor_count` above has been successful as
2108        // otherwise `check_err_code` would have returned an `Err` resulting in
2109        // early return from this function
2110        Ok(unsafe { count.assume_init() })
2111    }
2112}
2113
2114/// Helper macro to create return type of cursor methods
2115macro_rules! cursor_return_type {
2116    (bool $(,)?) => (bool);
2117    (key $(,)?) => (Option<K::AlignedRef<'_>>);
2118    (value $(,)?) => (Option<V::AlignedRef<'_>>);
2119    ((key, value $(,)?)) => (Option<(K::AlignedRef<'_>, V::AlignedRef<'_>)>);
2120}
2121
2122/// Create signature for cursor method
2123macro_rules! cursor_method_def {
2124    ($($meta:meta)*, $name:ident, (), $retval:tt $(,)?) => {
2125            $(#[$meta])*
2126            fn $name<K, V, C>(
2127                &self,
2128                cursor: &Cursor<K, V, C>,
2129            ) -> io::Result<cursor_return_type!($retval)>
2130            where
2131                K: ?Sized + Storable,
2132                V: ?Sized + Storable,
2133                C: Constraint;
2134    };
2135    ($($meta:meta)*, $name:ident, (key), $retval:tt $(,)?) => {
2136            $(#[$meta])*
2137            fn $name<'kr, K, V, C, KRef>(
2138                &self,
2139                cursor: &Cursor<K, V, C>,
2140                key: KRef,
2141            ) -> io::Result<cursor_return_type!($retval)>
2142            where
2143                K: ?Sized + Storable + 'kr,
2144                V: ?Sized + Storable,
2145                C: Constraint,
2146                KRef: StorableRef<'kr, K>;
2147    };
2148    ($($meta:meta)*, $name:ident, (key, value), $retval:tt $(,)?) => {
2149            $(#[$meta])*
2150            fn $name<'kr, 'vr, K, V, C, KRef, VRef>(
2151                &self,
2152                cursor: &Cursor<K, V, C>,
2153                key: KRef,
2154                value: VRef,
2155            ) -> io::Result<cursor_return_type!($retval)>
2156            where
2157                K: ?Sized + Storable + 'kr,
2158                V: ?Sized + Storable + 'vr,
2159                C: Constraint,
2160                KRef: StorableRef<'kr, K>,
2161                VRef: StorableRef<'vr, V>;
2162    };
2163}
2164
2165/// Create signatures for several cursor methods
2166macro_rules! cursor_method_defs {
2167    {
2168        $(
2169            $(#[$meta:meta])*
2170            fn $name:ident $args:tt -> $retval:tt;
2171        )*
2172    } => {
2173        $(
2174            cursor_method_def!($($meta)*, $name, $args, $retval);
2175        )*
2176    };
2177}
2178
2179/// Create signature for cursor method on databases with duplicate keys
2180macro_rules! cursor_method_dupkey_def {
2181    ($($meta:meta)*, $name:ident, (), $retval:tt $(,)?) => {
2182            $(#[$meta])*
2183            fn $name<K, V>(
2184                &self,
2185                cursor: &Cursor<K, V, KeysDuplicate>,
2186            ) -> io::Result<cursor_return_type!($retval)>
2187            where
2188                K: ?Sized + Storable,
2189                V: ?Sized + Storable;
2190    };
2191    ($($meta:meta)*, $name:ident, (key), $retval:tt $(,)?) => {
2192            $(#[$meta])*
2193            fn $name<'kr, K, V, KRef>(
2194                &self,
2195                cursor: &Cursor<K, V, KeysDuplicate>,
2196                key: KRef,
2197            ) -> io::Result<cursor_return_type!($retval)>
2198            where
2199                K: ?Sized + Storable + 'kr,
2200                V: ?Sized + Storable,
2201                KRef: StorableRef<'kr, K>;
2202    };
2203    ($($meta:meta)*, $name:ident, (key, value), $retval:tt $(,)?) => {
2204            $(#[$meta])*
2205            fn $name<'kr, 'vr, K, V, KRef, VRef>(
2206                &self,
2207                cursor: &Cursor<K, V, KeysDuplicate>,
2208                key: KRef,
2209                value: VRef,
2210            ) -> io::Result<cursor_return_type!($retval)>
2211            where
2212                K: ?Sized + Storable + 'kr,
2213                V: ?Sized + Storable + 'vr,
2214                KRef: StorableRef<'kr, K>,
2215                VRef: StorableRef<'vr, V>;
2216    };
2217}
2218
2219/// Create signatures for several cursor methods on databases with duplicate
2220/// keys
2221macro_rules! cursor_method_dupkey_defs {
2222    {
2223        $(
2224            $(#[$meta:meta])*
2225            fn $name:ident $args:tt -> $retval:tt;
2226        )*
2227    } => {
2228        $(
2229            cursor_method_dupkey_def!($($meta)*, $name, $args, $retval);
2230        )*
2231    };
2232}
2233
2234/// Read-write or read-only transaction
2235///
2236/// This trait provides the methods for read-access to databases.
2237/// The simplest interface is provided by [`Txn::get`], which returns a
2238/// [reference](Storable::AlignedRef) to the stored value for a given key
2239/// (or [`None`] if the key does not exist).
2240/// If an owned value is desired, use [`Txn::get_owned`] instead, which
2241/// automatically converts the reference (e.g. `&str`) into an owned value
2242/// (e.g. `String`) using [`GenericCow::into_owned`].
2243///
2244/// [`Txn::get`] and [`Txn::get_owned`] will only retrieve the first value in
2245/// case of [duplicate keys](DbBuilder::keys_duplicate). For more sophisticated
2246/// access, use [`Txn::new_cursor`] to create a new [`Cursor`] which then can
2247/// be used with one of the cursor methods in the `Txn` trait (or the [`TxnRw`]
2248/// struct in case of write access, respectively).
2249pub trait Txn {
2250    /// Get reference to value in database
2251    fn get<'kr, K, V, C, KRef>(
2252        &self,
2253        db: &Db<K, V, C>,
2254        key: KRef,
2255    ) -> io::Result<Option<V::AlignedRef<'_>>>
2256    where
2257        K: ?Sized + Storable + 'kr,
2258        V: ?Sized + Storable,
2259        C: Constraint,
2260        KRef: StorableRef<'kr, K>;
2261    /// Get owned value from database
2262    fn get_owned<'a, 'kr, K, V, C, KRef>(
2263        &'a self,
2264        db: &Db<K, V, C>,
2265        key: KRef,
2266    ) -> io::Result<Option<<V as ToOwned>::Owned>>
2267    where
2268        K: ?Sized + Storable + 'kr,
2269        V: ?Sized + Storable + ToOwned,
2270        C: Constraint,
2271        KRef: StorableRef<'kr, K>,
2272    {
2273        Ok(self.get(db, key)?.map(|x| x.into_owned()))
2274    }
2275    /// Create a new cursor
2276    fn new_cursor<K, V, C>(&self, db: &Db<K, V, C>) -> io::Result<Cursor<K, V, C>>
2277    where
2278        K: ?Sized + Storable,
2279        V: ?Sized + Storable,
2280        C: Constraint;
2281    /// Get number of values for current cursor position
2282    fn cursor_get_current_value_count<K, V>(
2283        &self,
2284        cursor: &Cursor<K, V, KeysDuplicate>,
2285    ) -> io::Result<usize>
2286    where
2287        K: ?Sized + Storable,
2288        V: ?Sized + Storable;
2289    cursor_method_defs! {
2290        /// Set cursor to first entry in database
2291        ///
2292        /// Returns `false` if database is empty.
2293        fn cursor_set_first() -> bool;
2294        /// Set cursor to first entry in database and get pair
2295        fn cursor_set_first_get_pair() -> (key, value);
2296        /// Set cursor to last entry in database
2297        ///
2298        /// Returns `false` if database is empty.
2299        fn cursor_set_last() -> bool;
2300        /// Set cursor to last entry in database and get pair
2301        fn cursor_set_last_get_pair() -> (key, value);
2302        /// Get key at current cursor position
2303        fn cursor_get_current_key() -> key;
2304        /// Get value at current cursor position
2305        fn cursor_get_current_value() -> value;
2306        /// Get key-value pair at current cursor position
2307        fn cursor_get_current_pair() -> (key, value);
2308        /// Set cursor to key
2309        ///
2310        /// Returns `false` if key does not exist.
2311        /// Note that in this case it's *not* guaranteed that subsequent
2312        /// accesses to the cursor using `cursor_get_current_` methods return
2313        /// `None`.
2314        fn cursor_set_key(key) -> bool;
2315        /// Set cursor to key and get value
2316        fn cursor_set_key_get_value(key) -> value;
2317        /// Set cursor to key or next greater key if not existent
2318        ///
2319        /// Returns `false` if no matching key has been found.
2320        /// Note that in this case it's *not* guaranteed that subsequent
2321        /// accesses to the cursor using `cursor_get_current_` methods return
2322        /// `None`.
2323        fn cursor_search_key(key) -> bool;
2324        /// Set cursor to key or next greater key if not existent and get pair
2325        fn cursor_search_key_get_pair(key) -> (key, value);
2326        /// Move cursor to next entry in database
2327        ///
2328        /// Returns `false` if there is no next entry.
2329        /// Note that in this case it's *not* guaranteed that subsequent
2330        /// accesses to the cursor using `cursor_get_current_` methods return
2331        /// `None`.
2332        fn cursor_set_next() -> bool;
2333        /// Move cursor to next entry in database and get pair
2334        fn cursor_set_next_get_pair() -> (key, value);
2335        /// Move cursor to previous entry in database
2336        ///
2337        /// Returns `false` if there is no previous entry.
2338        /// Note that in this case it's *not* guaranteed that subsequent
2339        /// accesses to the cursor using `cursor_get_current_` methods return
2340        /// `None`.
2341        fn cursor_set_prev() -> bool;
2342        /// Move cursor to previous entry in database and get pair
2343        fn cursor_set_prev_get_pair() -> (key, value);
2344        /// Move cursor to first value of next key
2345        ///
2346        /// Returns `false` if there is no next key.
2347        /// Note that in this case it's *not* guaranteed that subsequent
2348        /// accesses to the cursor using `cursor_get_current_` methods return
2349        /// `None`.
2350        fn cursor_set_next_key() -> bool;
2351        /// Move cursor to first value of next key and get pair
2352        fn cursor_set_next_key_get_pair() -> (key, value);
2353        /// Move cursor to last value of previous key
2354        ///
2355        /// Returns `false` if there is no previous key.
2356        /// Note that in this case it's *not* guaranteed that subsequent
2357        /// accesses to the cursor using `cursor_get_current_` methods return
2358        /// `None`.
2359        fn cursor_set_prev_key() -> bool;
2360        /// Move cursor to last value of previous key and get pair
2361        fn cursor_set_prev_key_get_pair() -> (key, value);
2362    }
2363    cursor_method_dupkey_defs! {
2364        /// Move cursor to first value of current key
2365        ///
2366        /// Returns `false` if no value has been found.
2367        /// Note that in this case it's *not* guaranteed that subsequent
2368        /// accesses to the cursor using `cursor_get_current_` methods return
2369        /// `None`.
2370        fn cursor_set_first_value() -> bool;
2371        /// Move cursor to first value of current key and get value
2372        fn cursor_set_first_value_get_value() -> value;
2373        /// Move cursor to last value of current key
2374        ///
2375        /// Returns `false` if no value has been found.
2376        /// Note that in this case it's *not* guaranteed that subsequent
2377        /// accesses to the cursor using `cursor_get_current_` methods return
2378        /// `None`.
2379        fn cursor_set_last_value() -> bool;
2380        /// Move cursor to last value of current key and get value
2381        fn cursor_set_last_value_get_value() -> value;
2382        /// Set cursor to key-value pair
2383        ///
2384        /// Returns `false` if not found.
2385        /// Note that in this case it's *not* guaranteed that subsequent
2386        /// accesses to the cursor using `cursor_get_current_` methods return
2387        /// `None`.
2388        fn cursor_set_pair(key, value) -> bool;
2389        /// Set cursor to key and value or next greater value if not existent
2390        ///
2391        /// Returns `false` if no matching value has been found for the given key.
2392        /// Note that in this case it's *not* guaranteed that subsequent
2393        /// accesses to the cursor using `cursor_get_current_` methods return
2394        /// `None`.
2395        fn cursor_set_key_search_value(key, value) -> bool;
2396        /// Set cursor to key and value or next greater value if not existent and get value
2397        fn cursor_set_key_search_value_get_value(key, value) -> value;
2398        /// Move cursor to next value of current key
2399        ///
2400        /// Returns `false` if there is no next value for the current key.
2401        /// Note that in this case it's *not* guaranteed that subsequent
2402        /// accesses to the cursor using `cursor_get_current_` methods return
2403        /// `None`.
2404        fn cursor_set_next_value() -> bool;
2405        /// Move cursor to next value of current key and get value
2406        fn cursor_set_next_value_get_value() -> value;
2407        /// Move cursor to next value of current key
2408        ///
2409        /// Returns `false` if there is no previous value for the current key.
2410        /// Note that in this case it's *not* guaranteed that subsequent
2411        /// accesses to the cursor using `cursor_get_current_` methods return
2412        /// `None`.
2413        fn cursor_set_prev_value() -> bool;
2414        /// Move cursor to next value of current key and get value
2415        fn cursor_set_prev_value_get_value() -> value;
2416    }
2417}
2418
2419/// Helper macro to extract return value for cursor methods
2420macro_rules! cursor_return_value {
2421    (bool, $x:expr $(,)?) => {
2422        match $x {
2423            Some(_) => true,
2424            None => false,
2425        }
2426    };
2427    (key, $x:expr $(,)?) => {
2428        $x.map(|(k, _)| k())
2429    };
2430    (value, $x:expr $(,)?) => {
2431        $x.map(|(_, v)| v())
2432    };
2433    ((key, value), $x:expr $(,)?) => {
2434        $x.map(|(k, v)| (k(), v()))
2435    };
2436}
2437
2438/// Create implementation for cursor method
2439macro_rules! cursor_method_impl {
2440    ($name:ident, (), $retval:tt, $op:ident $(,)?) => {
2441        fn $name<K, V, C>(
2442            &self,
2443            cursor: &Cursor<K, V, C>,
2444        ) -> io::Result<cursor_return_type!($retval)>
2445        where
2446            K: ?Sized + Storable,
2447            V: ?Sized + Storable,
2448            C: Constraint,
2449        {
2450            // SAFETY:
2451            //  *  Neither `TxnRo` nor `TxnRw` is `Sync` and `self.backend` is
2452            //     not accessed by any method calling this method.
2453            //  *  The macro `cursor_return_type!` gives a return type with
2454            //     `'_` as lifetime, which corresponds to the elided lifetime
2455            //     of `&self`. This lifetime cannot live longer than the end of
2456            //     this transaction and ends before any data is modified by the
2457            //     transaction. It is passed to `TxnBackend::cursor_op_unsafe`
2458            //     by inference.
2459            Ok(cursor_return_value!($retval, unsafe {
2460                let backend = &mut *self.backend.get();
2461                backend.cursor_op_unsafe::<K, V, C, &K, &V>(cursor, None, None, lmdb::$op)?
2462            }))
2463        }
2464    };
2465    ($name:ident, (key), $retval:tt, $op:ident) => {
2466        fn $name<'kr, K, V, C, KRef>(
2467            &self,
2468            cursor: &Cursor<K, V, C>,
2469            key: KRef,
2470        ) -> io::Result<cursor_return_type!($retval)>
2471        where
2472            K: ?Sized + Storable + 'kr,
2473            V: ?Sized + Storable,
2474            C: Constraint,
2475            KRef: StorableRef<'kr, K>,
2476        {
2477            // SAFETY: see above
2478            Ok(cursor_return_value!($retval, unsafe {
2479                let backend = &mut *self.backend.get();
2480                backend.cursor_op_unsafe::<K, V, C, KRef, &V>(cursor, Some(key), None, lmdb::$op)?
2481            }))
2482        }
2483    };
2484    ($name:ident, (key, value), $retval:tt, $op:ident) => {
2485        fn $name<'kr, 'vr, K, V, C, KRef, VRef>(
2486            &self,
2487            cursor: &Cursor<K, V, C>,
2488            key: KRef,
2489            value: VRef,
2490        ) -> io::Result<cursor_return_type!($retval)>
2491        where
2492            K: ?Sized + Storable + 'kr,
2493            V: ?Sized + Storable + 'vr,
2494            C: Constraint,
2495            KRef: StorableRef<'kr, K>,
2496            VRef: StorableRef<'vr, V>,
2497        {
2498            // SAFETY: see above
2499            Ok(cursor_return_value!($retval, unsafe {
2500                let backend = &mut *self.backend.get();
2501                backend.cursor_op_unsafe::<K, V, C, KRef, VRef>(
2502                    cursor,
2503                    Some(key),
2504                    Some(value),
2505                    lmdb::$op,
2506                )?
2507            }))
2508        }
2509    };
2510}
2511
2512/// Create implementation for cursor method for databases with duplicate keys
2513macro_rules! cursor_method_dupkey_impl {
2514    ($name:ident, (), $retval:tt, $op:ident $(,)?) => {
2515        fn $name<K, V>(
2516            &self,
2517            cursor: &Cursor<K, V, KeysDuplicate>,
2518        ) -> io::Result<cursor_return_type!($retval)>
2519        where
2520            K: ?Sized + Storable,
2521            V: ?Sized + Storable,
2522        {
2523            // SAFETY: see `cursor_method_impl!`
2524            Ok(cursor_return_value!($retval, unsafe {
2525                let backend = &mut *self.backend.get();
2526                backend.cursor_op_unsafe::<K, V, KeysDuplicate, &K, &V>(
2527                    cursor,
2528                    None,
2529                    None,
2530                    lmdb::$op,
2531                )?
2532            }))
2533        }
2534    };
2535    ($name:ident, (key), $retval:tt, $op:ident) => {
2536        fn $name<'kr, K, V, KRef>(
2537            &self,
2538            cursor: &Cursor<K, V, KeysDuplicate>,
2539            key: KRef,
2540        ) -> io::Result<cursor_return_type!($retval)>
2541        where
2542            K: ?Sized + Storable + 'kr,
2543            V: ?Sized + Storable,
2544            KRef: StorableRef<'kr, K>,
2545        {
2546            // SAFETY: see `cursor_method_impl!`
2547            Ok(cursor_return_value!($retval, unsafe {
2548                let backend = &mut *self.backend.get();
2549                backend.cursor_op_unsafe::<K, V, KeysDuplicate, KRef, &V>(
2550                    cursor,
2551                    Some(key),
2552                    None,
2553                    lmdb::$op,
2554                )?
2555            }))
2556        }
2557    };
2558    ($name:ident, (key, value), $retval:tt, $op:ident) => {
2559        fn $name<'kr, 'vr, K, V, KRef, VRef>(
2560            &self,
2561            cursor: &Cursor<K, V, KeysDuplicate>,
2562            key: KRef,
2563            value: VRef,
2564        ) -> io::Result<cursor_return_type!($retval)>
2565        where
2566            K: ?Sized + Storable + 'kr,
2567            V: ?Sized + Storable + 'vr,
2568            KRef: StorableRef<'kr, K>,
2569            VRef: StorableRef<'vr, V>,
2570        {
2571            // SAFETY: see `cursor_method_impl!`
2572            Ok(cursor_return_value!($retval, unsafe {
2573                let backend = &mut *self.backend.get();
2574                backend.cursor_op_unsafe::<K, V, KeysDuplicate, KRef, VRef>(
2575                    cursor,
2576                    Some(key),
2577                    Some(value),
2578                    lmdb::$op,
2579                )?
2580            }))
2581        }
2582    };
2583}
2584
2585/// Create implementations for all cursor methods
2586macro_rules! cursor_method_impls {
2587    ($macro:ident, $dupkey_macro:ident) => {
2588        $macro!(cursor_set_first, (), bool, MDB_cursor_op_MDB_FIRST);
2589        $macro!(
2590            cursor_set_first_get_pair,
2591            (),
2592            (key, value),
2593            MDB_cursor_op_MDB_FIRST
2594        );
2595        $macro!(cursor_set_last, (), bool, MDB_cursor_op_MDB_LAST);
2596        $macro!(
2597            cursor_set_last_get_pair,
2598            (),
2599            (key, value),
2600            MDB_cursor_op_MDB_LAST
2601        );
2602        $macro!(
2603            cursor_get_current_key,
2604            (),
2605            key,
2606            MDB_cursor_op_MDB_GET_CURRENT
2607        );
2608        $macro!(
2609            cursor_get_current_value,
2610            (),
2611            value,
2612            MDB_cursor_op_MDB_GET_CURRENT
2613        );
2614        $macro!(
2615            cursor_get_current_pair,
2616            (),
2617            (key, value),
2618            MDB_cursor_op_MDB_GET_CURRENT
2619        );
2620        $macro!(cursor_set_key, (key), bool, MDB_cursor_op_MDB_SET);
2621        $macro!(
2622            cursor_set_key_get_value,
2623            (key),
2624            value,
2625            MDB_cursor_op_MDB_SET
2626        );
2627        $macro!(cursor_search_key, (key), bool, MDB_cursor_op_MDB_SET_RANGE);
2628        $macro!(
2629            cursor_search_key_get_pair,
2630            (key),
2631            (key, value),
2632            MDB_cursor_op_MDB_SET_RANGE
2633        );
2634        $macro!(cursor_set_next, (), bool, MDB_cursor_op_MDB_NEXT);
2635        $macro!(
2636            cursor_set_next_get_pair,
2637            (),
2638            (key, value),
2639            MDB_cursor_op_MDB_NEXT
2640        );
2641        $macro!(cursor_set_prev, (), bool, MDB_cursor_op_MDB_PREV);
2642        $macro!(
2643            cursor_set_prev_get_pair,
2644            (),
2645            (key, value),
2646            MDB_cursor_op_MDB_PREV
2647        );
2648        $macro!(cursor_set_next_key, (), bool, MDB_cursor_op_MDB_NEXT_NODUP);
2649        $macro!(
2650            cursor_set_next_key_get_pair,
2651            (),
2652            (key, value),
2653            MDB_cursor_op_MDB_NEXT_NODUP
2654        );
2655        $macro!(cursor_set_prev_key, (), bool, MDB_cursor_op_MDB_PREV_NODUP);
2656        $macro!(
2657            cursor_set_prev_key_get_pair,
2658            (),
2659            (key, value),
2660            MDB_cursor_op_MDB_PREV_NODUP
2661        );
2662        $dupkey_macro!(
2663            cursor_set_first_value,
2664            (),
2665            bool,
2666            MDB_cursor_op_MDB_FIRST_DUP
2667        );
2668        $dupkey_macro!(
2669            cursor_set_first_value_get_value,
2670            (),
2671            value,
2672            MDB_cursor_op_MDB_FIRST_DUP
2673        );
2674        $dupkey_macro!(cursor_set_last_value, (), bool, MDB_cursor_op_MDB_LAST_DUP);
2675        $dupkey_macro!(
2676            cursor_set_last_value_get_value,
2677            (),
2678            value,
2679            MDB_cursor_op_MDB_LAST_DUP
2680        );
2681        $dupkey_macro!(
2682            cursor_set_pair,
2683            (key, value),
2684            bool,
2685            MDB_cursor_op_MDB_GET_BOTH
2686        );
2687        $dupkey_macro!(
2688            cursor_set_key_search_value,
2689            (key, value),
2690            bool,
2691            MDB_cursor_op_MDB_GET_BOTH_RANGE
2692        );
2693        $dupkey_macro!(
2694            cursor_set_key_search_value_get_value,
2695            (key, value),
2696            value,
2697            MDB_cursor_op_MDB_GET_BOTH_RANGE
2698        );
2699        $dupkey_macro!(cursor_set_next_value, (), bool, MDB_cursor_op_MDB_NEXT_DUP);
2700        $dupkey_macro!(
2701            cursor_set_next_value_get_value,
2702            (),
2703            value,
2704            MDB_cursor_op_MDB_NEXT_DUP
2705        );
2706        $dupkey_macro!(cursor_set_prev_value, (), bool, MDB_cursor_op_MDB_PREV_DUP);
2707        $dupkey_macro!(
2708            cursor_set_prev_value_get_value,
2709            (),
2710            value,
2711            MDB_cursor_op_MDB_PREV_DUP
2712        );
2713    };
2714}
2715
2716impl<'a> Txn for TxnRo<'a> {
2717    fn get<'kr, K, V, C, KRef>(
2718        &self,
2719        db: &Db<K, V, C>,
2720        key: KRef,
2721    ) -> io::Result<Option<V::AlignedRef<'_>>>
2722    where
2723        K: ?Sized + Storable + 'kr,
2724        V: ?Sized + Storable,
2725        C: Constraint,
2726        KRef: StorableRef<'kr, K>,
2727    {
2728        // SAFETY:
2729        //  *  `TxnRo` is `!Sync` and `self.backend` is not accessed by any
2730        //     method calling this method.
2731        //  *  The return type of this function has `'_` as lifetime, which
2732        //     corresponds to the elided lifetime of `&self`. This lifetime
2733        //     cannot live longer than the end of this transaction and ends
2734        //     before any data is modified by the transaction. It is passed
2735        //     to `TxnBackend::get_unsafe` by inference.
2736        unsafe {
2737            let backend = &mut *self.backend.get();
2738            backend.get_unsafe::<K, V, C, KRef>(db, key)
2739        }
2740    }
2741    fn new_cursor<K, V, C>(&self, db: &Db<K, V, C>) -> io::Result<Cursor<K, V, C>>
2742    where
2743        K: ?Sized + Storable,
2744        V: ?Sized + Storable,
2745        C: Constraint,
2746    {
2747        // SAFETY: `TxnRo` is `!Sync` and `self.backend` is not accessed by any
2748        // method calling this method
2749        let backend = unsafe { &mut *self.backend.get() };
2750        backend.new_cursor(db)
2751    }
2752    fn cursor_get_current_value_count<K, V>(
2753        &self,
2754        cursor: &Cursor<K, V, KeysDuplicate>,
2755    ) -> io::Result<usize>
2756    where
2757        K: ?Sized + Storable,
2758        V: ?Sized + Storable,
2759    {
2760        // SAFETY: `TxnRo` is `!Sync` and `self.backend` is not accessed by any
2761        // method calling this method
2762        let backend = unsafe { &mut *self.backend.get() };
2763        backend.cursor_get_current_value_count(cursor)
2764    }
2765    cursor_method_impls!(cursor_method_impl, cursor_method_dupkey_impl);
2766}
2767
2768impl<'a> Txn for TxnRw<'a> {
2769    fn get<'kr, K, V, C, KRef>(
2770        &self,
2771        db: &Db<K, V, C>,
2772        key: KRef,
2773    ) -> io::Result<Option<V::AlignedRef<'_>>>
2774    where
2775        K: ?Sized + Storable + 'kr,
2776        V: ?Sized + Storable,
2777        C: Constraint,
2778        KRef: StorableRef<'kr, K>,
2779    {
2780        // SAFETY:
2781        //  *  `TxnRw` is `!Sync` and `self.backend` is not accessed by any
2782        //     method calling this method.
2783        //  *  The return type of this function has `'_` as lifetime, which
2784        //     corresponds to the elided lifetime of `&self`. This lifetime
2785        //     cannot live longer than the end of this transaction and ends
2786        //     before any data is modified by the transaction. It is passed
2787        //     to `TxnBackend::get_unsafe` by inference.
2788        unsafe {
2789            let backend = &mut *self.backend.get();
2790            backend.get_unsafe::<K, V, C, KRef>(db, key)
2791        }
2792    }
2793    fn new_cursor<K, V, C>(&self, db: &Db<K, V, C>) -> io::Result<Cursor<K, V, C>>
2794    where
2795        K: ?Sized + Storable,
2796        V: ?Sized + Storable,
2797        C: Constraint,
2798    {
2799        // SAFETY: `TxnRw` is `!Sync` and `self.backend` is not accessed by any
2800        // method calling this method
2801        let backend = unsafe { &mut *self.backend.get() };
2802        backend.new_cursor(db)
2803    }
2804    fn cursor_get_current_value_count<K, V>(
2805        &self,
2806        cursor: &Cursor<K, V, KeysDuplicate>,
2807    ) -> io::Result<usize>
2808    where
2809        K: ?Sized + Storable,
2810        V: ?Sized + Storable,
2811    {
2812        // SAFETY: `TxnRw` is `!Sync` and `self.backend` is not accessed by any
2813        // method calling this method
2814        let backend = unsafe { &mut *self.backend.get() };
2815        backend.cursor_get_current_value_count(cursor)
2816    }
2817    cursor_method_impls!(cursor_method_impl, cursor_method_dupkey_impl);
2818}
2819
2820impl<'a> TxnRw<'a> {
2821    /// Add commit handler to be executed on [`TxnRw::commit`] before the
2822    /// transaction is actually committed
2823    pub fn on_commit<F>(&mut self, commit_handler: F)
2824    where
2825        F: FnOnce(&mut Self) -> io::Result<()> + 'a,
2826    {
2827        self.commit_handlers.push(Box::new(commit_handler));
2828    }
2829    /// Commit transaction
2830    ///
2831    /// Previously added commit handlers (see [`TxnRw::on_commit`]) are
2832    /// executed in the same order as they have been added. If one commit
2833    /// handler reports an error, the transaction is aborted.
2834    pub fn commit(mut self) -> io::Result<()> {
2835        for handler in take(&mut self.commit_handlers) {
2836            handler(&mut self)?;
2837        }
2838        self.backend.into_inner().commit()
2839    }
2840    /// Abort transaction (same as [`drop`])
2841    pub fn abort(self) {}
2842    /// Start nested transaction
2843    ///
2844    /// Panics if environment does not support nested transactions (which is
2845    /// the case when the [`EnvBuilder::writemap`] flag has been set).
2846    pub fn nested(&mut self) -> io::Result<TxnRw<'_>> {
2847        let backend = self.backend.get_mut();
2848        assert!(
2849            backend.env_ro.backend.nestable_txns,
2850            "environment does not support nested transactions"
2851        );
2852        let mut txn_inner = MaybeUninit::<*mut lmdb::MDB_txn>::uninit();
2853        // SAFETY:
2854        //  *  A mutable borrow of the parent transaction (`&mut self`) ensures
2855        //     that the parent transaction doesn't issue any operations while
2856        //     the child is active and that as long as the child transaction is
2857        //     active, the same rules apply as if the parent transaction is
2858        //     still open (in particular: no calls to `lmdb::mdb_txn_begin`
2859        //     with parent set to NULL can happen).
2860        //  *  The status passed to `check_err_code` is valid.
2861        unsafe {
2862            check_err_code(lmdb::mdb_txn_begin(
2863                backend.env_ro.backend.inner,
2864                backend.inner,
2865                0,
2866                txn_inner.as_mut_ptr(),
2867            ))?;
2868        }
2869        // SAFETY: call to `lmdb::mdb_txn_begin` above has been successful as
2870        // otherwise `check_err_code` would have returned an `Err` resulting in
2871        // early return from this function
2872        let txn_inner = unsafe { txn_inner.assume_init() };
2873        Ok(TxnRw {
2874            backend: UnsafeCell::new(TxnBackend {
2875                env_ro: &backend.env_ro,
2876                inner: txn_inner,
2877                cursors: Default::default(),
2878            }),
2879            used_dbs: UsedDbs::Nested(&mut self.used_dbs),
2880            commit_handlers: Default::default(),
2881        })
2882    }
2883    /// Implementation for various `put` related methods
2884    ///
2885    /// # Safety
2886    ///
2887    /// Passed `flags` must be valid and correctly chosen for the given `db`.
2888    unsafe fn put_with_flags<'kr, 'vr, K, V, C, KRef, VRef>(
2889        &mut self,
2890        db: &Db<K, V, C>,
2891        key: KRef,
2892        value: VRef,
2893        flags: LmdbFlags,
2894    ) -> io::Result<bool>
2895    where
2896        K: ?Sized + Storable + 'kr,
2897        V: ?Sized + Storable + 'vr,
2898        C: Constraint,
2899        KRef: StorableRef<'kr, K>,
2900        VRef: StorableRef<'vr, V>,
2901    {
2902        let backend = self.backend.get_mut();
2903        db.backend.assert_env_backend(&backend.env_ro.backend);
2904        let key: K::BytesRef<'_> = key.ref_to_bytes();
2905        let value: V::BytesRef<'_> = value.ref_to_bytes();
2906        backend.env_ro.assert_valid_keysize(&key)?;
2907        if C::DUPLICATE_KEYS {
2908            backend.env_ro.assert_valid_valuesize(&value)?;
2909        }
2910        // TODO: use `get_or_insert_owned` if stabilized
2911        //self.used_dbs.get_or_insert_owned(&db.backend);
2912        if !self.used_dbs.contains(&db.backend) {
2913            self.used_dbs.insert(db.backend.to_owned());
2914        }
2915        let lmdb_key = lmdb::MDB_val {
2916            mv_size: key.len(),
2917            mv_data: key.as_ptr() as *mut _,
2918        };
2919        let mut lmdb_data = lmdb::MDB_val {
2920            mv_size: value.len(),
2921            mv_data: value.as_ptr() as *mut _,
2922        };
2923        Ok(
2924            // SAFETY:
2925            //  *  `lmdb_key.mv_data` is a valid pointer to `lmdb_key.mv_size`
2926            //     bytes of memory for reading.
2927            //  *  `lmdb_data.mv_data` is a valid pointer to
2928            //     `lmdb_data.mv_size` bytes of memory for reading and writing
2929            //     (writing is required when some `flags` are set).
2930            //  *  The memory pointed to by `lmdb_data.mv_data` is not read
2931            //     after the transaction ends or modifies data (because it is
2932            //     not read at all).
2933            //  *  Documentation demands that `flags` are valid and correctly
2934            //     chosen for the database.
2935            match unsafe {
2936                lmdb::mdb_put(
2937                    backend.inner,
2938                    db.backend.inner,
2939                    &lmdb_key as *const _ as *mut lmdb::MDB_val,
2940                    &mut lmdb_data,
2941                    flags,
2942                )
2943            } {
2944                lmdb::MDB_KEYEXIST => false,
2945                status => {
2946                    // SAFETY: `status` is a valid LMDB return code, and if
2947                    // negative, it is a valid LMDB error code
2948                    unsafe { check_err_code(status) }?;
2949                    true
2950                }
2951            },
2952        )
2953    }
2954    /// Put value into database
2955    ///
2956    /// This will overwrite an existing value if the database does not use the
2957    /// [`DbBuilder::keys_duplicate`] option.
2958    pub fn put<'kr, 'vr, K, V, C, KRef, VRef>(
2959        &mut self,
2960        db: &Db<K, V, C>,
2961        key: KRef,
2962        value: VRef,
2963    ) -> io::Result<()>
2964    where
2965        K: ?Sized + Storable + 'kr,
2966        V: ?Sized + Storable + 'vr,
2967        C: Constraint,
2968        KRef: StorableRef<'kr, K>,
2969        VRef: StorableRef<'vr, V>,
2970    {
2971        // SAFETY: passing no flags (`0`) is valid for any database
2972        unsafe {
2973            self.put_with_flags(db, key, value, 0)?;
2974        }
2975        Ok(())
2976    }
2977    /// Put value into database unless key exists
2978    ///
2979    /// Returns `Ok(false)` if key exists.
2980    pub fn put_unless_key_exists<'kr, 'vr, K, V, C, KRef, VRef>(
2981        &mut self,
2982        db: &Db<K, V, C>,
2983        key: KRef,
2984        value: VRef,
2985    ) -> io::Result<bool>
2986    where
2987        K: ?Sized + Storable + 'kr,
2988        V: ?Sized + Storable + 'vr,
2989        C: Constraint,
2990        KRef: StorableRef<'kr, K>,
2991        VRef: StorableRef<'vr, V>,
2992    {
2993        // SAFETY: passing `lmdb::MDB_NOOVERWRITE` is valid for any database
2994        unsafe { self.put_with_flags(db, key, value, lmdb::MDB_NOOVERWRITE) }
2995    }
2996    /// Put value into database unless key-value pair exists
2997    ///
2998    /// Returns `Ok(false)` if key-value pair exists.
2999    pub fn put_unless_pair_exists<'kr, 'vr, K, V, KRef, VRef>(
3000        &mut self,
3001        db: &Db<K, V, KeysDuplicate>,
3002        key: KRef,
3003        value: VRef,
3004    ) -> io::Result<bool>
3005    where
3006        K: ?Sized + Storable + 'kr,
3007        V: ?Sized + Storable + 'vr,
3008        KRef: StorableRef<'kr, K>,
3009        VRef: StorableRef<'vr, V>,
3010    {
3011        // SAFETY: passing `lmdb::MDB_NODUPDATA` is valid for databases with
3012        // the `KeysDuplicate` option, which is set for the given `db`
3013        unsafe { self.put_with_flags(db, key, value, lmdb::MDB_NODUPDATA) }
3014    }
3015    /// Delete all values from database that match a given key
3016    pub fn delete_key<'kr, K, V, C, KRef>(
3017        &mut self,
3018        db: &Db<K, V, C>,
3019        key: KRef,
3020    ) -> io::Result<bool>
3021    where
3022        K: ?Sized + Storable + 'kr,
3023        V: ?Sized + Storable,
3024        C: Constraint,
3025        KRef: StorableRef<'kr, K>,
3026    {
3027        let backend = self.backend.get_mut();
3028        db.backend.assert_env_backend(&backend.env_ro.backend);
3029        let key: K::BytesRef<'_> = key.ref_to_bytes();
3030        // TODO: use `get_or_insert_owned` if stabilized
3031        //self.used_dbs.get_or_insert_owned(&db.backend);
3032        if !self.used_dbs.contains(&db.backend) {
3033            self.used_dbs.insert(db.backend.to_owned());
3034        }
3035        let lmdb_key = lmdb::MDB_val {
3036            mv_size: key.len(),
3037            mv_data: key.as_ptr() as *mut _,
3038        };
3039        Ok(
3040            // SAFETY:
3041            //  *  `lmdb_key.mv_data` is a valid pointer to `lmdb_key.mv_size`
3042            //     bytes of memory for reading.
3043            //  *  It is allowed to pass a NULL pointer as last argument.
3044            match unsafe {
3045                lmdb::mdb_del(
3046                    backend.inner,
3047                    db.backend.inner,
3048                    &lmdb_key as *const _ as *mut lmdb::MDB_val,
3049                    null_mut(),
3050                )
3051            } {
3052                lmdb::MDB_NOTFOUND => false,
3053                status => {
3054                    // SAFETY: `status` is a valid LMDB return code, and if
3055                    // negative, it is a valid LMDB error code
3056                    unsafe { check_err_code(status) }?;
3057                    true
3058                }
3059            },
3060        )
3061    }
3062    /// Delete key-value pair from database
3063    pub fn delete_pair<'kr, 'vr, K, V, KRef, VRef>(
3064        &mut self,
3065        db: &Db<K, V, KeysDuplicate>,
3066        key: KRef,
3067        value: VRef,
3068    ) -> io::Result<bool>
3069    where
3070        K: ?Sized + Storable + 'kr,
3071        V: ?Sized + Storable + 'vr,
3072        KRef: StorableRef<'kr, K>,
3073        VRef: StorableRef<'vr, V>,
3074    {
3075        let backend = self.backend.get_mut();
3076        db.backend.assert_env_backend(&backend.env_ro.backend);
3077        let key: K::BytesRef<'_> = key.ref_to_bytes();
3078        let value: V::BytesRef<'_> = value.ref_to_bytes();
3079        // TODO: use `get_or_insert_owned` if stabilized
3080        //self.used_dbs.get_or_insert_owned(&db.backend);
3081        if !self.used_dbs.contains(&db.backend) {
3082            self.used_dbs.insert(db.backend.to_owned());
3083        }
3084        let lmdb_key = lmdb::MDB_val {
3085            mv_size: key.len(),
3086            mv_data: key.as_ptr() as *mut _,
3087        };
3088        let lmdb_value = lmdb::MDB_val {
3089            mv_size: value.len(),
3090            mv_data: value.as_ptr() as *mut _,
3091        };
3092        Ok(
3093            // SAFETY:
3094            //  *  `lmdb_key.mv_data` and `lmdb_data.mv_data` are valid
3095            //     pointers to `lmdb_key.mv_size` and `lmdb_data.mv_size`
3096            //     bytes of memory, respectively, for reading.
3097            match unsafe {
3098                lmdb::mdb_del(
3099                    backend.inner,
3100                    db.backend.inner,
3101                    &lmdb_key as *const _ as *mut lmdb::MDB_val,
3102                    &lmdb_value as *const _ as *mut lmdb::MDB_val,
3103                )
3104            } {
3105                lmdb::MDB_NOTFOUND => false,
3106                status => {
3107                    // SAFETY: `status` is a valid LMDB return code, and if
3108                    // negative, it is a valid LMDB error code
3109                    unsafe { check_err_code(status) }?;
3110                    true
3111                }
3112            },
3113        )
3114    }
3115    /// Delete all entries in a database
3116    ///
3117    /// Use [`EnvRw::drop_db`] to completely drop the database.
3118    pub fn delete_all<K, V, C>(&mut self, db: &Db<K, V, C>) -> io::Result<()>
3119    where
3120        K: ?Sized + Storable,
3121        V: ?Sized + Storable,
3122        C: Constraint,
3123    {
3124        let backend = self.backend.get_mut();
3125        db.backend.assert_env_backend(&backend.env_ro.backend);
3126        // SAFETY:
3127        //  *  Passing zero (`0`) as a last argument to `lmdb::mdb_drop` means
3128        //     the database doesn't get closed but just emptied; thus no
3129        //     special requirements for calling the function exist.
3130        //  *  The status passed to `check_err_code` is valid.
3131        unsafe {
3132            check_err_code(lmdb::mdb_drop(backend.inner, db.backend.inner, 0))?;
3133        }
3134        Ok(())
3135    }
3136    /// Delete key-value pair at current cursor position
3137    pub fn cursor_delete_current<K, V, C>(&mut self, cursor: &Cursor<K, V, C>) -> io::Result<()>
3138    where
3139        K: ?Sized + Storable,
3140        V: ?Sized + Storable,
3141        C: Constraint,
3142    {
3143        // TODO: use `get_or_insert_owned` if stabilized
3144        //self.used_dbs.get_or_insert_owned(&cursor.db.backend);
3145        if !self.used_dbs.contains(&cursor.db.backend) {
3146            self.used_dbs.insert(cursor.db.backend.to_owned());
3147        }
3148        let backend = self.backend.get_mut();
3149        cursor.backend.assert_txn_backend(backend);
3150        // SAFETY:
3151        //  *  Regarding closing the cursor or its transaction, refer to the
3152        //     corresponding other SAFETY comments on closing the cursor
3153        //     and/or the transaction, respectively.
3154        //  *  Passing no flags (`0`) as last argument to
3155        //     `lmdb::mdb_cursor_del`is valid for any database
3156        //  *  The status passed to `check_err_code` is valid.
3157        unsafe { check_err_code(lmdb::mdb_cursor_del(cursor.backend.inner, 0)) }
3158    }
3159    /// Delete all values with same key at current cursor position
3160    pub fn cursor_delete_current_key<K, V>(
3161        &mut self,
3162        cursor: &Cursor<K, V, KeysDuplicate>,
3163    ) -> io::Result<()>
3164    where
3165        K: ?Sized + Storable,
3166        V: ?Sized + Storable,
3167    {
3168        // TODO: use `get_or_insert_owned` if stabilized
3169        //self.used_dbs.get_or_insert_owned(&cursor.db.backend);
3170        if !self.used_dbs.contains(&cursor.db.backend) {
3171            self.used_dbs.insert(cursor.db.backend.to_owned());
3172        }
3173        let backend = self.backend.get_mut();
3174        cursor.backend.assert_txn_backend(backend);
3175        // SAFETY:
3176        //  *  Regarding closing the cursor or its transaction, refer to the
3177        //     corresponding other SAFETY comments on closing the cursor
3178        //     and/or the transaction, respectively.
3179        //  *  Passing `lmdb::MDB_NODUPDATA` is valid for databases with
3180        //     the `KeysDuplicate` option, which is set for the given `cursor`
3181        //     and thus also for the corresponding database.
3182        //  *  The status passed to `check_err_code` is valid.
3183        unsafe {
3184            check_err_code(lmdb::mdb_cursor_del(
3185                cursor.backend.inner,
3186                lmdb::MDB_NODUPDATA as LmdbFlags,
3187            ))
3188        }
3189    }
3190}
3191
3192impl<K, V, C> Cursor<K, V, C> {
3193    /// Associated database
3194    pub fn db(&self) -> &Db<K, V, C> {
3195        &self.db
3196    }
3197}
3198
3199/// Version of underlying LMDB library
3200#[derive(Eq, PartialEq, Clone, Debug)]
3201pub struct LmdbVersion {
3202    /// Descriptive string
3203    pub string: &'static str,
3204    /// Major version number
3205    pub major: i32,
3206    /// Minor version number
3207    pub minor: i32,
3208    /// Patch version number
3209    pub patch: i32,
3210}
3211
3212/// Retrieve version of underlying LMDB library
3213pub fn lmdb_version() -> LmdbVersion {
3214    let mut major: c_int = 0;
3215    let mut minor: c_int = 0;
3216    let mut patch: c_int = 0;
3217    // SAFETY: `lmdb::mdb_version` is expected to return a static C string
3218    // as the API documentation does not put any constraints on the usage of
3219    // the returned string
3220    let string: &CStr = unsafe {
3221        CStr::from_ptr(lmdb::mdb_version(
3222            &mut major as *mut c_int,
3223            &mut minor as *mut c_int,
3224            &mut patch as *mut c_int,
3225        ))
3226    };
3227    LmdbVersion {
3228        string: string.to_str().unwrap(),
3229        major: major.try_into().unwrap(),
3230        minor: minor.try_into().unwrap(),
3231        patch: patch.try_into().unwrap(),
3232    }
3233}