lmdb_rs_m/
core.rs

1//! High level wrapper of LMDB APIs
2//!
3//! Requires knowledge of LMDB terminology
4//!
5//! # Environment
6//!
7//! Environment is actually the center point of LMDB, it's a container
8//! of everything else. As some settings couldn't be adjusted after
9//! opening, `Environment` is constructed using `EnvBuilder`, which
10//! sets up maximum size, maximum count of named databases, maximum
11//! readers which could be used from different threads without locking
12//! and so on.
13//!
14//! # Database
15//!
16//! Actual key-value store. The most crucial aspect is whether a database
17//! allows duplicates or not. It is specified on creation and couldn't be
18//! changed later. Entries for the same key are called `items`.
19//!
20//! There are a couple of optmizations to use, like marking
21//! keys or data as integer, allowing sorting using reverse key, marking
22//! keys/data as fixed size.
23//!
24//! # Transaction
25//!
26//! Absolutely every db operation happens in a transaction. It could
27//! be a read-only transaction (reader), which is lockless and therefore
28//! cheap. Or it could be a read-write transaction, which is unique, i.e.
29//! there could be only one writer at a time.
30//!
31//! While readers are cheap and lockless, they work better being short-lived
32//! as in other case they may lock pages from being reused. Readers have
33//! a special API for marking as finished and renewing.
34//!
35//! It is perfectly fine to create nested transactions.
36//!
37//!
38//! # Example
39//!
40
41#![allow(non_upper_case_globals)]
42
43use libc::{c_int, c_uint, size_t, c_void};
44use std;
45use std::borrow::ToOwned;
46use std::cell::{UnsafeCell};
47use std::cmp::{Ordering};
48use std::collections::HashMap;
49use std::error::Error;
50use std::ffi::{CString};
51use std::path::Path;
52use std::mem;
53use std::ptr;
54use std::result::Result;
55use std::sync::{Arc, Mutex};
56
57use bitflags::bitflags;
58
59use ffi::{self, MDB_val};
60pub use MdbError::{NotFound, KeyExists, Other, StateError, Corrupted, Panic};
61pub use MdbError::{InvalidPath, TxnFull, CursorFull, PageFull, CacheError};
62use crate::traits::{ToMdbValue, FromMdbValue};
63use crate::utils::{error_msg};
64
65
66macro_rules! lift_mdb {
67    ($e:expr) => (lift_mdb!($e, ()));
68    ($e:expr, $r:expr) => (
69        {
70            let t = $e;
71            match t {
72                ffi::MDB_SUCCESS => Ok($r),
73                _ => return Err(MdbError::new_with_code(t))
74            }
75        })
76}
77
78macro_rules! try_mdb {
79        ($e:expr) => (
80        {
81            let t = $e;
82            match t {
83                ffi::MDB_SUCCESS => (),
84                _ => return Err(MdbError::new_with_code(t))
85            }
86        })
87}
88
89macro_rules! assert_state_eq {
90    ($log:ident, $cur:expr, $exp:expr) =>
91        ({
92            let c = $cur;
93            let e = $exp;
94            if c == e {
95                
96            } else {
97                let msg = format!("{} requires {:?}, is in {:?}", stringify!($log), c, e);
98                return Err(StateError(msg))
99            }})
100}
101
102
103
104/// MdbError wraps information about LMDB error
105#[derive(Debug)]
106pub enum MdbError {
107    NotFound,
108    KeyExists,
109    TxnFull,
110    CursorFull,
111    PageFull,
112    Corrupted,
113    Panic,
114    InvalidPath,
115    StateError(String),
116    CacheError,
117    Other(c_int, String)
118}
119
120
121impl MdbError {
122    pub fn new_with_code(code: c_int) -> MdbError {
123        match code {
124            ffi::MDB_NOTFOUND    => NotFound,
125            ffi::MDB_KEYEXIST    => KeyExists,
126            ffi::MDB_TXN_FULL    => TxnFull,
127            ffi::MDB_CURSOR_FULL => CursorFull,
128            ffi::MDB_PAGE_FULL   => PageFull,
129            ffi::MDB_CORRUPTED   => Corrupted,
130            ffi::MDB_PANIC       => Panic,
131            _                    => Other(code, error_msg(code))
132        }
133    }
134}
135
136
137impl std::fmt::Display for MdbError {
138    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
139        match self {
140            &NotFound => write!(fmt, "not found"),
141            &KeyExists => write!(fmt, "key exists"),
142            &TxnFull => write!(fmt, "txn full"),
143            &CursorFull => write!(fmt, "cursor full"),
144            &PageFull => write!(fmt, "page full"),
145            &Corrupted => write!(fmt, "corrupted"),
146            &Panic => write!(fmt, "panic"),
147            &InvalidPath => write!(fmt, "invalid path for database"),
148            &CacheError => write!(fmt, "db cache error"),
149            StateError(msg) => write!(fmt, "{}", msg),
150            &Other(code, ref msg) => write!(fmt, "{}: {}", code, msg)
151        }
152    }
153}
154
155impl Error for MdbError {
156    fn description(&self) -> &'static str {
157        match *self {
158            NotFound => "not found",
159            KeyExists => "key exists",
160            TxnFull => "txn full",
161            CursorFull => "cursor full",
162            PageFull => "page full",
163            Corrupted => "corrupted",
164            Panic => "panic",
165            InvalidPath => "invalid path for database",
166            StateError(_) => "state error",
167            CacheError => "db cache error",
168            Other(_, _) => "other error",
169        }
170    }
171}
172
173
174pub type MdbResult<T> = Result<T, MdbError>;
175
176bitflags! {
177    #[doc = "A set of environment flags which could be changed after opening"]
178    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
179    pub struct EnvFlags: c_uint {
180
181        #[doc="Don't flush system buffers to disk when committing a
182        transaction. This optimization means a system crash can
183        corrupt the database or lose the last transactions if buffers
184        are not yet flushed to disk. The risk is governed by how
185        often the system flushes dirty buffers to disk and how often
186        mdb_env_sync() is called. However, if the filesystem
187        preserves write order and the MDB_WRITEMAP flag is not used,
188        transactions exhibit ACI (atomicity, consistency, isolation)
189        properties and only lose D (durability). I.e. database
190        integrity is maintained, but a system crash may undo the
191        final transactions. Note that (MDB_NOSYNC | MDB_WRITEMAP)
192        leaves the system with no hint for when to write transactions
193        to disk, unless mdb_env_sync() is called. (MDB_MAPASYNC |
194        MDB_WRITEMAP) may be preferable. This flag may be changed at
195        any time using mdb_env_set_flags()."]
196        const EnvNoSync      = ffi::MDB_NOSYNC;
197
198        #[doc="Flush system buffers to disk only once per transaction,
199        omit the metadata flush. Defer that until the system flushes
200        files to disk, or next non-MDB_RDONLY commit or
201        mdb_env_sync(). This optimization maintains database
202        integrity, but a system crash may undo the last committed
203        transaction. I.e. it preserves the ACI (atomicity,
204        consistency, isolation) but not D (durability) database
205        property. This flag may be changed at any time using
206        mdb_env_set_flags()."]
207        const EnvNoMetaSync  = ffi::MDB_NOMETASYNC;
208
209        #[doc="When using MDB_WRITEMAP, use asynchronous flushes to
210        disk. As with MDB_NOSYNC, a system crash can then corrupt the
211        database or lose the last transactions. Calling
212        mdb_env_sync() ensures on-disk database integrity until next
213        commit. This flag may be changed at any time using
214        mdb_env_set_flags()."]
215        const EnvMapAsync    = ffi::MDB_MAPASYNC;
216
217        #[doc="Don't initialize malloc'd memory before writing to
218        unused spaces in the data file. By default, memory for pages
219        written to the data file is obtained using malloc. While
220        these pages may be reused in subsequent transactions, freshly
221        malloc'd pages will be initialized to zeroes before use. This
222        avoids persisting leftover data from other code (that used
223        the heap and subsequently freed the memory) into the data
224        file. Note that many other system libraries may allocate and
225        free memory from the heap for arbitrary uses. E.g., stdio may
226        use the heap for file I/O buffers. This initialization step
227        has a modest performance cost so some applications may want
228        to disable it using this flag. This option can be a problem
229        for applications which handle sensitive data like passwords,
230        and it makes memory checkers like Valgrind noisy. This flag
231        is not needed with MDB_WRITEMAP, which writes directly to the
232        mmap instead of using malloc for pages. The initialization is
233        also skipped if MDB_RESERVE is used; the caller is expected
234        to overwrite all of the memory that was reserved in that
235        case. This flag may be changed at any time using
236        mdb_env_set_flags()."]
237        const EnvNoMemInit   = ffi::MDB_NOMEMINIT;
238    }
239}
240
241bitflags! {
242    #[doc = "A set of all environment flags"]
243    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
244    pub struct EnvCreateFlags: c_uint {
245        #[doc="Use a fixed address for the mmap region. This flag must be"]
246        #[doc=" specified when creating the environment, and is stored persistently"]
247        #[doc=" in the environment. If successful, the memory map will always reside"]
248        #[doc=" at the same virtual address and pointers used to reference data items"]
249        #[doc=" in the database will be constant across multiple invocations. This "]
250        #[doc="option may not always work, depending on how the operating system has"]
251        #[doc=" allocated memory to shared libraries and other uses. The feature is highly experimental."]
252        const EnvCreateFixedMap    = ffi::MDB_FIXEDMAP;
253        #[doc="By default, LMDB creates its environment in a directory whose"]
254        #[doc=" pathname is given in path, and creates its data and lock files"]
255        #[doc=" under that directory. With this option, path is used as-is"]
256        #[doc=" for the database main data file. The database lock file is"]
257        #[doc=" the path with \"-lock\" appended."]
258        const EnvCreateNoSubDir    = ffi::MDB_NOSUBDIR;
259        #[doc="Don't flush system buffers to disk when committing a"]
260        #[doc=" transaction. This optimization means a system crash can corrupt"]
261        #[doc=" the database or lose the last transactions if buffers are not"]
262        #[doc=" yet flushed to disk. The risk is governed by how often the"]
263        #[doc=" system flushes dirty buffers to disk and how often"]
264        #[doc=" mdb_env_sync() is called. However, if the filesystem preserves"]
265        #[doc=" write order and the MDB_WRITEMAP flag is not used, transactions"]
266        #[doc=" exhibit ACI (atomicity, consistency, isolation) properties and"]
267        #[doc=" only lose D (durability). I.e. database integrity is"]
268        #[doc=" maintained, but a system crash may undo the final"]
269        #[doc=" transactions. Note that (MDB_NOSYNC | MDB_WRITEMAP) leaves"]
270        #[doc=" the system with no hint for when to write transactions to"]
271        #[doc=" disk, unless mdb_env_sync() is called."]
272        #[doc=" (MDB_MAPASYNC | MDB_WRITEMAP) may be preferable. This flag"]
273        #[doc=" may be changed at any time using mdb_env_set_flags()."]
274        const EnvCreateNoSync      = ffi::MDB_NOSYNC;
275        #[doc="Open the environment in read-only mode. No write operations"]
276        #[doc=" will be allowed. LMDB will still modify the lock file - except"]
277        #[doc=" on read-only filesystems, where LMDB does not use locks."]
278        const EnvCreateReadOnly    = ffi::MDB_RDONLY;
279        #[doc="Flush system buffers to disk only once per transaction,"]
280        #[doc=" omit the metadata flush. Defer that until the system flushes"]
281        #[doc=" files to disk, or next non-MDB_RDONLY commit or mdb_env_sync()."]
282        #[doc=" This optimization maintains database integrity, but a system"]
283        #[doc=" crash may undo the last committed transaction. I.e. it"]
284        #[doc=" preserves the ACI (atomicity, consistency, isolation) but"]
285        #[doc=" not D (durability) database property. This flag may be changed"]
286        #[doc=" at any time using mdb_env_set_flags()."]
287        const EnvCreateNoMetaSync  = ffi::MDB_NOMETASYNC;
288        #[doc="Use a writeable memory map unless MDB_RDONLY is set. This is"]
289        #[doc="faster and uses fewer mallocs, but loses protection from"]
290        #[doc="application bugs like wild pointer writes and other bad updates"]
291        #[doc="into the database. Incompatible with nested"]
292        #[doc="transactions. Processes with and without MDB_WRITEMAP on the"]
293        #[doc="same environment do not cooperate well."]
294        const EnvCreateWriteMap    = ffi::MDB_WRITEMAP;
295        #[doc="When using MDB_WRITEMAP, use asynchronous flushes to disk. As"]
296        #[doc="with MDB_NOSYNC, a system crash can then corrupt the database or"]
297        #[doc="lose the last transactions. Calling mdb_env_sync() ensures"]
298        #[doc="on-disk database integrity until next commit. This flag may be"]
299        #[doc="changed at any time using mdb_env_set_flags()."]
300        const EnvCreateMapAsync    = ffi::MDB_MAPASYNC;
301        #[doc="Don't use Thread-Local Storage. Tie reader locktable slots to"]
302        #[doc="ffi::MDB_txn objects instead of to threads. I.e. mdb_txn_reset()"]
303        #[doc="keeps the slot reseved for the ffi::MDB_txn object. A thread may"]
304        #[doc="use parallel read-only transactions. A read-only transaction may"]
305        #[doc="span threads if the user synchronizes its use. Applications that"]
306        #[doc="multiplex many user threads over individual OS threads need this"]
307        #[doc="option. Such an application must also serialize the write"]
308        #[doc="transactions in an OS thread, since LMDB's write locking is"]
309        #[doc="unaware of the user threads."]
310        const EnvCreateNoTls       = ffi::MDB_NOTLS;
311        #[doc="Don't do any locking. If concurrent access is anticipated, the"]
312        #[doc="caller must manage all concurrency itself. For proper operation"]
313        #[doc="the caller must enforce single-writer semantics, and must ensure"]
314        #[doc="that no readers are using old transactions while a writer is"]
315        #[doc="active. The simplest approach is to use an exclusive lock so"]
316        #[doc="that no readers may be active at all when a writer begins. "]
317        const EnvCreateNoLock      = ffi::MDB_NOLOCK;
318        #[doc="Turn off readahead. Most operating systems perform readahead on"]
319        #[doc="read requests by default. This option turns it off if the OS"]
320        #[doc="supports it. Turning it off may help random read performance"]
321        #[doc="when the DB is larger than RAM and system RAM is full. The"]
322        #[doc="option is not implemented on Windows."]
323        const EnvCreateNoReadAhead = ffi::MDB_NORDAHEAD;
324        #[doc="Don't initialize malloc'd memory before writing to unused spaces"]
325        #[doc="in the data file. By default, memory for pages written to the"]
326        #[doc="data file is obtained using malloc. While these pages may be"]
327        #[doc="reused in subsequent transactions, freshly malloc'd pages will"]
328        #[doc="be initialized to zeroes before use. This avoids persisting"]
329        #[doc="leftover data from other code (that used the heap and"]
330        #[doc="subsequently freed the memory) into the data file. Note that"]
331        #[doc="many other system libraries may allocate and free memory from"]
332        #[doc="the heap for arbitrary uses. E.g., stdio may use the heap for"]
333        #[doc="file I/O buffers. This initialization step has a modest"]
334        #[doc="performance cost so some applications may want to disable it"]
335        #[doc="using this flag. This option can be a problem for applications"]
336        #[doc="which handle sensitive data like passwords, and it makes memory"]
337        #[doc="checkers like Valgrind noisy. This flag is not needed with"]
338        #[doc="MDB_WRITEMAP, which writes directly to the mmap instead of using"]
339        #[doc="malloc for pages. The initialization is also skipped if"]
340        #[doc="MDB_RESERVE is used; the caller is expected to overwrite all of"]
341        #[doc="the memory that was reserved in that case. This flag may be"]
342        #[doc="changed at any time using mdb_env_set_flags()."]
343        const EnvCreateNoMemInit   = ffi::MDB_NOMEMINIT;
344    }
345}
346
347bitflags! {
348    #[doc = "A set of database flags"]
349    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
350    pub struct DbFlags: c_uint {
351        #[doc="Keys are strings to be compared in reverse order, from the"]
352        #[doc=" end of the strings to the beginning. By default, Keys are"]
353        #[doc=" treated as strings and compared from beginning to end."]
354        const DbReverseKey   = ffi::MDB_REVERSEKEY;
355        #[doc="Duplicate keys may be used in the database. (Or, from another"]
356        #[doc="perspective, keys may have multiple data items, stored in sorted"]
357        #[doc="order.) By default keys must be unique and may have only a"]
358        #[doc="single data item."]
359        const DbAllowDups    = ffi::MDB_DUPSORT;
360        #[doc="Keys are binary integers in native byte order. Setting this"]
361        #[doc="option requires all keys to be the same size, typically"]
362        #[doc="sizeof(int) or sizeof(size_t)."]
363        const DbIntKey       = ffi::MDB_INTEGERKEY;
364        #[doc="This flag may only be used in combination with"]
365        #[doc="ffi::MDB_DUPSORT. This option tells the library that the data"]
366        #[doc="items for this database are all the same size, which allows"]
367        #[doc="further optimizations in storage and retrieval. When all data"]
368        #[doc="items are the same size, the ffi::MDB_GET_MULTIPLE and"]
369        #[doc="ffi::MDB_NEXT_MULTIPLE cursor operations may be used to retrieve"]
370        #[doc="multiple items at once."]
371        const DbDupFixed     = ffi::MDB_DUPFIXED;
372        #[doc="This option specifies that duplicate data items are also"]
373        #[doc="integers, and should be sorted as such."]
374        const DbAllowIntDups = ffi::MDB_INTEGERDUP;
375        #[doc="This option specifies that duplicate data items should be"]
376        #[doc=" compared as strings in reverse order."]
377        const DbReversedDups = ffi::MDB_REVERSEDUP;
378        #[doc="Create the named database if it doesn't exist. This option"]
379        #[doc=" is not allowed in a read-only transaction or a read-only"]
380        #[doc=" environment."]
381        const DbCreate       = ffi::MDB_CREATE;
382    }
383}
384
385/// Database
386#[derive(Debug)]
387pub struct Database<'a> {
388    handle: ffi::MDB_dbi,
389    txn: &'a NativeTransaction<'a>,
390}
391
392// FIXME: provide different interfaces for read-only/read-write databases
393// FIXME: provide different interfaces for simple KV and storage with duplicates
394
395impl<'a> Database<'a> {
396    fn new_with_handle(handle: ffi::MDB_dbi, txn: &'a NativeTransaction<'a>) -> Database<'a> {
397        Database { handle, txn }
398    }
399
400    /// Retrieves current db's statistics.
401    pub fn stat(&'a self) -> MdbResult<ffi::MDB_stat> {
402        self.txn.stat(self.handle)
403    }
404
405    /// Retrieves a value by key. In case of DbAllowDups it will be the first value
406    pub fn get<V: FromMdbValue + 'a>(&'a self, key: &dyn ToMdbValue) -> MdbResult<V> {
407        self.txn.get(self.handle, key)
408    }
409
410    /// Sets value for key. In case of DbAllowDups it will add a new item
411    pub fn set(&self, key: &dyn ToMdbValue, value: &dyn ToMdbValue) -> MdbResult<()> {
412        self.txn.set(self.handle, key, value)
413    }
414
415    /// Appends new key-value pair to database, starting a new page instead of splitting an
416    /// existing one if necessary. Requires that key be >= all existing keys in the database
417    /// (or will return KeyExists error).
418    pub fn append<K: ToMdbValue, V: ToMdbValue>(&self, key: &K, value: &V) -> MdbResult<()> {
419        self.txn.append(self.handle, key, value)
420    }
421
422    /// Appends new value for the given key (requires DbAllowDups), starting a new page instead
423    /// of splitting an existing one if necessary. Requires that value be >= all existing values
424    /// for the given key (or will return KeyExists error).
425    pub fn append_duplicate<K: ToMdbValue, V: ToMdbValue>(&self, key: &K, value: &V) -> MdbResult<()> {
426        self.txn.append_duplicate(self.handle, key, value)
427    }
428
429    /// Set value for key. Fails if key already exists, even when duplicates are allowed.
430    pub fn insert(&self, key: &dyn ToMdbValue, value: &dyn ToMdbValue) -> MdbResult<()> {
431        self.txn.insert(self.handle, key, value)
432    }
433
434    /// Deletes value for key.
435    pub fn del(&self, key: &dyn ToMdbValue) -> MdbResult<()> {
436        self.txn.del(self.handle, key)
437    }
438
439    /// Should be used only with DbAllowDups. Deletes corresponding (key, value)
440    pub fn del_item(&self, key: &dyn ToMdbValue, data: &dyn ToMdbValue) -> MdbResult<()> {
441        self.txn.del_item(self.handle, key, data)
442    }
443
444    /// Returns a new cursor
445    pub fn new_cursor(&'a self) -> MdbResult<Cursor<'a>> {
446        self.txn.new_cursor(self.handle)
447    }
448
449    /// Deletes current db, also moves it out
450    pub fn del_db(self) -> MdbResult<()> {
451        self.txn.del_db(self)
452    }
453
454    /// Removes all key/values from db
455    pub fn clear(&self) -> MdbResult<()> {
456        self.txn.clear_db(self.handle)
457    }
458
459    /// Returns an iterator for all values in database
460    pub fn iter(&'a self) -> MdbResult<CursorIterator<'a, CursorIter>> {
461        self.txn.new_cursor(self.handle).map(|c| CursorIterator::wrap(c, CursorIter))
462    }
463
464    /// Returns an iterator through keys starting with start_key (>=), start_key is included
465    pub fn keyrange_from<'c, K: ToMdbValue + 'c>(&'c self, start_key: &'c K) -> MdbResult<CursorIterator<'c, CursorFromKeyIter<'c>>> {
466        let cursor = self.txn.new_cursor(self.handle)?;
467        let key_range = CursorFromKeyIter::new(start_key);
468        let wrap = CursorIterator::wrap(cursor, key_range);
469        Ok(wrap)
470    }
471
472    /// Returns an iterator through keys less than end_key, end_key is not included
473    pub fn keyrange_to<'c, K: ToMdbValue + 'c>(&'c self, end_key: &'c K) -> MdbResult<CursorIterator<'c, CursorToKeyIter<'c>>> {
474        let cursor = self.txn.new_cursor(self.handle)?;
475        let key_range = CursorToKeyIter::new(end_key);
476        let wrap = CursorIterator::wrap(cursor, key_range);
477        Ok(wrap)
478    }
479
480    /// Returns an iterator through keys `start_key <= x < end_key`. This is, start_key is
481    /// included in the iteration, while end_key is kept excluded.
482    pub fn keyrange_from_to<'c, K: ToMdbValue + 'c>(&'c self, start_key: &'c K, end_key: &'c K)
483                               -> MdbResult<CursorIterator<'c, CursorKeyRangeIter<'c>>>
484    {
485        let cursor = self.txn.new_cursor(self.handle)?;
486        let key_range = CursorKeyRangeIter::new(start_key, end_key, false);
487        let wrap = CursorIterator::wrap(cursor, key_range);
488        Ok(wrap)
489    }
490
491    /// Returns an iterator for values between start_key and end_key (included).
492    /// Currently it works only for unique keys (i.e. it will skip
493    /// multiple items when DB created with ffi::MDB_DUPSORT).
494    /// Iterator is valid while cursor is valid
495    pub fn keyrange<'c, K: ToMdbValue + 'c>(&'c self, start_key: &'c K, end_key: &'c K)
496                               -> MdbResult<CursorIterator<'c, CursorKeyRangeIter<'c>>>
497    {
498        let cursor = self.txn.new_cursor(self.handle)?;
499        let key_range = CursorKeyRangeIter::new(start_key, end_key, true);
500        let wrap = CursorIterator::wrap(cursor, key_range);
501        Ok(wrap)
502    }
503
504    /// Returns an iterator for all items (i.e. values with same key)
505    pub fn item_iter<'c, 'db: 'c, K: ToMdbValue>(&'db self, key: &'c K) -> MdbResult<CursorIterator<'c, CursorItemIter<'c>>> {
506        let cursor = self.txn.new_cursor(self.handle)?;
507        let inner_iter = CursorItemIter::<'c>::new(key);
508        Ok(CursorIterator::<'c>::wrap(cursor, inner_iter))
509    }
510
511    /// Sets the key compare function for this database.
512    ///
513    /// Warning: This function must be called before any data access functions
514    /// are used, otherwise data corruption may occur. The same comparison
515    /// function must be used by every program accessing the database, every
516    /// time the database is used.
517    ///
518    /// If not called, keys are compared lexically, with shorter keys collating
519    /// before longer keys.
520    ///
521    /// Setting lasts for the lifetime of the underlying db handle.
522    pub fn set_compare(&self, cmp_fn: extern "C" fn(*const MDB_val, *const MDB_val) -> c_int) -> MdbResult<()> {
523        lift_mdb!(unsafe {
524            ffi::mdb_set_compare(self.txn.handle, self.handle, cmp_fn)
525        })
526    }
527
528    /// Sets the value comparison function for values of the same key in this database.
529    ///
530    /// Warning: This function must be called before any data access functions
531    /// are used, otherwise data corruption may occur. The same dupsort
532    /// function must be used by every program accessing the database, every
533    /// time the database is used.
534    ///
535    /// If not called, values are compared lexically, with shorter values collating
536    /// before longer values.
537    ///
538    /// Only used when DbAllowDups is true.
539    /// Setting lasts for the lifetime of the underlying db handle.
540    pub fn set_dupsort(&self, cmp_fn: extern "C" fn(*const MDB_val, *const MDB_val) -> c_int) -> MdbResult<()> {
541        lift_mdb!(unsafe {
542            ffi::mdb_set_dupsort(self.txn.handle, self.handle, cmp_fn)
543        })
544    }
545}
546
547
548/// Constructs environment with settigs which couldn't be
549/// changed after opening. By default it tries to create
550/// corresponding dir if it doesn't exist, use `autocreate_dir()`
551/// to override that behavior
552#[derive(Copy, Clone, Debug)]
553pub struct EnvBuilder {
554    flags: EnvCreateFlags,
555    max_readers: Option<usize>,
556    max_dbs: Option<usize>,
557    map_size: Option<u64>,
558    autocreate_dir: bool,
559}
560
561impl Default for EnvBuilder {
562    fn default() -> Self {
563        Self::new()
564    }
565}
566
567impl EnvBuilder {
568    pub fn new() -> EnvBuilder {
569        EnvBuilder {
570            flags: EnvCreateFlags::empty(),
571            max_readers: None,
572            max_dbs: None,
573            map_size: None,
574            autocreate_dir: true,
575        }
576    }
577
578    /// Sets environment flags
579    pub fn flags(mut self, flags: EnvCreateFlags) -> EnvBuilder {
580        self.flags = flags;
581        self
582    }
583
584    /// Sets max concurrent readers operating on environment
585    pub fn max_readers(mut self, max_readers: usize) -> EnvBuilder {
586        self.max_readers = Some(max_readers);
587        self
588    }
589
590    /// Set max number of databases
591    pub fn max_dbs(mut self, max_dbs: usize) -> EnvBuilder {
592        self.max_dbs = Some(max_dbs);
593        self
594    }
595
596    /// Sets max environment size, i.e. size in memory/disk of
597    /// all data
598    pub fn map_size(mut self, map_size: u64) -> EnvBuilder {
599        self.map_size = Some(map_size);
600        self
601    }
602
603    /// Sets whetever `lmdb-rs` should try to autocreate dir with default
604    /// permissions on opening (default is true)
605    pub fn autocreate_dir(mut self, autocreate_dir: bool)  -> EnvBuilder {
606        self.autocreate_dir = autocreate_dir;
607        self
608    }
609
610    /// Opens environment in specified path
611    pub fn open<P: AsRef<Path>>(self, path: P, perms: u32) -> MdbResult<Environment> {
612        let changeable_flags: EnvCreateFlags = EnvCreateFlags::EnvCreateMapAsync | EnvCreateFlags::EnvCreateNoMemInit | EnvCreateFlags::EnvCreateNoSync | EnvCreateFlags::EnvCreateNoMetaSync;
613
614        let env: *mut ffi::MDB_env = ptr::null_mut();
615        unsafe {
616            let p_env: *mut *mut ffi::MDB_env = &env as *const *mut ffi::MDB_env as *mut *mut ffi::MDB_env;
617            try_mdb!(ffi::mdb_env_create(p_env));
618        }
619
620        // Enable only flags which can be changed, otherwise it'll fail
621        try_mdb!(unsafe { ffi::mdb_env_set_flags(env, self.flags.bits() & changeable_flags.bits(), 1)});
622
623        if let Some(map_size) = self.map_size {
624            try_mdb!(unsafe { ffi::mdb_env_set_mapsize(env, map_size as size_t)});
625        }
626
627        if let Some(max_readers) = self.max_readers {
628            try_mdb!(unsafe { ffi::mdb_env_set_maxreaders(env, max_readers as u32)});
629        }
630
631        if let Some(max_dbs) = self.max_dbs {
632            try_mdb!(unsafe { ffi::mdb_env_set_maxdbs(env, max_dbs as u32)});
633        }
634
635        if self.autocreate_dir {
636            EnvBuilder::check_path(&path, self.flags)?;
637        }
638
639        let is_readonly = self.flags.contains(EnvCreateFlags::EnvCreateReadOnly);
640
641        let res = unsafe {
642            // FIXME: revert back once `convert` is stable
643            // let c_path = path.as_os_str().to_cstring().unwrap();
644            let path_str = path.as_ref().to_str().ok_or(MdbError::InvalidPath)?;
645            let c_path = CString::new(path_str).map_err(|_| MdbError::InvalidPath)?;
646
647            ffi::mdb_env_open(env, c_path.as_ref().as_ptr(), self.flags.bits(),
648                              perms as ffi::mdb_mode_t)
649        };
650
651        let _ = self;
652        match res {
653            ffi::MDB_SUCCESS => {
654                Ok(Environment::from_raw(env, is_readonly))
655            },
656            _ => {
657                unsafe { ffi::mdb_env_close(env); }
658                Err(MdbError::new_with_code(res))
659            }
660        }
661
662    }
663
664    fn check_path<P: AsRef<Path>>(path: P, flags: EnvCreateFlags) -> MdbResult<()> {
665        use std::{fs, io};
666
667        if flags.contains(EnvCreateFlags::EnvCreateNoSubDir) {
668            // FIXME: check parent dir existence/absence
669            warn!("checking for path in NoSubDir mode isn't implemented yet");
670            return Ok(());
671        }
672
673        // There should be a directory before open
674        match fs::metadata(&path) {
675            Ok(meta) => {
676                if meta.is_dir() {
677                    Ok(())
678                } else {
679                    Err(MdbError::InvalidPath)
680                }
681            },
682            Err(e) => {
683                if e.kind() == io::ErrorKind::NotFound {
684                    fs::create_dir_all(path.as_ref()).map_err(|e| {
685                        error!("failed to auto create dir: {}", e);
686                        MdbError::InvalidPath
687                    })
688                } else {
689                    Err(MdbError::InvalidPath)
690                }
691            }
692        }
693    }
694}
695
696#[derive(Debug)]
697struct EnvHandle(*mut ffi::MDB_env);
698
699unsafe impl Send for EnvHandle {}
700unsafe impl Sync for EnvHandle {}
701
702impl Drop for EnvHandle {
703    fn drop(&mut self) {
704        unsafe {
705            if !self.0.is_null() {
706                ffi::mdb_env_close(self.0);
707            }
708        }
709    }
710}
711
712/// Represents LMDB Environment. Should be opened using `EnvBuilder`
713#[derive(Debug)]
714pub struct Environment {
715    env: Arc<EnvHandle>,
716    db_cache: Arc<Mutex<UnsafeCell<HashMap<String, ffi::MDB_dbi>>>>,
717    is_readonly: bool, // true if opened in 'read-only' mode
718}
719
720impl Environment {
721    pub fn builder() -> EnvBuilder {
722        EnvBuilder::new()
723    }
724
725    fn from_raw(env: *mut ffi::MDB_env, is_readonly: bool) -> Environment {
726        Environment {
727            env: Arc::new(EnvHandle(env)),
728            db_cache: Arc::new(Mutex::new(UnsafeCell::new(HashMap::new()))),
729            is_readonly,
730        }
731    }
732
733    /// Check for stale entries in the reader lock table.
734    ///
735    /// Returns the number of stale slots that were cleared.
736    pub fn reader_check(&self) -> MdbResult<c_int> {
737        let mut dead: c_int = 0;
738        lift_mdb!(unsafe { ffi::mdb_reader_check(self.env.0, &mut dead as *mut c_int)}, dead)
739    }
740
741    /// Retrieve environment statistics
742    pub fn stat(&self) -> MdbResult<ffi::MDB_stat> {
743        let mut tmp: ffi::MDB_stat = unsafe { std::mem::zeroed() };
744        lift_mdb!(unsafe { ffi::mdb_env_stat(self.env.0, &mut tmp)}, tmp)
745    }
746
747    pub fn info(&self) -> MdbResult<ffi::MDB_envinfo> {
748        let mut tmp: ffi::MDB_envinfo = unsafe { std::mem::zeroed() };
749        lift_mdb!(unsafe { ffi::mdb_env_info(self.env.0, &mut tmp)}, tmp)
750    }
751
752    /// Sync environment to disk
753    pub fn sync(&self, force: bool) -> MdbResult<()> {
754        lift_mdb!(unsafe { ffi::mdb_env_sync(self.env.0, if force {1} else {0})})
755    }
756
757    /// Sets map size.
758    /// This can be called after [open](struct.EnvBuilder.html#method.open) if no transactions are active in this process.
759    pub fn set_mapsize(&self, map_size: usize) -> MdbResult<()> {
760        lift_mdb!(unsafe { ffi::mdb_env_set_mapsize(self.env.0, map_size as size_t)})
761    }
762
763    /// This one sets only flags which are available for change even
764    /// after opening, see also [get_flags](#method.get_flags) and [get_all_flags](#method.get_all_flags)
765    pub fn set_flags(&mut self, flags: EnvFlags, turn_on: bool) -> MdbResult<()> {
766        lift_mdb!(unsafe {
767            ffi::mdb_env_set_flags(self.env.0, flags.bits(), if turn_on {1} else {0})
768        })
769    }
770
771    /// Get flags of environment, which could be changed after it was opened
772    /// use [get_all_flags](#method.get_all_flags) if you need also creation time flags
773    pub fn get_flags(&self) -> MdbResult<EnvFlags> {
774        let tmp = self.get_all_flags()?;
775        Ok(EnvFlags::from_bits_truncate(tmp.bits()))
776    }
777
778    /// Get all flags of environment, including which were specified on creation
779    /// See also [get_flags](#method.get_flags) if you're interested only in modifiable flags
780    pub fn get_all_flags(&self) -> MdbResult<EnvCreateFlags> {
781        let mut flags: c_uint = 0;
782        lift_mdb!(unsafe {ffi::mdb_env_get_flags(self.env.0, &mut flags)}, EnvCreateFlags::from_bits_truncate(flags))
783    }
784
785    pub fn get_maxreaders(&self) -> MdbResult<c_uint> {
786        let mut max_readers: c_uint = 0;
787        lift_mdb!(unsafe {
788            ffi::mdb_env_get_maxreaders(self.env.0, &mut max_readers)
789        }, max_readers)
790    }
791
792    pub fn get_maxkeysize(&self) -> c_int {
793        unsafe {ffi::mdb_env_get_maxkeysize(self.env.0)}
794    }
795
796    /// Creates a backup copy in specified file descriptor
797    pub fn copy_to_fd(&self, fd: ffi::mdb_filehandle_t) -> MdbResult<()> {
798        lift_mdb!(unsafe { ffi::mdb_env_copyfd(self.env.0, fd) })
799    }
800
801    /// Gets file descriptor of this environment
802    pub fn get_fd(&self) -> MdbResult<ffi::mdb_filehandle_t> {
803        let mut fd = 0;
804        lift_mdb!({ unsafe { ffi::mdb_env_get_fd(self.env.0, &mut fd) }}, fd)
805    }
806
807    /// Creates a backup copy in specified path
808    // FIXME: check who is responsible for creating path: callee or caller
809    pub fn copy_to_path<P: AsRef<Path>>(&self, path: P) -> MdbResult<()> {
810        // FIXME: revert back once `convert` is stable
811        // let c_path = path.as_os_str().to_cstring().unwrap();
812        let path_str = path.as_ref().to_str().ok_or(MdbError::InvalidPath)?;
813        let c_path = CString::new(path_str).map_err(|_| MdbError::InvalidPath)?;
814
815        unsafe {
816            lift_mdb!(ffi::mdb_env_copy(self.env.0, c_path.as_ref().as_ptr()))
817        }
818    }
819
820    fn create_transaction(&self, parent: Option<NativeTransaction>, flags: c_uint) -> MdbResult<NativeTransaction<'_>> {
821        let mut handle: *mut ffi::MDB_txn = ptr::null_mut();
822        let parent_handle = match parent {
823            Some(t) => t.handle,
824            _ => ptr::null_mut()
825        };
826
827        lift_mdb!(unsafe { ffi::mdb_txn_begin(self.env.0, parent_handle, flags, &mut handle) },
828                 NativeTransaction::new_with_handle(handle, flags as usize, self))
829    }
830
831    /// Creates a new read-write transaction
832    ///
833    /// Use `get_reader` to get much faster lock-free alternative
834    pub fn new_transaction(&self) -> MdbResult<Transaction<'_>> {
835        if self.is_readonly {
836            return Err(MdbError::StateError("Error: creating read-write transaction in read-only environment".to_owned()))
837        }
838        self.create_transaction(None, 0).map(Transaction::new_with_native)
839    }
840
841    /// Creates a readonly transaction
842    pub fn get_reader(&self) -> MdbResult<ReadonlyTransaction<'_>> {
843        self.create_transaction(None, ffi::MDB_RDONLY).map(ReadonlyTransaction::new_with_native)
844    }
845
846    fn _open_db(&self, db_name: & str, flags: DbFlags, force_creation: bool) -> MdbResult<ffi::MDB_dbi> {
847        debug!("Opening {} (create={}, read_only={})", db_name, force_creation, self.is_readonly);
848        // From LMDB docs for mdb_dbi_open:
849        //
850        // This function must not be called from multiple concurrent
851        // transactions. A transaction that uses this function must finish
852        // (either commit or abort) before any other transaction may use
853        // this function
854        match self.db_cache.lock() {
855            Err(_) => Err(MdbError::CacheError),
856            Ok(guard) => {
857                let cell = &(*guard);
858                let cache = cell.get();
859
860                unsafe {
861                    if let Some(db) = (*cache).get(db_name) {
862                        debug!("Cached value for {}: {}", db_name, *db);
863                        return Ok(*db);
864                    }
865                }
866
867                let mut txn = {
868                    let txflags = if self.is_readonly { ffi::MDB_RDONLY } else { 0 };
869                    self.create_transaction(None, txflags)?
870                };
871                let opt_name = if !db_name.is_empty() {Some(db_name)} else {None};
872                let flags = if force_creation {flags | DbFlags::DbCreate} else {flags - DbFlags::DbCreate};
873
874                let mut db: ffi::MDB_dbi = 0;
875                let db_res = match opt_name {
876                    None => unsafe { ffi::mdb_dbi_open(txn.handle, ptr::null(), flags.bits(), &mut db) },
877                    Some(db_name) => {
878                        let db_name = CString::new(db_name.as_bytes()).unwrap();
879                        unsafe {
880                            ffi::mdb_dbi_open(txn.handle, db_name.as_ptr(), flags.bits(), &mut db)
881                        }
882                    }
883                };
884
885                try_mdb!(db_res);
886                txn.commit()?;
887
888                debug!("Caching: {} -> {}", db_name, db);
889                unsafe {
890                    (*cache).insert(db_name.to_owned(), db);
891                };
892
893                Ok(db)
894            }
895        }
896    }
897
898    /// Opens existing DB
899    pub fn get_db(& self, db_name: &str, flags: DbFlags) -> MdbResult<DbHandle> {
900        let db = self._open_db(db_name, flags, false)?;
901        Ok(DbHandle {handle: db, flags})
902    }
903
904    /// Opens or creates a DB
905    pub fn create_db(&self, db_name: &str, flags: DbFlags) -> MdbResult<DbHandle> {
906        let db = self._open_db(db_name, flags, true)?;
907        Ok(DbHandle {handle: db, flags})
908    }
909
910    /// Opens default DB with specified flags
911    pub fn get_default_db(&self, flags: DbFlags) -> MdbResult<DbHandle> {
912        self.get_db("", flags)
913    }
914
915    fn drop_db_from_cache(&self, handle: ffi::MDB_dbi) {
916        match self.db_cache.lock() {
917            Err(_) => (),
918            Ok(guard) => {
919                let cell = &(*guard);
920
921                unsafe {
922                    let cache = cell.get();
923
924                    let mut key = None;
925                    for (k, v) in (*cache).iter() {
926                        if *v == handle {
927                            key = Some(k);
928                            break;
929                        }
930                    }
931
932                    if let Some(key) = key {
933                        (*cache).remove(key);
934                    }
935                }
936            }
937        }
938    }
939}
940
941unsafe impl Sync for Environment {}
942unsafe impl Send for Environment {}
943
944impl Clone for Environment {
945    fn clone(&self) -> Environment {
946        Environment {
947            env: self.env.clone(),
948            db_cache: self.db_cache.clone(),
949            is_readonly: self.is_readonly,
950        }
951    }
952}
953
954#[allow(dead_code)]
955#[derive(Copy, Clone, Debug)]
956/// A handle to a database
957///
958/// It can be cached to avoid opening db on every access
959/// In the current state it is unsafe as other thread
960/// can ask to drop it.
961pub struct DbHandle {
962    handle: ffi::MDB_dbi,
963    flags: DbFlags
964}
965
966unsafe impl Sync for DbHandle {}
967unsafe impl Send for DbHandle {}
968
969#[derive(Copy, PartialEq, Debug, Eq, Clone)]
970enum TransactionState {
971    Normal,   // Normal, any operation possible
972    Released, // Released (reset on readonly), has to be renewed
973    Invalid,  // Invalid, no further operation possible
974}
975
976#[derive(Debug)]
977struct NativeTransaction<'a> {
978    handle: *mut ffi::MDB_txn,
979    env: &'a Environment,
980    flags: usize,
981    state: TransactionState,
982}
983
984impl<'a> NativeTransaction<'a> {
985    fn new_with_handle(h: *mut ffi::MDB_txn, flags: usize, env: &Environment) -> NativeTransaction<'_> {
986        // debug!("new native txn");
987        NativeTransaction {
988            handle: h,
989            flags,
990            state: TransactionState::Normal,
991            env,
992        }
993    }
994
995    fn is_readonly(&self) -> bool {
996        (self.flags as u32 & ffi::MDB_RDONLY) == ffi::MDB_RDONLY
997    }
998
999    fn commit(&mut self) -> MdbResult<()> {
1000        assert_state_eq!(txn, self.state, TransactionState::Normal);
1001        debug!("commit txn");
1002        self.state = if self.is_readonly() {
1003            TransactionState::Released
1004        } else {
1005            TransactionState::Invalid
1006        };
1007        try_mdb!(unsafe { ffi::mdb_txn_commit(self.handle) } );
1008        Ok(())
1009    }
1010
1011    fn abort(&mut self) {
1012        if self.state != TransactionState::Normal {
1013            debug!("Can't abort transaction: current state {:?}", self.state)
1014        } else {
1015            debug!("abort txn");
1016            unsafe { ffi::mdb_txn_abort(self.handle); }
1017            self.state = if self.is_readonly() {
1018                TransactionState::Released
1019            } else {
1020                TransactionState::Invalid
1021            };
1022        }
1023    }
1024
1025    /// Resets read only transaction, handle is kept. Must be followed
1026    /// by a call to `renew`
1027    fn reset(&mut self) {
1028        if self.state != TransactionState::Normal {
1029            debug!("Can't reset transaction: current state {:?}", self.state);
1030        } else {
1031            unsafe { ffi::mdb_txn_reset(self.handle); }
1032            self.state = TransactionState::Released;
1033        }
1034    }
1035
1036    /// Acquires a new reader lock after it was released by reset
1037    fn renew(&mut self) -> MdbResult<()> {
1038        assert_state_eq!(txn, self.state, TransactionState::Released);
1039        try_mdb!(unsafe {ffi::mdb_txn_renew(self.handle)});
1040        self.state = TransactionState::Normal;
1041        Ok(())
1042    }
1043
1044    fn new_child(&self, flags: c_uint) -> MdbResult<NativeTransaction<'_>> {
1045        let mut out: *mut ffi::MDB_txn = ptr::null_mut();
1046        try_mdb!(unsafe { ffi::mdb_txn_begin(ffi::mdb_txn_env(self.handle), self.handle, flags, &mut out) });
1047        Ok(NativeTransaction::new_with_handle(out, flags as usize, self.env))
1048    }
1049
1050    /// Used in Drop to switch state
1051    fn silent_abort(&mut self) {
1052        if self.state == TransactionState::Normal {
1053            debug!("silent abort");
1054            unsafe {ffi::mdb_txn_abort(self.handle);}
1055            self.state = TransactionState::Invalid;
1056        }
1057    }
1058
1059    fn get_value<V: FromMdbValue + 'a>(&'a self, db: ffi::MDB_dbi, key: &dyn ToMdbValue) -> MdbResult<V> {
1060        let mut key_val = key.to_mdb_value();
1061        unsafe {
1062            let mut data_val: MdbValue = std::mem::zeroed();
1063            try_mdb!(ffi::mdb_get(self.handle, db, &mut key_val.value, &mut data_val.value));
1064            Ok(FromMdbValue::from_mdb_value(&data_val))
1065        }
1066    }
1067
1068    fn get<V: FromMdbValue + 'a>(&'a self, db: ffi::MDB_dbi, key: &dyn ToMdbValue) -> MdbResult<V> {
1069        assert_state_eq!(txn, self.state, TransactionState::Normal);
1070        self.get_value(db, key)
1071    }
1072
1073    fn set_value(&self, db: ffi::MDB_dbi, key: &dyn ToMdbValue, value: &dyn ToMdbValue) -> MdbResult<()> {
1074        self.set_value_with_flags(db, key, value, 0)
1075    }
1076
1077    fn set_value_with_flags(&self, db: ffi::MDB_dbi, key: &dyn ToMdbValue, value: &dyn ToMdbValue, flags: c_uint) -> MdbResult<()> {
1078        unsafe {
1079            let mut key_val = key.to_mdb_value();
1080            let mut data_val = value.to_mdb_value();
1081
1082            lift_mdb!(ffi::mdb_put(self.handle, db, &mut key_val.value, &mut data_val.value, flags))
1083        }
1084    }
1085
1086    /// Sets a new value for key, in case of enabled duplicates
1087    /// it actually appends a new value
1088    // FIXME: think about creating explicit separation of
1089    // all traits for databases with dup keys
1090    fn set(&self, db: ffi::MDB_dbi, key: &dyn ToMdbValue, value: &dyn ToMdbValue) -> MdbResult<()> {
1091        assert_state_eq!(txn, self.state, TransactionState::Normal);
1092        self.set_value(db, key, value)
1093    }
1094
1095    fn append(&self, db: ffi::MDB_dbi, key: &dyn ToMdbValue, value: &dyn ToMdbValue) -> MdbResult<()> {
1096        assert_state_eq!(txn, self.state, TransactionState::Normal);
1097        self.set_value_with_flags(db, key, value, ffi::MDB_APPEND)
1098    }
1099
1100    fn append_duplicate(&self, db: ffi::MDB_dbi, key: &dyn ToMdbValue, value: &dyn ToMdbValue) -> MdbResult<()> {
1101        assert_state_eq!(txn, self.state, TransactionState::Normal);
1102        self.set_value_with_flags(db, key, value, ffi::MDB_APPENDDUP)
1103    }
1104
1105    /// Set the value for key only if the key does not exist in the database,
1106    /// even if the database supports duplicates.
1107    fn insert(&self, db: ffi::MDB_dbi, key: &dyn ToMdbValue, value: &dyn ToMdbValue) -> MdbResult<()> {
1108        assert_state_eq!(txn, self.state, TransactionState::Normal);
1109        self.set_value_with_flags(db, key, value, ffi::MDB_NOOVERWRITE)
1110    }
1111
1112    /// Deletes all values by key
1113    fn del_value(&self, db: ffi::MDB_dbi, key: &dyn ToMdbValue) -> MdbResult<()> {
1114        unsafe {
1115            let mut key_val = key.to_mdb_value();
1116            lift_mdb!(ffi::mdb_del(self.handle, db, &mut key_val.value, ptr::null_mut()))
1117        }
1118    }
1119
1120    /// If duplicate keys are allowed deletes value for key which is equal to data
1121    fn del_item(&self, db: ffi::MDB_dbi, key: &dyn ToMdbValue, data: &dyn ToMdbValue) -> MdbResult<()> {
1122        assert_state_eq!(txn, self.state, TransactionState::Normal);
1123        unsafe {
1124            let mut key_val = key.to_mdb_value();
1125            let mut data_val = data.to_mdb_value();
1126
1127            lift_mdb!(ffi::mdb_del(self.handle, db, &mut key_val.value, &mut data_val.value))
1128        }
1129    }
1130
1131    /// Deletes all values for key
1132    fn del(&self, db: ffi::MDB_dbi, key: &dyn ToMdbValue) -> MdbResult<()> {
1133        assert_state_eq!(txn, self.state, TransactionState::Normal);
1134        self.del_value(db, key)
1135    }
1136
1137    /// Creates a new cursor in current transaction tied to db
1138    fn new_cursor(&'a self, db: ffi::MDB_dbi) -> MdbResult<Cursor<'a>> {
1139        Cursor::new(self, db)
1140    }
1141
1142    /// Deletes provided database completely
1143    fn del_db(&self, db: Database) -> MdbResult<()> {
1144        assert_state_eq!(txn, self.state, TransactionState::Normal);
1145        unsafe {
1146            self.env.drop_db_from_cache(db.handle);
1147            lift_mdb!(ffi::mdb_drop(self.handle, db.handle, 1))
1148        }
1149    }
1150
1151    /// Empties provided database
1152    fn clear_db(&self, db: ffi::MDB_dbi) -> MdbResult<()> {
1153        assert_state_eq!(txn, self.state, TransactionState::Normal);
1154        unsafe {
1155            lift_mdb!(ffi::mdb_drop(self.handle, db, 0))
1156        }
1157    }
1158
1159    /// Retrieves provided database's statistics
1160    fn stat(&self, db: ffi::MDB_dbi) -> MdbResult<ffi::MDB_stat> {
1161        let mut tmp: ffi::MDB_stat = unsafe { std::mem::zeroed() };
1162        lift_mdb!(unsafe { ffi::mdb_stat(self.handle, db, &mut tmp)}, tmp)
1163    }
1164
1165    /*
1166    fn get_db(&self, name: &str, flags: DbFlags) -> MdbResult<Database> {
1167        self.env.get_db(name, flags)
1168            .and_then(|db| Ok(Database::new_with_handle(db.handle, self)))
1169    }
1170    */
1171
1172    /*
1173    fn get_or_create_db(&self, name: &str, flags: DbFlags) -> MdbResult<Database> {
1174        self.get_db(name, flags | DbCreate)
1175    }
1176    */
1177}
1178
1179impl Drop for NativeTransaction<'_> {
1180    fn drop(&mut self) {
1181        //debug!("Dropping native transaction!");
1182        self.silent_abort();
1183    }
1184}
1185
1186#[derive(Debug)]
1187pub struct Transaction<'a> {
1188    inner: NativeTransaction<'a>,
1189}
1190
1191impl<'a> Transaction<'a> {
1192    fn new_with_native(txn: NativeTransaction<'a>) -> Transaction<'a> {
1193        Transaction {
1194            inner: txn
1195        }
1196    }
1197
1198    pub fn new_child(&self) -> MdbResult<Transaction<'_>> {
1199        self.inner.new_child(0).map(Transaction::new_with_native)
1200    }
1201
1202    pub fn new_ro_child(&self) -> MdbResult<ReadonlyTransaction<'_>> {
1203        self.inner.new_child(ffi::MDB_RDONLY).map(ReadonlyTransaction::new_with_native)
1204    }
1205
1206    /// Commits transaction, moves it out
1207    pub fn commit(self) -> MdbResult<()> {
1208        //self.inner.commit()
1209        let mut t = self;
1210        t.inner.commit()
1211    }
1212
1213    /// Aborts transaction, moves it out
1214    pub fn abort(self) {
1215        let mut t = self;
1216        t.inner.abort();
1217    }
1218
1219    pub fn bind(&self, db_handle: &DbHandle) -> Database<'_> {
1220        Database::new_with_handle(db_handle.handle, &self.inner)
1221    }
1222}
1223
1224
1225#[derive(Debug)]
1226pub struct ReadonlyTransaction<'a> {
1227    inner: NativeTransaction<'a>,
1228}
1229
1230
1231impl<'a> ReadonlyTransaction<'a> {
1232    fn new_with_native(txn: NativeTransaction<'a>) -> ReadonlyTransaction<'a> {
1233        ReadonlyTransaction {
1234            inner: txn,
1235        }
1236    }
1237
1238    pub fn new_ro_child(&self) -> MdbResult<ReadonlyTransaction<'_>> {
1239        self.inner.new_child(ffi::MDB_RDONLY).map(ReadonlyTransaction::new_with_native)
1240
1241    }
1242
1243    /// Aborts transaction. But readonly transaction could be
1244    /// reused later by calling `renew`
1245    pub fn abort(&mut self) {
1246        self.inner.abort();
1247    }
1248
1249    /// Resets read only transaction, handle is kept. Must be followed
1250    /// by call to `renew`
1251    pub fn reset(&mut self) {
1252        self.inner.reset();
1253    }
1254
1255    /// Acquires a new reader lock after transaction
1256    /// `abort` or `reset`
1257    pub fn renew(&mut self) -> MdbResult<()> {
1258        self.inner.renew()
1259    }
1260
1261    pub fn bind(&self, db_handle: &DbHandle) -> Database<'_> {
1262        Database::new_with_handle(db_handle.handle, &self.inner)
1263    }
1264}
1265
1266/// Helper to determine the property of "less than or equal to" where
1267/// the "equal to" part is to be specified at runtime.
1268trait IsLess {
1269    fn is_less(&self, or_equal: bool) -> bool;
1270}
1271
1272impl IsLess for Ordering {
1273    fn is_less(&self, or_equal: bool) -> bool {
1274        matches!((*self, or_equal), (Ordering::Less, _) | (Ordering::Equal, true))
1275    }
1276}
1277
1278impl IsLess for MdbResult<Ordering> {
1279    fn is_less(&self, or_equal: bool) -> bool {
1280        match *self {
1281            Ok(ord) => ord.is_less(or_equal),
1282            Err(_) => false,
1283        }
1284    }
1285}
1286
1287#[derive(Debug)]
1288pub struct Cursor<'txn> {
1289    handle: *mut ffi::MDB_cursor,
1290    data_val: ffi::MDB_val,
1291    key_val: ffi::MDB_val,
1292    txn: &'txn NativeTransaction<'txn>,
1293    db: ffi::MDB_dbi,
1294    valid_key: bool,
1295}
1296
1297
1298impl<'txn> Cursor<'txn> {
1299    fn new(txn: &'txn NativeTransaction, db: ffi::MDB_dbi) -> MdbResult<Cursor<'txn>> {
1300        debug!("Opening cursor in {}", db);
1301        let mut tmp: *mut ffi::MDB_cursor = std::ptr::null_mut();
1302        try_mdb!(unsafe { ffi::mdb_cursor_open(txn.handle, db, &mut tmp) });
1303        Ok(Cursor {
1304            handle: tmp,
1305            data_val: unsafe { std::mem::zeroed() },
1306            key_val: unsafe { std::mem::zeroed() },
1307            txn,
1308            db,
1309            valid_key: false,
1310        })
1311    }
1312
1313    fn navigate(&mut self, op: ffi::MDB_cursor_op) -> MdbResult<()> {
1314        self.valid_key = false;
1315
1316        let res = unsafe {
1317            ffi::mdb_cursor_get(self.handle, &mut self.key_val, &mut self.data_val, op)
1318        };
1319        match res {
1320            ffi::MDB_SUCCESS => {
1321                // MDB_SET is the only cursor operation which doesn't
1322                // writes back a new value. In this case any access to
1323                // cursor key value should cause a cursor retrieval
1324                // to get back pointer to database owned memory instead
1325                // of value used to set the cursor as it might be
1326                // already destroyed and there is no need to borrow it
1327                self.valid_key = op != ffi::MDB_cursor_op::MDB_SET;
1328                Ok(())
1329            },
1330            e => Err(MdbError::new_with_code(e))
1331        }
1332    }
1333
1334    fn move_to<K, V>(&mut self, key: &K, value: Option<&V>, op: ffi::MDB_cursor_op) -> MdbResult<()>
1335        where K: ToMdbValue, V: ToMdbValue {
1336        self.key_val = key.to_mdb_value().value;
1337        self.data_val = match value {
1338            Some(v) => v.to_mdb_value().value,
1339            _ => unsafe {std::mem::zeroed() }
1340        };
1341
1342        self.navigate(op)
1343    }
1344
1345    /// Moves cursor to first entry
1346    pub fn to_first(&mut self) -> MdbResult<()> {
1347        self.navigate(ffi::MDB_cursor_op::MDB_FIRST)
1348    }
1349
1350    /// Moves cursor to last entry
1351    pub fn to_last(&mut self) -> MdbResult<()> {
1352        self.navigate(ffi::MDB_cursor_op::MDB_LAST)
1353    }
1354
1355    /// Moves cursor to first entry for key if it exists
1356    pub fn to_key<'k, K: ToMdbValue>(&mut self, key: &'k K) -> MdbResult<()> {
1357        self.move_to(key, None::<&MdbValue<'k>>, ffi::MDB_cursor_op::MDB_SET_KEY)
1358    }
1359
1360    /// Moves cursor to first entry for key greater than
1361    /// or equal to ke
1362    pub fn to_gte_key<'k, K: ToMdbValue>(&mut self, key: &'k K) -> MdbResult<()> {
1363        self.move_to(key, None::<&MdbValue<'k>>, ffi::MDB_cursor_op::MDB_SET_RANGE)
1364    }
1365
1366    /// Moves cursor to specific item (for example, if cursor
1367    /// already points to a correct key and you need to delete
1368    /// a specific item through cursor)
1369    pub fn to_item<K, V>(&mut self, key: &K, value: & V) -> MdbResult<()> where K: ToMdbValue, V: ToMdbValue {
1370        self.move_to(key, Some(value), ffi::MDB_cursor_op::MDB_GET_BOTH)
1371    }
1372
1373    /// Moves cursor to nearest item.
1374    pub fn to_gte_item<K, V>(&mut self, key: &K, value: & V) -> MdbResult<()> where K: ToMdbValue, V: ToMdbValue {
1375        self.move_to(key, Some(value), ffi::MDB_cursor_op::MDB_GET_BOTH_RANGE)
1376    }
1377
1378    /// Moves cursor to next key, i.e. skip items
1379    /// with duplicate keys
1380    pub fn to_next_key(&mut self) -> MdbResult<()> {
1381        self.navigate(ffi::MDB_cursor_op::MDB_NEXT_NODUP)
1382    }
1383
1384    /// Moves cursor to next item with the same key as current
1385    pub fn to_next_item(&mut self) -> MdbResult<()> {
1386        self.navigate(ffi::MDB_cursor_op::MDB_NEXT_DUP)
1387    }
1388
1389    /// Moves cursor to prev entry, i.e. skips items
1390    /// with duplicate keys
1391    pub fn to_prev_key(&mut self) -> MdbResult<()> {
1392        self.navigate(ffi::MDB_cursor_op::MDB_PREV_NODUP)
1393    }
1394
1395    /// Moves cursor to prev item with the same key as current
1396    pub fn to_prev_item(&mut self) -> MdbResult<()> {
1397        self.navigate(ffi::MDB_cursor_op::MDB_PREV_DUP)
1398    }
1399
1400    /// Moves cursor to first item with the same key as current
1401    pub fn to_first_item(&mut self) -> MdbResult<()> {
1402        self.navigate(ffi::MDB_cursor_op::MDB_FIRST_DUP)
1403    }
1404
1405    /// Moves cursor to last item with the same key as current
1406    pub fn to_last_item(&mut self) -> MdbResult<()> {
1407        self.navigate(ffi::MDB_cursor_op::MDB_LAST_DUP)
1408    }
1409
1410    /// Retrieves current key/value as tuple
1411    pub fn get<'a, T: FromMdbValue + 'a, U: FromMdbValue + 'a>(&'a mut self) -> MdbResult<(T, U)> {
1412        let (k, v) = self.get_plain()?;
1413
1414        unsafe {
1415            Ok((FromMdbValue::from_mdb_value(mem::transmute::<&MdbValue<'_>, &MdbValue<'_>>(&k)),
1416                FromMdbValue::from_mdb_value(mem::transmute::<&MdbValue<'_>, &MdbValue<'_>>(&v))))
1417        }
1418    }
1419
1420    /// Retrieves current value
1421    pub fn get_value<'a, V: FromMdbValue + 'a>(&'a mut self) -> MdbResult<V> {
1422        let (_, v) = self.get_plain()?;
1423
1424        unsafe {
1425            Ok(FromMdbValue::from_mdb_value(mem::transmute::<&MdbValue<'_>, &MdbValue<'_>>(&v)))
1426        }
1427    }
1428
1429    /// Retrieves current key
1430    pub fn get_key<'a, K: FromMdbValue + 'a>(&'a mut self) -> MdbResult<K> {
1431        let (k, _) = self.get_plain()?;
1432
1433        unsafe {
1434            Ok(FromMdbValue::from_mdb_value(mem::transmute::<&MdbValue<'_>, &MdbValue<'_>>(&k)))
1435        }
1436    }
1437
1438    /// Compares the cursor's current key with the specified other one.
1439    #[inline]
1440    fn cmp_key(&mut self, other: &MdbValue) -> MdbResult<Ordering> {
1441        let (k, _) = self.get_plain()?;
1442        let mut kval = k.value;
1443        let cmp = unsafe {
1444            ffi::mdb_cmp(self.txn.handle, self.db, &mut kval, mem::transmute(other))
1445        };
1446        Ok(match cmp {
1447            n if n < 0 => Ordering::Less,
1448            n if n > 0 => Ordering::Greater,
1449            _          => Ordering::Equal,
1450        })
1451    }
1452
1453    #[inline]
1454    fn ensure_key_valid(&mut self) -> MdbResult<()> {
1455        // If key might be invalid simply perform cursor get to be sure
1456        // it points to database memory instead of user one
1457        if !self.valid_key {
1458            unsafe {
1459                try_mdb!(ffi::mdb_cursor_get(self.handle, &mut self.key_val,
1460                                             ptr::null_mut(),
1461                                             ffi::MDB_cursor_op::MDB_GET_CURRENT));
1462            }
1463            self.valid_key = true;
1464        }
1465        Ok(())
1466    }
1467
1468    #[inline]
1469    fn get_plain(&mut self) -> MdbResult<(MdbValue<'txn>, MdbValue<'txn>)> {
1470        self.ensure_key_valid()?;
1471        let k = MdbValue {value: self.key_val, marker: ::std::marker::PhantomData};
1472        let v = MdbValue {value: self.data_val, marker: ::std::marker::PhantomData};
1473
1474        Ok((k, v))
1475    }
1476
1477
1478
1479    fn set_value<V: ToMdbValue>(&mut self, value: &V, flags: c_uint) -> MdbResult<()> {
1480        self.ensure_key_valid()?;
1481        self.data_val = value.to_mdb_value().value;
1482        lift_mdb!(unsafe {ffi::mdb_cursor_put(self.handle, &mut self.key_val, &mut self.data_val, flags)})
1483    }
1484
1485    pub fn set<K: ToMdbValue, V: ToMdbValue>(&mut self, key: &K, value: &V, flags: c_uint) -> MdbResult<()> {
1486        self.key_val = key.to_mdb_value().value;
1487        self.valid_key = true;
1488        let res = self.set_value(value, flags);
1489        self.valid_key = false;
1490        res
1491    }
1492
1493    /// Overwrites value for current item
1494    /// Note: overwrites max cur_value.len() bytes
1495    pub fn replace<V: ToMdbValue>(&mut self, value: &V) -> MdbResult<()> {
1496        let res = self.set_value(value, ffi::MDB_CURRENT);
1497        self.valid_key = false;
1498        res
1499    }
1500
1501    /// Adds a new item when created with allowed duplicates
1502    pub fn add_item<V: ToMdbValue>(&mut self, value: &V) -> MdbResult<()> {
1503        let res = self.set_value(value, 0);
1504        self.valid_key = false;
1505        res
1506    }
1507
1508    fn del_value(&mut self, flags: c_uint) -> MdbResult<()> {
1509        lift_mdb!(unsafe { ffi::mdb_cursor_del(self.handle, flags) })
1510    }
1511
1512    /// Deletes current key
1513    pub fn del(&mut self) -> MdbResult<()> {
1514        self.del_all()
1515    }
1516
1517    /// Deletes only current item
1518    ///
1519    /// Note that it doesn't check anything so it is caller responsibility
1520    /// to make sure that correct item is deleted if, for example, caller
1521    /// wants to delete only items of current key
1522    pub fn del_item(&mut self) -> MdbResult<()> {
1523        let res = self.del_value(0);
1524        self.valid_key = false;
1525        res
1526    }
1527
1528    /// Deletes all items with same key as current
1529    pub fn del_all(&mut self) -> MdbResult<()> {
1530        self.del_value(ffi::MDB_NODUPDATA)
1531    }
1532
1533    /// Returns count of items with the same key as current
1534    pub fn item_count(&self) -> MdbResult<size_t> {
1535        let mut tmp: size_t = 0;
1536        lift_mdb!(unsafe {ffi::mdb_cursor_count(self.handle, &mut tmp)}, tmp)
1537    }
1538
1539    pub fn get_item<'k, K: ToMdbValue>(self, k: &'k K) -> CursorItemAccessor<'txn, 'k, K> {
1540        CursorItemAccessor {
1541            cursor: self,
1542            key: k
1543        }
1544    }
1545}
1546
1547impl Drop for Cursor<'_> {
1548    fn drop(&mut self) {
1549        unsafe { ffi::mdb_cursor_close(self.handle) };
1550    }
1551}
1552
1553#[derive(Debug)]
1554pub struct CursorItemAccessor<'c, 'k, K: 'k> {
1555    cursor: Cursor<'c>,
1556    key: &'k K,
1557}
1558
1559impl<'k, 'c: 'k, K: ToMdbValue> CursorItemAccessor<'c, 'k, K> {
1560    pub fn get<'a, V: FromMdbValue + 'a>(&'a mut self) -> MdbResult<V> {
1561        self.cursor.to_key(self.key)?;
1562        self.cursor.get_value()
1563    }
1564
1565    pub fn add<V: ToMdbValue>(&mut self, v: &V) -> MdbResult<()> {
1566        self.cursor.set(self.key, v, 0)
1567    }
1568
1569    pub fn del<V: ToMdbValue>(&mut self, v: &V) -> MdbResult<()> {
1570        self.cursor.to_item(self.key, v)?;
1571        self.cursor.del_item()
1572    }
1573
1574    pub fn del_all(&mut self) -> MdbResult<()> {
1575        self.cursor.to_key(self.key)?;
1576        self.cursor.del_all()
1577    }
1578
1579    pub fn into_inner(self) -> Cursor<'c> {
1580        let tmp = self;
1581        tmp.cursor
1582    }
1583}
1584
1585
1586#[derive(Debug)]
1587pub struct CursorValue<'cursor> {
1588    key: MdbValue<'cursor>,
1589    value: MdbValue<'cursor>,
1590    marker: ::std::marker::PhantomData<&'cursor ()>,
1591}
1592
1593/// CursorValue performs lazy data extraction from iterator
1594/// avoiding any data conversions and memory copy. Lifetime
1595/// is limited to iterator lifetime
1596impl<'cursor> CursorValue<'cursor> {
1597    pub fn get_key<T: FromMdbValue + 'cursor>(&'cursor self) -> T {
1598        FromMdbValue::from_mdb_value(&self.key)
1599    }
1600
1601    pub fn get_value<T: FromMdbValue + 'cursor>(&'cursor self) -> T {
1602        FromMdbValue::from_mdb_value(&self.value)
1603    }
1604
1605    pub fn get<T: FromMdbValue + 'cursor, U: FromMdbValue + 'cursor>(&'cursor self) -> (T, U) {
1606        (FromMdbValue::from_mdb_value(&self.key),
1607         FromMdbValue::from_mdb_value(&self.value))
1608    }
1609}
1610
1611/// Allows the cration of custom cursor iteration behaviours.
1612pub trait IterateCursor {
1613    /// Returns true if initialization successful, for example that
1614    /// the key exists.
1615    fn init_cursor<'a, 'b: 'a>(&'a self, cursor: &mut Cursor<'b>) -> bool;
1616
1617    /// Returns true if there is still data and iterator is in correct range
1618    fn move_to_next<'iter, 'cursor: 'iter>(&'iter self, cursor: &'cursor mut Cursor<'cursor>) -> bool;
1619
1620    /// Returns size hint considering current state of cursor
1621    fn get_size_hint(&self, _cursor: &Cursor) -> (usize, Option<usize>) {
1622        (0, None)
1623    }
1624}
1625
1626
1627#[derive(Debug)]
1628pub struct CursorIterator<'c, I> {
1629    inner: I,
1630    has_data: bool,
1631    cursor: Cursor<'c>,
1632    marker: ::std::marker::PhantomData<&'c ()>,
1633}
1634
1635impl<'c, I: IterateCursor + 'c> CursorIterator<'c, I> {
1636    fn wrap(cursor: Cursor<'c>, inner: I) -> CursorIterator<'c, I> {
1637        let mut cursor = cursor;
1638        let has_data = inner.init_cursor(&mut cursor);
1639        CursorIterator {
1640            inner,
1641            has_data,
1642            cursor,
1643            marker: ::std::marker::PhantomData,
1644        }
1645    }
1646
1647    #[allow(dead_code)]
1648    fn unwrap(self) -> Cursor<'c> {
1649        self.cursor
1650    }
1651}
1652
1653impl<'c, I: IterateCursor + 'c> Iterator for CursorIterator<'c, I> {
1654    type Item = CursorValue<'c>;
1655
1656    fn next(&mut self) -> Option<CursorValue<'c>> {
1657        if !self.has_data {
1658            None
1659        } else {
1660            match self.cursor.get_plain() {
1661                Err(_) => None,
1662                Ok((k, v)) => {
1663                    self.has_data = unsafe { self.inner.move_to_next(mem::transmute::<&mut Cursor<'_>, &mut Cursor<'_>>(&mut self.cursor)) };
1664                    Some(CursorValue {
1665                        key: k,
1666                        value: v,
1667                        marker: ::std::marker::PhantomData
1668                    })
1669                }
1670            }
1671        }
1672    }
1673
1674    fn size_hint(&self) -> (usize, Option<usize>) {
1675        self.inner.get_size_hint(&self.cursor)
1676    }
1677}
1678
1679#[derive(Debug)]
1680pub struct CursorKeyRangeIter<'a> {
1681    start_key: MdbValue<'a>,
1682    end_key: MdbValue<'a>,
1683    end_inclusive: bool,
1684    marker: ::std::marker::PhantomData<&'a ()>,
1685}
1686
1687impl<'a> CursorKeyRangeIter<'a> {
1688    pub fn new<K: ToMdbValue+'a>(start_key: &'a K, end_key: &'a K, end_inclusive: bool) -> CursorKeyRangeIter<'a> {
1689        CursorKeyRangeIter {
1690            start_key: start_key.to_mdb_value(),
1691            end_key: end_key.to_mdb_value(),
1692            end_inclusive,
1693            marker: ::std::marker::PhantomData,
1694        }
1695    }
1696}
1697
1698impl IterateCursor for CursorKeyRangeIter<'_> {
1699    fn init_cursor<'a, 'b: 'a>(&'a self, cursor: & mut Cursor<'b>) -> bool {
1700        let ok = unsafe {
1701            cursor.to_gte_key(mem::transmute::<&'a MdbValue<'a>, &'b MdbValue<'b>>(&self.start_key)).is_ok()
1702        };
1703        ok && cursor.cmp_key(&self.end_key).is_less(self.end_inclusive)
1704    }
1705
1706    fn move_to_next<'i, 'c: 'i>(&'i self, cursor: &'c mut Cursor<'c>) -> bool {
1707        let moved = cursor.to_next_key().is_ok();
1708        if !moved {
1709            false
1710        } else {
1711            cursor.cmp_key(&self.end_key).is_less(self.end_inclusive)
1712        }
1713    }
1714}
1715
1716#[derive(Debug)]
1717pub struct CursorFromKeyIter<'a> {
1718    start_key: MdbValue<'a>,
1719    marker: ::std::marker::PhantomData<&'a ()>,
1720}
1721
1722
1723impl<'a> CursorFromKeyIter<'a> {
1724    pub fn new<K: ToMdbValue+'a>(start_key: &'a K) -> CursorFromKeyIter<'a> {
1725        CursorFromKeyIter {
1726            start_key: start_key.to_mdb_value(),
1727            marker: ::std::marker::PhantomData
1728        }
1729    }
1730}
1731
1732impl IterateCursor for CursorFromKeyIter<'_> {
1733    fn init_cursor<'a, 'b: 'a>(&'a self, cursor: & mut Cursor<'b>) -> bool {
1734        unsafe {
1735            cursor.to_gte_key(mem::transmute::<&'a MdbValue<'a>, &'b MdbValue<'b>>(&self.start_key)).is_ok()
1736        }
1737    }
1738
1739    fn move_to_next<'i, 'c: 'i>(&'i self, cursor: &'c mut Cursor<'c>) -> bool {
1740        cursor.to_next_key().is_ok()
1741    }
1742}
1743
1744
1745#[derive(Debug)]
1746pub struct CursorToKeyIter<'a> {
1747    end_key: MdbValue<'a>,
1748    marker: ::std::marker::PhantomData<&'a ()>,
1749}
1750
1751
1752impl<'a> CursorToKeyIter<'a> {
1753    pub fn new<K: ToMdbValue+'a>(end_key: &'a K) -> CursorToKeyIter<'a> {
1754        CursorToKeyIter {
1755            end_key: end_key.to_mdb_value(),
1756            marker: ::std::marker::PhantomData,
1757        }
1758    }
1759}
1760
1761impl IterateCursor for CursorToKeyIter<'_> {
1762    fn init_cursor<'a, 'b: 'a>(&'a self, cursor: & mut Cursor<'b>) -> bool {
1763        let ok = cursor.to_first().is_ok();
1764        ok && cursor.cmp_key(&self.end_key).is_less(false)
1765    }
1766
1767    fn move_to_next<'i, 'c: 'i>(&'i self, cursor: &'c mut Cursor<'c>) -> bool {
1768        let moved = cursor.to_next_key().is_ok();
1769        if !moved {
1770            false
1771        } else {
1772            cursor.cmp_key(&self.end_key).is_less(false)
1773        }
1774    }
1775}
1776
1777#[allow(missing_copy_implementations)]
1778#[derive(Debug)]
1779pub struct CursorIter;
1780
1781
1782impl IterateCursor for CursorIter {
1783    fn init_cursor<'a, 'b: 'a>(&'a self, cursor: & mut Cursor<'b>) -> bool {
1784        cursor.to_first().is_ok()
1785    }
1786
1787    fn move_to_next<'i, 'c: 'i>(&'i self, cursor: &'c mut Cursor<'c>) -> bool {
1788        cursor.to_next_key().is_ok()
1789    }
1790}
1791
1792
1793#[derive(Debug)]
1794pub struct CursorItemIter<'a> {
1795    key: MdbValue<'a>,
1796    marker: ::std::marker::PhantomData<&'a ()>,
1797}
1798
1799
1800impl<'a> CursorItemIter<'a> {
1801    pub fn new<K: ToMdbValue+'a>(key: &'a K) -> CursorItemIter<'a> {
1802        CursorItemIter {
1803            key: key.to_mdb_value(),
1804            marker: ::std::marker::PhantomData
1805        }
1806    }
1807}
1808
1809impl IterateCursor for CursorItemIter<'_> {
1810    fn init_cursor<'a, 'b: 'a>(&'a self, cursor: & mut Cursor<'b>) -> bool {
1811        unsafe {
1812            cursor.to_key(mem::transmute::<&MdbValue, &'b MdbValue<'b>>(&self.key)).is_ok()
1813        }
1814    }
1815
1816    fn move_to_next<'i, 'c: 'i>(&'i self, cursor: &'c mut Cursor<'c>) -> bool {
1817        cursor.to_next_item().is_ok()
1818    }
1819
1820    fn get_size_hint(&self, c: &Cursor) -> (usize, Option<usize>) {
1821        match c.item_count() {
1822            Err(_) => (0, None),
1823            Ok(cnt) => (0, Some(cnt))
1824        }
1825    }
1826}
1827
1828
1829#[derive(Copy, Clone, Debug)]
1830pub struct MdbValue<'a> {
1831    value: MDB_val,
1832    marker: ::std::marker::PhantomData<&'a ()>,
1833}
1834
1835impl<'a> MdbValue<'a> {
1836    /// # Safety
1837    /// The caller must ensure that `data` points to valid memory of at least `len` bytes
1838    /// that remains valid for the lifetime 'a.
1839    #[inline]
1840    pub unsafe fn new(data: *const c_void, len: usize) -> MdbValue<'a> {
1841        MdbValue {
1842            value: MDB_val {
1843                mv_data: data,
1844                mv_size: len as size_t
1845            },
1846            marker: ::std::marker::PhantomData
1847        }
1848    }
1849
1850    /// # Safety
1851    /// The caller must ensure that `mdb_val` points to a valid MDB_val structure
1852    /// and that the data it references remains valid for the lifetime 'a.
1853    #[inline]
1854    pub unsafe fn from_raw(mdb_val: *const ffi::MDB_val) -> MdbValue<'a> {
1855        MdbValue::new((*mdb_val).mv_data, (*mdb_val).mv_size)
1856    }
1857
1858    #[inline]
1859    pub fn new_from_sized<T>(data: &'a T) -> MdbValue<'a> {
1860        unsafe {
1861            MdbValue::new(data as *const T as *const c_void, mem::size_of::<T>())
1862        }
1863    }
1864
1865    /// # Safety
1866    /// Returns a raw pointer to the underlying data. The caller must ensure
1867    /// proper lifetime management and not access the pointer after the MdbValue is dropped.
1868    #[inline]
1869    pub unsafe fn get_ref(&'a self) -> *const c_void {
1870        self.value.mv_data
1871    }
1872
1873    #[inline]
1874    pub fn get_size(&self) -> usize {
1875        self.value.mv_size
1876    }
1877}