reth_libmdbx/
cursor.rs

1use crate::{
2    error::{mdbx_result, Error, Result},
3    flags::*,
4    mdbx_try_optional,
5    transaction::{TransactionKind, RW},
6    TableObject, Transaction,
7};
8use ffi::{
9    MDBX_cursor_op, MDBX_FIRST, MDBX_FIRST_DUP, MDBX_GET_BOTH, MDBX_GET_BOTH_RANGE,
10    MDBX_GET_CURRENT, MDBX_GET_MULTIPLE, MDBX_LAST, MDBX_LAST_DUP, MDBX_NEXT, MDBX_NEXT_DUP,
11    MDBX_NEXT_MULTIPLE, MDBX_NEXT_NODUP, MDBX_PREV, MDBX_PREV_DUP, MDBX_PREV_MULTIPLE,
12    MDBX_PREV_NODUP, MDBX_SET, MDBX_SET_KEY, MDBX_SET_LOWERBOUND, MDBX_SET_RANGE,
13};
14use std::{borrow::Cow, ffi::c_void, fmt, marker::PhantomData, mem, ptr};
15
16/// A cursor for navigating the items within a database.
17pub struct Cursor<K>
18where
19    K: TransactionKind,
20{
21    txn: Transaction<K>,
22    cursor: *mut ffi::MDBX_cursor,
23}
24
25impl<K> Cursor<K>
26where
27    K: TransactionKind,
28{
29    pub(crate) fn new(txn: Transaction<K>, dbi: ffi::MDBX_dbi) -> Result<Self> {
30        let mut cursor: *mut ffi::MDBX_cursor = ptr::null_mut();
31        unsafe {
32            txn.txn_execute(|txn_ptr| {
33                mdbx_result(ffi::mdbx_cursor_open(txn_ptr, dbi, &mut cursor))
34            })??;
35        }
36        Ok(Self { txn, cursor })
37    }
38
39    fn new_at_position(other: &Self) -> Result<Self> {
40        unsafe {
41            let cursor = ffi::mdbx_cursor_create(ptr::null_mut());
42
43            let res = ffi::mdbx_cursor_copy(other.cursor(), cursor);
44
45            let s = Self { txn: other.txn.clone(), cursor };
46
47            mdbx_result(res)?;
48
49            Ok(s)
50        }
51    }
52
53    /// Returns a raw pointer to the underlying MDBX cursor.
54    ///
55    /// The caller **must** ensure that the pointer is not used after the
56    /// lifetime of the cursor.
57    pub const fn cursor(&self) -> *mut ffi::MDBX_cursor {
58        self.cursor
59    }
60
61    /// Returns an iterator over the raw key value slices.
62    pub fn iter_slices<'a>(self) -> IntoIter<K, Cow<'a, [u8]>, Cow<'a, [u8]>> {
63        self.into_iter()
64    }
65
66    /// Returns an iterator over database items.
67    #[expect(clippy::should_implement_trait)]
68    pub fn into_iter<Key, Value>(self) -> IntoIter<K, Key, Value>
69    where
70        Key: TableObject,
71        Value: TableObject,
72    {
73        IntoIter::new(self, MDBX_NEXT, MDBX_NEXT)
74    }
75
76    /// Retrieves a key/data pair from the cursor. Depending on the cursor op,
77    /// the current key may be returned.
78    fn get<Key, Value>(
79        &self,
80        key: Option<&[u8]>,
81        data: Option<&[u8]>,
82        op: MDBX_cursor_op,
83    ) -> Result<(Option<Key>, Value, bool)>
84    where
85        Key: TableObject,
86        Value: TableObject,
87    {
88        unsafe {
89            let mut key_val = slice_to_val(key);
90            let mut data_val = slice_to_val(data);
91            let key_ptr = key_val.iov_base;
92            let data_ptr = data_val.iov_base;
93            self.txn.txn_execute(|txn| {
94                let v = mdbx_result(ffi::mdbx_cursor_get(
95                    self.cursor,
96                    &mut key_val,
97                    &mut data_val,
98                    op,
99                ))?;
100                assert_ne!(data_ptr, data_val.iov_base);
101                let key_out = {
102                    // MDBX wrote in new key
103                    if ptr::eq(key_ptr, key_val.iov_base) {
104                        None
105                    } else {
106                        Some(Key::decode_val::<K>(txn, key_val)?)
107                    }
108                };
109                let data_out = Value::decode_val::<K>(txn, data_val)?;
110                Ok((key_out, data_out, v))
111            })?
112        }
113    }
114
115    fn get_value<Value>(
116        &mut self,
117        key: Option<&[u8]>,
118        data: Option<&[u8]>,
119        op: MDBX_cursor_op,
120    ) -> Result<Option<Value>>
121    where
122        Value: TableObject,
123    {
124        let (_, v, _) = mdbx_try_optional!(self.get::<(), Value>(key, data, op));
125
126        Ok(Some(v))
127    }
128
129    fn get_full<Key, Value>(
130        &mut self,
131        key: Option<&[u8]>,
132        data: Option<&[u8]>,
133        op: MDBX_cursor_op,
134    ) -> Result<Option<(Key, Value)>>
135    where
136        Key: TableObject,
137        Value: TableObject,
138    {
139        let (k, v, _) = mdbx_try_optional!(self.get(key, data, op));
140
141        Ok(Some((k.unwrap(), v)))
142    }
143
144    /// Position at first key/data item.
145    pub fn first<Key, Value>(&mut self) -> Result<Option<(Key, Value)>>
146    where
147        Key: TableObject,
148        Value: TableObject,
149    {
150        self.get_full(None, None, MDBX_FIRST)
151    }
152
153    /// [`DatabaseFlags::DUP_SORT`]-only: Position at first data item of current key.
154    pub fn first_dup<Value>(&mut self) -> Result<Option<Value>>
155    where
156        Value: TableObject,
157    {
158        self.get_value(None, None, MDBX_FIRST_DUP)
159    }
160
161    /// [`DatabaseFlags::DUP_SORT`]-only: Position at key/data pair.
162    pub fn get_both<Value>(&mut self, k: &[u8], v: &[u8]) -> Result<Option<Value>>
163    where
164        Value: TableObject,
165    {
166        self.get_value(Some(k), Some(v), MDBX_GET_BOTH)
167    }
168
169    /// [`DatabaseFlags::DUP_SORT`]-only: Position at given key and at first data greater than or
170    /// equal to specified data.
171    pub fn get_both_range<Value>(&mut self, k: &[u8], v: &[u8]) -> Result<Option<Value>>
172    where
173        Value: TableObject,
174    {
175        self.get_value(Some(k), Some(v), MDBX_GET_BOTH_RANGE)
176    }
177
178    /// Return key/data at current cursor position.
179    pub fn get_current<Key, Value>(&mut self) -> Result<Option<(Key, Value)>>
180    where
181        Key: TableObject,
182        Value: TableObject,
183    {
184        self.get_full(None, None, MDBX_GET_CURRENT)
185    }
186
187    /// DupFixed-only: Return up to a page of duplicate data items from current cursor position.
188    /// Move cursor to prepare for [`Self::next_multiple()`].
189    pub fn get_multiple<Value>(&mut self) -> Result<Option<Value>>
190    where
191        Value: TableObject,
192    {
193        self.get_value(None, None, MDBX_GET_MULTIPLE)
194    }
195
196    /// Position at last key/data item.
197    pub fn last<Key, Value>(&mut self) -> Result<Option<(Key, Value)>>
198    where
199        Key: TableObject,
200        Value: TableObject,
201    {
202        self.get_full(None, None, MDBX_LAST)
203    }
204
205    /// DupSort-only: Position at last data item of current key.
206    pub fn last_dup<Value>(&mut self) -> Result<Option<Value>>
207    where
208        Value: TableObject,
209    {
210        self.get_value(None, None, MDBX_LAST_DUP)
211    }
212
213    /// Position at next data item
214    #[expect(clippy::should_implement_trait)]
215    pub fn next<Key, Value>(&mut self) -> Result<Option<(Key, Value)>>
216    where
217        Key: TableObject,
218        Value: TableObject,
219    {
220        self.get_full(None, None, MDBX_NEXT)
221    }
222
223    /// [`DatabaseFlags::DUP_SORT`]-only: Position at next data item of current key.
224    pub fn next_dup<Key, Value>(&mut self) -> Result<Option<(Key, Value)>>
225    where
226        Key: TableObject,
227        Value: TableObject,
228    {
229        self.get_full(None, None, MDBX_NEXT_DUP)
230    }
231
232    /// [`DatabaseFlags::DUP_FIXED`]-only: Return up to a page of duplicate data items from next
233    /// cursor position. Move cursor to prepare for `MDBX_NEXT_MULTIPLE`.
234    pub fn next_multiple<Key, Value>(&mut self) -> Result<Option<(Key, Value)>>
235    where
236        Key: TableObject,
237        Value: TableObject,
238    {
239        self.get_full(None, None, MDBX_NEXT_MULTIPLE)
240    }
241
242    /// Position at first data item of next key.
243    pub fn next_nodup<Key, Value>(&mut self) -> Result<Option<(Key, Value)>>
244    where
245        Key: TableObject,
246        Value: TableObject,
247    {
248        self.get_full(None, None, MDBX_NEXT_NODUP)
249    }
250
251    /// Position at previous data item.
252    pub fn prev<Key, Value>(&mut self) -> Result<Option<(Key, Value)>>
253    where
254        Key: TableObject,
255        Value: TableObject,
256    {
257        self.get_full(None, None, MDBX_PREV)
258    }
259
260    /// [`DatabaseFlags::DUP_SORT`]-only: Position at previous data item of current key.
261    pub fn prev_dup<Key, Value>(&mut self) -> Result<Option<(Key, Value)>>
262    where
263        Key: TableObject,
264        Value: TableObject,
265    {
266        self.get_full(None, None, MDBX_PREV_DUP)
267    }
268
269    /// Position at last data item of previous key.
270    pub fn prev_nodup<Key, Value>(&mut self) -> Result<Option<(Key, Value)>>
271    where
272        Key: TableObject,
273        Value: TableObject,
274    {
275        self.get_full(None, None, MDBX_PREV_NODUP)
276    }
277
278    /// Position at specified key.
279    pub fn set<Value>(&mut self, key: &[u8]) -> Result<Option<Value>>
280    where
281        Value: TableObject,
282    {
283        self.get_value(Some(key), None, MDBX_SET)
284    }
285
286    /// Position at specified key, return both key and data.
287    pub fn set_key<Key, Value>(&mut self, key: &[u8]) -> Result<Option<(Key, Value)>>
288    where
289        Key: TableObject,
290        Value: TableObject,
291    {
292        self.get_full(Some(key), None, MDBX_SET_KEY)
293    }
294
295    /// Position at first key greater than or equal to specified key.
296    pub fn set_range<Key, Value>(&mut self, key: &[u8]) -> Result<Option<(Key, Value)>>
297    where
298        Key: TableObject,
299        Value: TableObject,
300    {
301        self.get_full(Some(key), None, MDBX_SET_RANGE)
302    }
303
304    /// [`DatabaseFlags::DUP_FIXED`]-only: Position at previous page and return up to a page of
305    /// duplicate data items.
306    pub fn prev_multiple<Key, Value>(&mut self) -> Result<Option<(Key, Value)>>
307    where
308        Key: TableObject,
309        Value: TableObject,
310    {
311        self.get_full(None, None, MDBX_PREV_MULTIPLE)
312    }
313
314    /// Position at first key-value pair greater than or equal to specified, return both key and
315    /// data, and the return code depends on a exact match.
316    ///
317    /// For non DupSort-ed collections this works the same as [`Self::set_range()`], but returns
318    /// [false] if key found exactly and [true] if greater key was found.
319    ///
320    /// For DupSort-ed a data value is taken into account for duplicates, i.e. for a pairs/tuples of
321    /// a key and an each data value of duplicates. Returns [false] if key-value pair found
322    /// exactly and [true] if the next pair was returned.
323    pub fn set_lowerbound<Key, Value>(&mut self, key: &[u8]) -> Result<Option<(bool, Key, Value)>>
324    where
325        Key: TableObject,
326        Value: TableObject,
327    {
328        let (k, v, found) = mdbx_try_optional!(self.get(Some(key), None, MDBX_SET_LOWERBOUND));
329
330        Ok(Some((found, k.unwrap(), v)))
331    }
332
333    /// Returns an iterator over database items.
334    ///
335    /// The iterator will begin with item next after the cursor, and continue until the end of the
336    /// database. For new cursors, the iterator will begin with the first item in the database.
337    ///
338    /// For databases with duplicate data items ([`DatabaseFlags::DUP_SORT`]), the
339    /// duplicate data items of each key will be returned before moving on to
340    /// the next key.
341    pub fn iter<Key, Value>(&mut self) -> Iter<'_, K, Key, Value>
342    where
343        Key: TableObject,
344        Value: TableObject,
345    {
346        Iter::new(self, ffi::MDBX_NEXT, ffi::MDBX_NEXT)
347    }
348
349    /// Iterate over database items starting from the beginning of the database.
350    ///
351    /// For databases with duplicate data items ([`DatabaseFlags::DUP_SORT`]), the
352    /// duplicate data items of each key will be returned before moving on to
353    /// the next key.
354    pub fn iter_start<Key, Value>(&mut self) -> Iter<'_, K, Key, Value>
355    where
356        Key: TableObject,
357        Value: TableObject,
358    {
359        Iter::new(self, ffi::MDBX_FIRST, ffi::MDBX_NEXT)
360    }
361
362    /// Iterate over database items starting from the given key.
363    ///
364    /// For databases with duplicate data items ([`DatabaseFlags::DUP_SORT`]), the
365    /// duplicate data items of each key will be returned before moving on to
366    /// the next key.
367    pub fn iter_from<Key, Value>(&mut self, key: &[u8]) -> Iter<'_, K, Key, Value>
368    where
369        Key: TableObject,
370        Value: TableObject,
371    {
372        let res: Result<Option<((), ())>> = self.set_range(key);
373        if let Err(error) = res {
374            return Iter::Err(Some(error))
375        };
376        Iter::new(self, ffi::MDBX_GET_CURRENT, ffi::MDBX_NEXT)
377    }
378
379    /// Iterate over duplicate database items. The iterator will begin with the
380    /// item next after the cursor, and continue until the end of the database.
381    /// Each item will be returned as an iterator of its duplicates.
382    pub fn iter_dup<Key, Value>(&mut self) -> IterDup<'_, K, Key, Value>
383    where
384        Key: TableObject,
385        Value: TableObject,
386    {
387        IterDup::new(self, ffi::MDBX_NEXT)
388    }
389
390    /// Iterate over duplicate database items starting from the beginning of the
391    /// database. Each item will be returned as an iterator of its duplicates.
392    pub fn iter_dup_start<Key, Value>(&mut self) -> IterDup<'_, K, Key, Value>
393    where
394        Key: TableObject,
395        Value: TableObject,
396    {
397        IterDup::new(self, ffi::MDBX_FIRST)
398    }
399
400    /// Iterate over duplicate items in the database starting from the given
401    /// key. Each item will be returned as an iterator of its duplicates.
402    pub fn iter_dup_from<Key, Value>(&mut self, key: &[u8]) -> IterDup<'_, K, Key, Value>
403    where
404        Key: TableObject,
405        Value: TableObject,
406    {
407        let res: Result<Option<((), ())>> = self.set_range(key);
408        if let Err(error) = res {
409            return IterDup::Err(Some(error))
410        };
411        IterDup::new(self, ffi::MDBX_GET_CURRENT)
412    }
413
414    /// Iterate over the duplicates of the item in the database with the given key.
415    pub fn iter_dup_of<Key, Value>(&mut self, key: &[u8]) -> Iter<'_, K, Key, Value>
416    where
417        Key: TableObject,
418        Value: TableObject,
419    {
420        let res: Result<Option<()>> = self.set(key);
421        match res {
422            Ok(Some(_)) => (),
423            Ok(None) => {
424                let _: Result<Option<((), ())>> = self.last();
425                return Iter::new(self, ffi::MDBX_NEXT, ffi::MDBX_NEXT)
426            }
427            Err(error) => return Iter::Err(Some(error)),
428        };
429        Iter::new(self, ffi::MDBX_GET_CURRENT, ffi::MDBX_NEXT_DUP)
430    }
431}
432
433impl Cursor<RW> {
434    /// Puts a key/data pair into the database. The cursor will be positioned at
435    /// the new data item, or on failure usually near it.
436    pub fn put(&mut self, key: &[u8], data: &[u8], flags: WriteFlags) -> Result<()> {
437        let key_val: ffi::MDBX_val =
438            ffi::MDBX_val { iov_len: key.len(), iov_base: key.as_ptr() as *mut c_void };
439        let mut data_val: ffi::MDBX_val =
440            ffi::MDBX_val { iov_len: data.len(), iov_base: data.as_ptr() as *mut c_void };
441        mdbx_result(unsafe {
442            self.txn.txn_execute(|_| {
443                ffi::mdbx_cursor_put(self.cursor, &key_val, &mut data_val, flags.bits())
444            })?
445        })?;
446
447        Ok(())
448    }
449
450    /// Deletes the current key/data pair.
451    ///
452    /// ### Flags
453    ///
454    /// [`WriteFlags::NO_DUP_DATA`] may be used to delete all data items for the
455    /// current key, if the database was opened with [`DatabaseFlags::DUP_SORT`].
456    pub fn del(&mut self, flags: WriteFlags) -> Result<()> {
457        mdbx_result(unsafe {
458            self.txn.txn_execute(|_| ffi::mdbx_cursor_del(self.cursor, flags.bits()))?
459        })?;
460
461        Ok(())
462    }
463}
464
465impl<K> Clone for Cursor<K>
466where
467    K: TransactionKind,
468{
469    fn clone(&self) -> Self {
470        self.txn.txn_execute(|_| Self::new_at_position(self).unwrap()).unwrap()
471    }
472}
473
474impl<K> fmt::Debug for Cursor<K>
475where
476    K: TransactionKind,
477{
478    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
479        f.debug_struct("Cursor").finish_non_exhaustive()
480    }
481}
482
483impl<K> Drop for Cursor<K>
484where
485    K: TransactionKind,
486{
487    fn drop(&mut self) {
488        // To be able to close a cursor of a timed out transaction, we need to renew it first.
489        // Hence the usage of `txn_execute_renew_on_timeout` here.
490        let _ = self
491            .txn
492            .txn_execute_renew_on_timeout(|_| unsafe { ffi::mdbx_cursor_close(self.cursor) });
493    }
494}
495
496const unsafe fn slice_to_val(slice: Option<&[u8]>) -> ffi::MDBX_val {
497    match slice {
498        Some(slice) => {
499            ffi::MDBX_val { iov_len: slice.len(), iov_base: slice.as_ptr() as *mut c_void }
500        }
501        None => ffi::MDBX_val { iov_len: 0, iov_base: ptr::null_mut() },
502    }
503}
504
505unsafe impl<K> Send for Cursor<K> where K: TransactionKind {}
506unsafe impl<K> Sync for Cursor<K> where K: TransactionKind {}
507
508/// An iterator over the key/value pairs in an MDBX database.
509#[derive(Debug)]
510pub enum IntoIter<K, Key, Value>
511where
512    K: TransactionKind,
513    Key: TableObject,
514    Value: TableObject,
515{
516    /// An iterator that returns an error on every call to [`Iter::next()`].
517    /// Cursor.iter*() creates an Iter of this type when MDBX returns an error
518    /// on retrieval of a cursor.  Using this variant instead of returning
519    /// an error makes `Cursor.iter()`* methods infallible, so consumers only
520    /// need to check the result of `Iter.next()`.
521    Err(Option<Error>),
522
523    /// An iterator that returns an Item on calls to [`Iter::next()`].
524    /// The Item is a [Result], so this variant
525    /// might still return an error, if retrieval of the key/value pair
526    /// fails for some reason.
527    Ok {
528        /// The MDBX cursor with which to iterate.
529        cursor: Cursor<K>,
530
531        /// The first operation to perform when the consumer calls [`Iter::next()`].
532        op: ffi::MDBX_cursor_op,
533
534        /// The next and subsequent operations to perform.
535        next_op: ffi::MDBX_cursor_op,
536
537        _marker: PhantomData<(Key, Value)>,
538    },
539}
540
541impl<K, Key, Value> IntoIter<K, Key, Value>
542where
543    K: TransactionKind,
544    Key: TableObject,
545    Value: TableObject,
546{
547    /// Creates a new iterator backed by the given cursor.
548    fn new(cursor: Cursor<K>, op: ffi::MDBX_cursor_op, next_op: ffi::MDBX_cursor_op) -> Self {
549        Self::Ok { cursor, op, next_op, _marker: Default::default() }
550    }
551}
552
553impl<K, Key, Value> Iterator for IntoIter<K, Key, Value>
554where
555    K: TransactionKind,
556    Key: TableObject,
557    Value: TableObject,
558{
559    type Item = Result<(Key, Value)>;
560
561    fn next(&mut self) -> Option<Self::Item> {
562        match self {
563            Self::Ok { cursor, op, next_op, .. } => {
564                let mut key = ffi::MDBX_val { iov_len: 0, iov_base: ptr::null_mut() };
565                let mut data = ffi::MDBX_val { iov_len: 0, iov_base: ptr::null_mut() };
566                let op = mem::replace(op, *next_op);
567                unsafe {
568                    let result = cursor.txn.txn_execute(|txn| {
569                        match ffi::mdbx_cursor_get(cursor.cursor(), &mut key, &mut data, op) {
570                            ffi::MDBX_SUCCESS => {
571                                let key = match Key::decode_val::<K>(txn, key) {
572                                    Ok(v) => v,
573                                    Err(e) => return Some(Err(e)),
574                                };
575                                let data = match Value::decode_val::<K>(txn, data) {
576                                    Ok(v) => v,
577                                    Err(e) => return Some(Err(e)),
578                                };
579                                Some(Ok((key, data)))
580                            }
581                            // MDBX_ENODATA can occur when the cursor was previously sought to a
582                            // non-existent value, e.g. iter_from with a
583                            // key greater than all values in the database.
584                            ffi::MDBX_NOTFOUND | ffi::MDBX_ENODATA => None,
585                            error => Some(Err(Error::from_err_code(error))),
586                        }
587                    });
588                    match result {
589                        Ok(result) => result,
590                        Err(err) => Some(Err(err)),
591                    }
592                }
593            }
594            Self::Err(err) => err.take().map(Err),
595        }
596    }
597}
598
599/// An iterator over the key/value pairs in an MDBX database.
600#[derive(Debug)]
601pub enum Iter<'cur, K, Key, Value>
602where
603    K: TransactionKind,
604    Key: TableObject,
605    Value: TableObject,
606{
607    /// An iterator that returns an error on every call to [`Iter::next()`].
608    /// Cursor.iter*() creates an Iter of this type when MDBX returns an error
609    /// on retrieval of a cursor.  Using this variant instead of returning
610    /// an error makes `Cursor.iter()`* methods infallible, so consumers only
611    /// need to check the result of `Iter.next()`.
612    Err(Option<Error>),
613
614    /// An iterator that returns an Item on calls to [`Iter::next()`].
615    /// The Item is a [Result], so this variant
616    /// might still return an error, if retrieval of the key/value pair
617    /// fails for some reason.
618    Ok {
619        /// The MDBX cursor with which to iterate.
620        cursor: &'cur mut Cursor<K>,
621
622        /// The first operation to perform when the consumer calls [`Iter::next()`].
623        op: ffi::MDBX_cursor_op,
624
625        /// The next and subsequent operations to perform.
626        next_op: ffi::MDBX_cursor_op,
627
628        _marker: PhantomData<fn(&'cur (), K, Key, Value)>,
629    },
630}
631
632impl<'cur, K, Key, Value> Iter<'cur, K, Key, Value>
633where
634    K: TransactionKind,
635    Key: TableObject,
636    Value: TableObject,
637{
638    /// Creates a new iterator backed by the given cursor.
639    fn new(
640        cursor: &'cur mut Cursor<K>,
641        op: ffi::MDBX_cursor_op,
642        next_op: ffi::MDBX_cursor_op,
643    ) -> Self {
644        Iter::Ok { cursor, op, next_op, _marker: Default::default() }
645    }
646}
647
648impl<K, Key, Value> Iterator for Iter<'_, K, Key, Value>
649where
650    K: TransactionKind,
651    Key: TableObject,
652    Value: TableObject,
653{
654    type Item = Result<(Key, Value)>;
655
656    fn next(&mut self) -> Option<Self::Item> {
657        match self {
658            Iter::Ok { cursor, op, next_op, .. } => {
659                let mut key = ffi::MDBX_val { iov_len: 0, iov_base: ptr::null_mut() };
660                let mut data = ffi::MDBX_val { iov_len: 0, iov_base: ptr::null_mut() };
661                let op = mem::replace(op, *next_op);
662                unsafe {
663                    let result = cursor.txn.txn_execute(|txn| {
664                        match ffi::mdbx_cursor_get(cursor.cursor(), &mut key, &mut data, op) {
665                            ffi::MDBX_SUCCESS => {
666                                let key = match Key::decode_val::<K>(txn, key) {
667                                    Ok(v) => v,
668                                    Err(e) => return Some(Err(e)),
669                                };
670                                let data = match Value::decode_val::<K>(txn, data) {
671                                    Ok(v) => v,
672                                    Err(e) => return Some(Err(e)),
673                                };
674                                Some(Ok((key, data)))
675                            }
676                            // MDBX_NODATA can occur when the cursor was previously sought to a
677                            // non-existent value, e.g. iter_from with a
678                            // key greater than all values in the database.
679                            ffi::MDBX_NOTFOUND | ffi::MDBX_ENODATA => None,
680                            error => Some(Err(Error::from_err_code(error))),
681                        }
682                    });
683                    match result {
684                        Ok(result) => result,
685                        Err(err) => Some(Err(err)),
686                    }
687                }
688            }
689            Iter::Err(err) => err.take().map(Err),
690        }
691    }
692}
693
694/// An iterator over the keys and duplicate values in an MDBX database.
695///
696/// The yielded items of the iterator are themselves iterators over the duplicate values for a
697/// specific key.
698pub enum IterDup<'cur, K, Key, Value>
699where
700    K: TransactionKind,
701    Key: TableObject,
702    Value: TableObject,
703{
704    /// An iterator that returns an error on every call to `Iter.next()`.
705    /// Cursor.iter*() creates an Iter of this type when MDBX returns an error
706    /// on retrieval of a cursor.  Using this variant instead of returning
707    /// an error makes `Cursor.iter()`* methods infallible, so consumers only
708    /// need to check the result of `Iter.next()`.
709    Err(Option<Error>),
710
711    /// An iterator that returns an Item on calls to `Iter.next()`.
712    /// The Item is a Result<(&'txn [u8], &'txn [u8])>, so this variant
713    /// might still return an error, if retrieval of the key/value pair
714    /// fails for some reason.
715    Ok {
716        /// The MDBX cursor with which to iterate.
717        cursor: &'cur mut Cursor<K>,
718
719        /// The first operation to perform when the consumer calls `Iter.next()`.
720        op: MDBX_cursor_op,
721
722        _marker: PhantomData<fn(&'cur (Key, Value))>,
723    },
724}
725
726impl<'cur, K, Key, Value> IterDup<'cur, K, Key, Value>
727where
728    K: TransactionKind,
729    Key: TableObject,
730    Value: TableObject,
731{
732    /// Creates a new iterator backed by the given cursor.
733    fn new(cursor: &'cur mut Cursor<K>, op: MDBX_cursor_op) -> Self {
734        IterDup::Ok { cursor, op, _marker: Default::default() }
735    }
736}
737
738impl<K, Key, Value> fmt::Debug for IterDup<'_, K, Key, Value>
739where
740    K: TransactionKind,
741    Key: TableObject,
742    Value: TableObject,
743{
744    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
745        f.debug_struct("IterDup").finish()
746    }
747}
748
749impl<K, Key, Value> Iterator for IterDup<'_, K, Key, Value>
750where
751    K: TransactionKind,
752    Key: TableObject,
753    Value: TableObject,
754{
755    type Item = IntoIter<K, Key, Value>;
756
757    fn next(&mut self) -> Option<Self::Item> {
758        match self {
759            IterDup::Ok { cursor, op, .. } => {
760                let mut key = ffi::MDBX_val { iov_len: 0, iov_base: ptr::null_mut() };
761                let mut data = ffi::MDBX_val { iov_len: 0, iov_base: ptr::null_mut() };
762                let op = mem::replace(op, ffi::MDBX_NEXT_NODUP);
763
764                let result = cursor.txn.txn_execute(|_| {
765                    let err_code =
766                        unsafe { ffi::mdbx_cursor_get(cursor.cursor(), &mut key, &mut data, op) };
767
768                    (err_code == ffi::MDBX_SUCCESS).then(|| {
769                        IntoIter::new(
770                            Cursor::new_at_position(&**cursor).unwrap(),
771                            ffi::MDBX_GET_CURRENT,
772                            ffi::MDBX_NEXT_DUP,
773                        )
774                    })
775                });
776
777                match result {
778                    Ok(result) => result,
779                    Err(err) => Some(IntoIter::Err(Some(err))),
780                }
781            }
782            IterDup::Err(err) => err.take().map(|e| IntoIter::Err(Some(e))),
783        }
784    }
785}