aingle_lmdb/
cursor.rs

1use std::marker::PhantomData;
2use std::{
3    fmt,
4    mem,
5    ptr,
6    result,
7    slice,
8};
9
10use libc::{
11    c_uint,
12    c_void,
13    size_t,
14    EINVAL,
15};
16
17use crate::database::Database;
18use crate::error::{
19    lmdb_result,
20    Error,
21    Result,
22};
23use crate::ffi;
24use crate::flags::WriteFlags;
25use crate::transaction::Transaction;
26
27/// An LMDB cursor.
28pub trait Cursor<'txn> {
29    /// Returns a raw pointer to the underlying LMDB cursor.
30    ///
31    /// The caller **must** ensure that the pointer is not used after the
32    /// lifetime of the cursor.
33    fn cursor(&self) -> *mut ffi::MDB_cursor;
34
35    /// Retrieves a key/data pair from the cursor. Depending on the cursor op,
36    /// the current key may be returned.
37    fn get(&self, key: Option<&[u8]>, data: Option<&[u8]>, op: c_uint) -> Result<(Option<&'txn [u8]>, &'txn [u8])> {
38        unsafe {
39            let mut key_val = slice_to_val(key);
40            let mut data_val = slice_to_val(data);
41            let key_ptr = key_val.mv_data;
42            lmdb_result(ffi::mdb_cursor_get(self.cursor(), &mut key_val, &mut data_val, op))?;
43            let key_out = if key_ptr != key_val.mv_data {
44                Some(val_to_slice(key_val))
45            } else {
46                None
47            };
48            let data_out = val_to_slice(data_val);
49            Ok((key_out, data_out))
50        }
51    }
52
53    /// Iterate over database items. The iterator will begin with item next
54    /// after the cursor, and continue until the end of the database. For new
55    /// cursors, the iterator will begin with the first item in the database.
56    ///
57    /// For databases with duplicate data items (`DatabaseFlags::DUP_SORT`), the
58    /// duplicate data items of each key will be returned before moving on to
59    /// the next key.
60    fn iter(&mut self) -> Iter<'txn> {
61        Iter::new(self.cursor(), ffi::MDB_NEXT, ffi::MDB_NEXT)
62    }
63
64    /// Iterate over database items starting from the beginning of the database.
65    ///
66    /// For databases with duplicate data items (`DatabaseFlags::DUP_SORT`), the
67    /// duplicate data items of each key will be returned before moving on to
68    /// the next key.
69    fn iter_start(&mut self) -> Iter<'txn> {
70        Iter::new(self.cursor(), ffi::MDB_FIRST, ffi::MDB_NEXT)
71    }
72
73    /// Iterate over database items starting from the beginning of the database.
74    ///
75    /// For databases with duplicate data items (`DatabaseFlags::DUP_SORT`), the
76    /// duplicate data items of each key will be returned before moving on to
77    /// the next key.
78    fn iter_end(&mut self) -> Iter<'txn> {
79        Iter::new(self.cursor(), ffi::MDB_LAST, ffi::MDB_PREV)
80    }
81
82    /// Iterate over database items starting from the given key.
83    ///
84    /// For databases with duplicate data items (`DatabaseFlags::DUP_SORT`), the
85    /// duplicate data items of each key will be returned before moving on to
86    /// the next key.
87    fn iter_from<K>(&mut self, key: K) -> Iter<'txn>
88    where
89        K: AsRef<[u8]>,
90    {
91        match self.get(Some(key.as_ref()), None, ffi::MDB_SET_RANGE) {
92            Ok(_) | Err(Error::NotFound) => (),
93            Err(error) => return Iter::Err(error),
94        };
95        Iter::new(self.cursor(), ffi::MDB_GET_CURRENT, ffi::MDB_NEXT)
96    }
97
98    /// Iterate over duplicate database items. The iterator will begin with the
99    /// item next after the cursor, and continue until the end of the database.
100    /// Each item will be returned as an iterator of its duplicates.
101    fn iter_dup(&mut self) -> IterDup<'txn> {
102        IterDup::new(self.cursor(), ffi::MDB_NEXT)
103    }
104
105    /// Iterate over duplicate database items starting from the beginning of the
106    /// database. Each item will be returned as an iterator of its duplicates.
107    fn iter_dup_start(&mut self) -> IterDup<'txn> {
108        IterDup::new(self.cursor(), ffi::MDB_FIRST)
109    }
110
111    /// Iterate over duplicate items in the database starting from the given
112    /// key. Each item will be returned as an iterator of its duplicates.
113    fn iter_dup_from<K>(&mut self, key: K) -> IterDup<'txn>
114    where
115        K: AsRef<[u8]>,
116    {
117        match self.get(Some(key.as_ref()), None, ffi::MDB_SET_RANGE) {
118            Ok(_) | Err(Error::NotFound) => (),
119            Err(error) => return IterDup::Err(error),
120        };
121        IterDup::new(self.cursor(), ffi::MDB_GET_CURRENT)
122    }
123
124    /// Iterate over the duplicates of the item in the database with the given key.
125    fn iter_dup_of<K>(&mut self, key: K) -> Iter<'txn>
126    where
127        K: AsRef<[u8]>,
128    {
129        match self.get(Some(key.as_ref()), None, ffi::MDB_SET) {
130            Ok(_) => (),
131            Err(Error::NotFound) => {
132                self.get(None, None, ffi::MDB_LAST).ok();
133                return Iter::new(self.cursor(), ffi::MDB_NEXT, ffi::MDB_NEXT);
134            },
135            Err(error) => return Iter::Err(error),
136        };
137        Iter::new(self.cursor(), ffi::MDB_GET_CURRENT, ffi::MDB_NEXT_DUP)
138    }
139}
140
141/// A read-only cursor for navigating the items within a database.
142pub struct RoCursor<'txn> {
143    cursor: *mut ffi::MDB_cursor,
144    _marker: PhantomData<fn() -> &'txn ()>,
145}
146
147impl<'txn> Cursor<'txn> for RoCursor<'txn> {
148    fn cursor(&self) -> *mut ffi::MDB_cursor {
149        self.cursor
150    }
151}
152
153impl<'txn> fmt::Debug for RoCursor<'txn> {
154    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
155        f.debug_struct("RoCursor").finish()
156    }
157}
158
159impl<'txn> Drop for RoCursor<'txn> {
160    fn drop(&mut self) {
161        unsafe { ffi::mdb_cursor_close(self.cursor) }
162    }
163}
164
165impl<'txn> RoCursor<'txn> {
166    /// Creates a new read-only cursor in the given database and transaction.
167    /// Prefer using `Transaction::open_cursor`.
168    pub(crate) fn new<T>(txn: &'txn T, db: Database) -> Result<RoCursor<'txn>>
169    where
170        T: Transaction,
171    {
172        let mut cursor: *mut ffi::MDB_cursor = ptr::null_mut();
173        unsafe {
174            lmdb_result(ffi::mdb_cursor_open(txn.txn(), db.dbi(), &mut cursor))?;
175        }
176        Ok(RoCursor {
177            cursor,
178            _marker: PhantomData,
179        })
180    }
181}
182
183/// A read-write cursor for navigating items within a database.
184pub struct RwCursor<'txn> {
185    cursor: *mut ffi::MDB_cursor,
186    _marker: PhantomData<fn() -> &'txn ()>,
187}
188
189impl<'txn> Cursor<'txn> for RwCursor<'txn> {
190    fn cursor(&self) -> *mut ffi::MDB_cursor {
191        self.cursor
192    }
193}
194
195impl<'txn> fmt::Debug for RwCursor<'txn> {
196    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
197        f.debug_struct("RwCursor").finish()
198    }
199}
200
201impl<'txn> Drop for RwCursor<'txn> {
202    fn drop(&mut self) {
203        unsafe { ffi::mdb_cursor_close(self.cursor) }
204    }
205}
206
207impl<'txn> RwCursor<'txn> {
208    /// Creates a new read-only cursor in the given database and transaction.
209    /// Prefer using `RwTransaction::open_rw_cursor`.
210    pub(crate) fn new<T>(txn: &'txn T, db: Database) -> Result<RwCursor<'txn>>
211    where
212        T: Transaction,
213    {
214        let mut cursor: *mut ffi::MDB_cursor = ptr::null_mut();
215        unsafe {
216            lmdb_result(ffi::mdb_cursor_open(txn.txn(), db.dbi(), &mut cursor))?;
217        }
218        Ok(RwCursor {
219            cursor,
220            _marker: PhantomData,
221        })
222    }
223
224    /// Puts a key/data pair into the database. The cursor will be positioned at
225    /// the new data item, or on failure usually near it.
226    pub fn put<K, D>(&mut self, key: &K, data: &D, flags: WriteFlags) -> Result<()>
227    where
228        K: AsRef<[u8]>,
229        D: AsRef<[u8]>,
230    {
231        let key = key.as_ref();
232        let data = data.as_ref();
233        let mut key_val: ffi::MDB_val = ffi::MDB_val {
234            mv_size: key.len() as size_t,
235            mv_data: key.as_ptr() as *mut c_void,
236        };
237        let mut data_val: ffi::MDB_val = ffi::MDB_val {
238            mv_size: data.len() as size_t,
239            mv_data: data.as_ptr() as *mut c_void,
240        };
241        unsafe { lmdb_result(ffi::mdb_cursor_put(self.cursor(), &mut key_val, &mut data_val, flags.bits())) }
242    }
243
244    /// Deletes the current key/data pair.
245    ///
246    /// ### Flags
247    ///
248    /// `WriteFlags::NO_DUP_DATA` may be used to delete all data items for the
249    /// current key, if the database was opened with `DatabaseFlags::DUP_SORT`.
250    pub fn del(&mut self, flags: WriteFlags) -> Result<()> {
251        unsafe { lmdb_result(ffi::mdb_cursor_del(self.cursor(), flags.bits())) }
252    }
253}
254
255unsafe fn slice_to_val(slice: Option<&[u8]>) -> ffi::MDB_val {
256    match slice {
257        Some(slice) => ffi::MDB_val {
258            mv_size: slice.len() as size_t,
259            mv_data: slice.as_ptr() as *mut c_void,
260        },
261        None => ffi::MDB_val {
262            mv_size: 0,
263            mv_data: ptr::null_mut(),
264        },
265    }
266}
267
268unsafe fn val_to_slice<'a>(val: ffi::MDB_val) -> &'a [u8] {
269    slice::from_raw_parts(val.mv_data as *const u8, val.mv_size as usize)
270}
271
272/// An iterator over the key/value pairs in an LMDB database.
273pub enum Iter<'txn> {
274    /// An iterator that returns an error on every call to Iter.next().
275    /// Cursor.iter*() creates an Iter of this type when LMDB returns an error
276    /// on retrieval of a cursor.  Using this variant instead of returning
277    /// an error makes Cursor.iter()* methods infallible, so consumers only
278    /// need to check the result of Iter.next().
279    Err(Error),
280
281    /// An iterator that returns an Item on calls to Iter.next().
282    /// The Item is a Result<(&'txn [u8], &'txn [u8])>, so this variant
283    /// might still return an error, if retrieval of the key/value pair
284    /// fails for some reason.
285    Ok {
286        /// The LMDB cursor with which to iterate.
287        cursor: *mut ffi::MDB_cursor,
288
289        /// The first operation to perform when the consumer calls Iter.next().
290        op: c_uint,
291
292        /// The next and subsequent operations to perform.
293        next_op: c_uint,
294
295        /// A marker to ensure the iterator doesn't outlive the transaction.
296        _marker: PhantomData<fn(&'txn ())>,
297    },
298}
299
300impl<'txn> Iter<'txn> {
301    /// Creates a new iterator backed by the given cursor.
302    fn new<'t>(cursor: *mut ffi::MDB_cursor, op: c_uint, next_op: c_uint) -> Iter<'t> {
303        Iter::Ok {
304            cursor,
305            op,
306            next_op,
307            _marker: PhantomData,
308        }
309    }
310}
311
312impl<'txn> fmt::Debug for Iter<'txn> {
313    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
314        f.debug_struct("Iter").finish()
315    }
316}
317
318impl<'txn> Iterator for Iter<'txn> {
319    type Item = Result<(&'txn [u8], &'txn [u8])>;
320
321    fn next(&mut self) -> Option<Result<(&'txn [u8], &'txn [u8])>> {
322        match self {
323            &mut Iter::Ok {
324                cursor,
325                ref mut op,
326                next_op,
327                _marker,
328            } => {
329                let mut key = ffi::MDB_val {
330                    mv_size: 0,
331                    mv_data: ptr::null_mut(),
332                };
333                let mut data = ffi::MDB_val {
334                    mv_size: 0,
335                    mv_data: ptr::null_mut(),
336                };
337                let op = mem::replace(op, next_op);
338                unsafe {
339                    match ffi::mdb_cursor_get(cursor, &mut key, &mut data, op) {
340                        ffi::MDB_SUCCESS => Some(Ok((val_to_slice(key), val_to_slice(data)))),
341                        // EINVAL can occur when the cursor was previously seeked to a non-existent value,
342                        // e.g. iter_from with a key greater than all values in the database.
343                        ffi::MDB_NOTFOUND | EINVAL => None,
344                        error => Some(Err(Error::from_err_code(error))),
345                    }
346                }
347            },
348            &mut Iter::Err(err) => Some(Err(err)),
349        }
350    }
351}
352
353/// An iterator over the keys and duplicate values in an LMDB database.
354///
355/// The yielded items of the iterator are themselves iterators over the duplicate values for a
356/// specific key.
357pub enum IterDup<'txn> {
358    /// An iterator that returns an error on every call to Iter.next().
359    /// Cursor.iter*() creates an Iter of this type when LMDB returns an error
360    /// on retrieval of a cursor.  Using this variant instead of returning
361    /// an error makes Cursor.iter()* methods infallible, so consumers only
362    /// need to check the result of Iter.next().
363    Err(Error),
364
365    /// An iterator that returns an Item on calls to Iter.next().
366    /// The Item is a Result<(&'txn [u8], &'txn [u8])>, so this variant
367    /// might still return an error, if retrieval of the key/value pair
368    /// fails for some reason.
369    Ok {
370        /// The LMDB cursor with which to iterate.
371        cursor: *mut ffi::MDB_cursor,
372
373        /// The first operation to perform when the consumer calls Iter.next().
374        op: c_uint,
375
376        /// A marker to ensure the iterator doesn't outlive the transaction.
377        _marker: PhantomData<fn(&'txn ())>,
378    },
379}
380
381impl<'txn> IterDup<'txn> {
382    /// Creates a new iterator backed by the given cursor.
383    fn new<'t>(cursor: *mut ffi::MDB_cursor, op: c_uint) -> IterDup<'t> {
384        IterDup::Ok {
385            cursor,
386            op,
387            _marker: PhantomData,
388        }
389    }
390}
391
392impl<'txn> fmt::Debug for IterDup<'txn> {
393    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
394        f.debug_struct("IterDup").finish()
395    }
396}
397
398impl<'txn> Iterator for IterDup<'txn> {
399    type Item = Iter<'txn>;
400
401    fn next(&mut self) -> Option<Iter<'txn>> {
402        match self {
403            &mut IterDup::Ok {
404                cursor,
405                ref mut op,
406                _marker,
407            } => {
408                let mut key = ffi::MDB_val {
409                    mv_size: 0,
410                    mv_data: ptr::null_mut(),
411                };
412                let mut data = ffi::MDB_val {
413                    mv_size: 0,
414                    mv_data: ptr::null_mut(),
415                };
416                let op = mem::replace(op, ffi::MDB_NEXT_NODUP);
417                let err_code = unsafe { ffi::mdb_cursor_get(cursor, &mut key, &mut data, op) };
418
419                if err_code == ffi::MDB_SUCCESS {
420                    Some(Iter::new(cursor, ffi::MDB_GET_CURRENT, ffi::MDB_NEXT_DUP))
421                } else {
422                    None
423                }
424            },
425            &mut IterDup::Err(err) => Some(Iter::Err(err)),
426        }
427    }
428}
429
430#[cfg(test)]
431mod test {
432
433    use super::*;
434    use crate::environment::*;
435    use crate::ffi::*;
436    use crate::flags::*;
437
438    #[test]
439    fn test_get() {
440        let dir = tempfile::tempdir().unwrap();
441        let env = Environment::new().open(dir.path()).unwrap();
442        let db = env.open_db(None).unwrap();
443
444        let mut txn = env.begin_rw_txn().unwrap();
445        txn.put(db, b"key1", b"val1", WriteFlags::empty()).unwrap();
446        txn.put(db, b"key2", b"val2", WriteFlags::empty()).unwrap();
447        txn.put(db, b"key3", b"val3", WriteFlags::empty()).unwrap();
448
449        let cursor = txn.open_ro_cursor(db).unwrap();
450        assert_eq!((Some(&b"key1"[..]), &b"val1"[..]), cursor.get(None, None, MDB_FIRST).unwrap());
451        assert_eq!((Some(&b"key1"[..]), &b"val1"[..]), cursor.get(None, None, MDB_GET_CURRENT).unwrap());
452        assert_eq!((Some(&b"key2"[..]), &b"val2"[..]), cursor.get(None, None, MDB_NEXT).unwrap());
453        assert_eq!((Some(&b"key1"[..]), &b"val1"[..]), cursor.get(None, None, MDB_PREV).unwrap());
454        assert_eq!((Some(&b"key3"[..]), &b"val3"[..]), cursor.get(None, None, MDB_LAST).unwrap());
455        assert_eq!((None, &b"val2"[..]), cursor.get(Some(b"key2"), None, MDB_SET).unwrap());
456        assert_eq!((Some(&b"key3"[..]), &b"val3"[..]), cursor.get(Some(&b"key3"[..]), None, MDB_SET_KEY).unwrap());
457        assert_eq!((Some(&b"key3"[..]), &b"val3"[..]), cursor.get(Some(&b"key2\0"[..]), None, MDB_SET_RANGE).unwrap());
458    }
459
460    #[test]
461    fn test_get_dup() {
462        let dir = tempfile::tempdir().unwrap();
463        let env = Environment::new().open(dir.path()).unwrap();
464        let db = env.create_db(None, DatabaseFlags::DUP_SORT).unwrap();
465
466        let mut txn = env.begin_rw_txn().unwrap();
467        txn.put(db, b"key1", b"val1", WriteFlags::empty()).unwrap();
468        txn.put(db, b"key1", b"val2", WriteFlags::empty()).unwrap();
469        txn.put(db, b"key1", b"val3", WriteFlags::empty()).unwrap();
470        txn.put(db, b"key2", b"val1", WriteFlags::empty()).unwrap();
471        txn.put(db, b"key2", b"val2", WriteFlags::empty()).unwrap();
472        txn.put(db, b"key2", b"val3", WriteFlags::empty()).unwrap();
473
474        let cursor = txn.open_ro_cursor(db).unwrap();
475        assert_eq!((Some(&b"key1"[..]), &b"val1"[..]), cursor.get(None, None, MDB_FIRST).unwrap());
476        assert_eq!((None, &b"val1"[..]), cursor.get(None, None, MDB_FIRST_DUP).unwrap());
477        assert_eq!((Some(&b"key1"[..]), &b"val1"[..]), cursor.get(None, None, MDB_GET_CURRENT).unwrap());
478        assert_eq!((Some(&b"key2"[..]), &b"val1"[..]), cursor.get(None, None, MDB_NEXT_NODUP).unwrap());
479        assert_eq!((Some(&b"key2"[..]), &b"val2"[..]), cursor.get(None, None, MDB_NEXT_DUP).unwrap());
480        assert_eq!((Some(&b"key2"[..]), &b"val3"[..]), cursor.get(None, None, MDB_NEXT_DUP).unwrap());
481        assert!(cursor.get(None, None, MDB_NEXT_DUP).is_err());
482        assert_eq!((Some(&b"key2"[..]), &b"val2"[..]), cursor.get(None, None, MDB_PREV_DUP).unwrap());
483        assert_eq!((None, &b"val3"[..]), cursor.get(None, None, MDB_LAST_DUP).unwrap());
484        assert_eq!((Some(&b"key1"[..]), &b"val3"[..]), cursor.get(None, None, MDB_PREV_NODUP).unwrap());
485        assert_eq!((None, &b"val1"[..]), cursor.get(Some(&b"key1"[..]), None, MDB_SET).unwrap());
486        assert_eq!((Some(&b"key2"[..]), &b"val1"[..]), cursor.get(Some(&b"key2"[..]), None, MDB_SET_KEY).unwrap());
487        assert_eq!((Some(&b"key2"[..]), &b"val1"[..]), cursor.get(Some(&b"key1\0"[..]), None, MDB_SET_RANGE).unwrap());
488        assert_eq!((None, &b"val3"[..]), cursor.get(Some(&b"key1"[..]), Some(&b"val3"[..]), MDB_GET_BOTH).unwrap());
489        assert_eq!(
490            (None, &b"val1"[..]),
491            cursor.get(Some(&b"key2"[..]), Some(&b"val"[..]), MDB_GET_BOTH_RANGE).unwrap()
492        );
493    }
494
495    #[test]
496    fn test_get_dupfixed() {
497        let dir = tempfile::tempdir().unwrap();
498        let env = Environment::new().open(dir.path()).unwrap();
499        let db = env.create_db(None, DatabaseFlags::DUP_SORT | DatabaseFlags::DUP_FIXED).unwrap();
500
501        let mut txn = env.begin_rw_txn().unwrap();
502        txn.put(db, b"key1", b"val1", WriteFlags::empty()).unwrap();
503        txn.put(db, b"key1", b"val2", WriteFlags::empty()).unwrap();
504        txn.put(db, b"key1", b"val3", WriteFlags::empty()).unwrap();
505        txn.put(db, b"key2", b"val4", WriteFlags::empty()).unwrap();
506        txn.put(db, b"key2", b"val5", WriteFlags::empty()).unwrap();
507        txn.put(db, b"key2", b"val6", WriteFlags::empty()).unwrap();
508
509        let cursor = txn.open_ro_cursor(db).unwrap();
510        assert_eq!((Some(&b"key1"[..]), &b"val1"[..]), cursor.get(None, None, MDB_FIRST).unwrap());
511        assert_eq!((None, &b"val1val2val3"[..]), cursor.get(None, None, MDB_GET_MULTIPLE).unwrap());
512        assert!(cursor.get(None, None, MDB_NEXT_MULTIPLE).is_err());
513    }
514
515    #[test]
516    fn test_iter() {
517        let dir = tempfile::tempdir().unwrap();
518        let env = Environment::new().open(dir.path()).unwrap();
519        let db = env.open_db(None).unwrap();
520
521        let items: Vec<(&[u8], &[u8])> =
522            vec![(b"key1", b"val1"), (b"key2", b"val2"), (b"key3", b"val3"), (b"key5", b"val5")];
523
524        {
525            let mut txn = env.begin_rw_txn().unwrap();
526            for &(ref key, ref data) in &items {
527                txn.put(db, key, data, WriteFlags::empty()).unwrap();
528            }
529            txn.commit().unwrap();
530        }
531
532        let txn = env.begin_ro_txn().unwrap();
533        let mut cursor = txn.open_ro_cursor(db).unwrap();
534
535        // Because Result implements FromIterator, we can collect the iterator
536        // of items of type Result<_, E> into a Result<Vec<_, E>> by specifying
537        // the collection type via the turbofish syntax.
538        assert_eq!(items, cursor.iter().collect::<Result<Vec<_>>>().unwrap());
539
540        // Alternately, we can collect it into an appropriately typed variable.
541        let retr: Result<Vec<_>> = cursor.iter_start().collect();
542        assert_eq!(items, retr.unwrap());
543
544        cursor.get(Some(b"key2"), None, MDB_SET).unwrap();
545        assert_eq!(
546            items.clone().into_iter().skip(2).collect::<Vec<_>>(),
547            cursor.iter().collect::<Result<Vec<_>>>().unwrap()
548        );
549
550        assert_eq!(items, cursor.iter_start().collect::<Result<Vec<_>>>().unwrap());
551
552        assert_eq!(
553            items.clone().into_iter().skip(1).collect::<Vec<_>>(),
554            cursor.iter_from(b"key2").collect::<Result<Vec<_>>>().unwrap()
555        );
556
557        assert_eq!(
558            items.clone().into_iter().skip(3).collect::<Vec<_>>(),
559            cursor.iter_from(b"key4").collect::<Result<Vec<_>>>().unwrap()
560        );
561
562        assert_eq!(
563            vec!().into_iter().collect::<Vec<(&[u8], &[u8])>>(),
564            cursor.iter_from(b"key6").collect::<Result<Vec<_>>>().unwrap()
565        );
566    }
567
568    #[test]
569    fn test_iter_empty_database() {
570        let dir = tempfile::tempdir().unwrap();
571        let env = Environment::new().open(dir.path()).unwrap();
572        let db = env.open_db(None).unwrap();
573        let txn = env.begin_ro_txn().unwrap();
574        let mut cursor = txn.open_ro_cursor(db).unwrap();
575
576        assert_eq!(0, cursor.iter().count());
577        assert_eq!(0, cursor.iter_start().count());
578        assert_eq!(0, cursor.iter_from(b"foo").count());
579    }
580
581    #[test]
582    fn test_iter_empty_dup_database() {
583        let dir = tempfile::tempdir().unwrap();
584        let env = Environment::new().open(dir.path()).unwrap();
585        let db = env.create_db(None, DatabaseFlags::DUP_SORT).unwrap();
586        let txn = env.begin_ro_txn().unwrap();
587        let mut cursor = txn.open_ro_cursor(db).unwrap();
588
589        assert_eq!(0, cursor.iter().count());
590        assert_eq!(0, cursor.iter_start().count());
591        assert_eq!(0, cursor.iter_from(b"foo").count());
592        assert_eq!(0, cursor.iter_dup().count());
593        assert_eq!(0, cursor.iter_dup_start().count());
594        assert_eq!(0, cursor.iter_dup_from(b"foo").count());
595        assert_eq!(0, cursor.iter_dup_of(b"foo").count());
596    }
597
598    #[test]
599    fn test_iter_dup() {
600        let dir = tempfile::tempdir().unwrap();
601        let env = Environment::new().open(dir.path()).unwrap();
602        let db = env.create_db(None, DatabaseFlags::DUP_SORT).unwrap();
603
604        let items: Vec<(&[u8], &[u8])> = vec![
605            (b"a", b"1"),
606            (b"a", b"2"),
607            (b"a", b"3"),
608            (b"b", b"1"),
609            (b"b", b"2"),
610            (b"b", b"3"),
611            (b"c", b"1"),
612            (b"c", b"2"),
613            (b"c", b"3"),
614            (b"e", b"1"),
615            (b"e", b"2"),
616            (b"e", b"3"),
617        ];
618
619        {
620            let mut txn = env.begin_rw_txn().unwrap();
621            for &(ref key, ref data) in &items {
622                txn.put(db, key, data, WriteFlags::empty()).unwrap();
623            }
624            txn.commit().unwrap();
625        }
626
627        let txn = env.begin_ro_txn().unwrap();
628        let mut cursor = txn.open_ro_cursor(db).unwrap();
629        assert_eq!(items, cursor.iter_dup().flatten().collect::<Result<Vec<_>>>().unwrap());
630
631        cursor.get(Some(b"b"), None, MDB_SET).unwrap();
632        assert_eq!(
633            items.clone().into_iter().skip(4).collect::<Vec<(&[u8], &[u8])>>(),
634            cursor.iter_dup().flatten().collect::<Result<Vec<_>>>().unwrap()
635        );
636
637        assert_eq!(items, cursor.iter_dup_start().flatten().collect::<Result<Vec<(&[u8], &[u8])>>>().unwrap());
638
639        assert_eq!(
640            items.clone().into_iter().skip(3).collect::<Vec<(&[u8], &[u8])>>(),
641            cursor.iter_dup_from(b"b").flatten().collect::<Result<Vec<_>>>().unwrap()
642        );
643
644        assert_eq!(
645            items.clone().into_iter().skip(3).collect::<Vec<(&[u8], &[u8])>>(),
646            cursor.iter_dup_from(b"ab").flatten().collect::<Result<Vec<_>>>().unwrap()
647        );
648
649        assert_eq!(
650            items.clone().into_iter().skip(9).collect::<Vec<(&[u8], &[u8])>>(),
651            cursor.iter_dup_from(b"d").flatten().collect::<Result<Vec<_>>>().unwrap()
652        );
653
654        assert_eq!(
655            vec!().into_iter().collect::<Vec<(&[u8], &[u8])>>(),
656            cursor.iter_dup_from(b"f").flatten().collect::<Result<Vec<_>>>().unwrap()
657        );
658
659        assert_eq!(
660            items.clone().into_iter().skip(3).take(3).collect::<Vec<(&[u8], &[u8])>>(),
661            cursor.iter_dup_of(b"b").collect::<Result<Vec<_>>>().unwrap()
662        );
663
664        assert_eq!(0, cursor.iter_dup_of(b"foo").count());
665    }
666
667    #[test]
668    fn test_iter_del_get() {
669        let dir = tempfile::tempdir().unwrap();
670        let env = Environment::new().open(dir.path()).unwrap();
671        let db = env.create_db(None, DatabaseFlags::DUP_SORT).unwrap();
672
673        let items: Vec<(&[u8], &[u8])> = vec![(b"a", b"1"), (b"b", b"2")];
674        let r: Vec<(&[u8], &[u8])> = Vec::new();
675        {
676            let txn = env.begin_ro_txn().unwrap();
677            let mut cursor = txn.open_ro_cursor(db).unwrap();
678            assert_eq!(r, cursor.iter_dup_of(b"a").collect::<Result<Vec<_>>>().unwrap());
679        }
680
681        {
682            let mut txn = env.begin_rw_txn().unwrap();
683            for &(ref key, ref data) in &items {
684                txn.put(db, key, data, WriteFlags::empty()).unwrap();
685            }
686            txn.commit().unwrap();
687        }
688
689        let mut txn = env.begin_rw_txn().unwrap();
690        let mut cursor = txn.open_rw_cursor(db).unwrap();
691        assert_eq!(items, cursor.iter_dup().flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap());
692
693        assert_eq!(
694            items.clone().into_iter().take(1).collect::<Vec<(&[u8], &[u8])>>(),
695            cursor.iter_dup_of(b"a").collect::<Result<Vec<_>>>().unwrap()
696        );
697
698        assert_eq!((None, &b"1"[..]), cursor.get(Some(b"a"), Some(b"1"), MDB_SET).unwrap());
699
700        cursor.del(WriteFlags::empty()).unwrap();
701
702        assert_eq!(r, cursor.iter_dup_of(b"a").collect::<Result<Vec<_>>>().unwrap());
703    }
704
705    #[test]
706    fn test_put_del() {
707        let dir = tempfile::tempdir().unwrap();
708        let env = Environment::new().open(dir.path()).unwrap();
709        let db = env.open_db(None).unwrap();
710
711        let mut txn = env.begin_rw_txn().unwrap();
712        let mut cursor = txn.open_rw_cursor(db).unwrap();
713
714        cursor.put(b"key1", b"val1", WriteFlags::empty()).unwrap();
715        cursor.put(b"key2", b"val2", WriteFlags::empty()).unwrap();
716        cursor.put(b"key3", b"val3", WriteFlags::empty()).unwrap();
717
718        assert_eq!((Some(&b"key3"[..]), &b"val3"[..]), cursor.get(None, None, MDB_GET_CURRENT).unwrap());
719
720        cursor.del(WriteFlags::empty()).unwrap();
721        assert_eq!((Some(&b"key2"[..]), &b"val2"[..]), cursor.get(None, None, MDB_LAST).unwrap());
722    }
723}