Skip to main content

heed/iterator/
iter.rs

1use std::borrow::Cow;
2use std::marker;
3
4use types::LazyDecode;
5
6use crate::iteration_method::{IterationMethod, MoveBetweenKeys, MoveThroughDuplicateValues};
7use crate::*;
8
9/// A read-only iterator structure.
10pub struct RoIter<'txn, KC, DC, IM = MoveThroughDuplicateValues> {
11    cursor: RoCursor<'txn>,
12    move_on_first: bool,
13    _phantom: marker::PhantomData<(KC, DC, IM)>,
14}
15
16impl<'txn, KC, DC, IM> RoIter<'txn, KC, DC, IM> {
17    pub(crate) fn new(cursor: RoCursor<'txn>) -> RoIter<'txn, KC, DC, IM> {
18        RoIter {
19            cursor,
20            move_on_first: true,
21            _phantom: marker::PhantomData,
22        }
23    }
24
25    /// Move on the first value of keys, ignoring duplicate values.
26    ///
27    /// ```
28    /// # use std::fs;
29    /// # use std::path::Path;
30    /// # use heed::{DatabaseFlags, EnvOpenOptions};
31    /// use heed::types::*;
32    /// use heed::byteorder::BigEndian;
33    ///
34    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
35    /// # let dir = tempfile::tempdir()?;
36    /// # let env = unsafe { EnvOpenOptions::new()
37    /// #     .map_size(10 * 1024 * 1024) // 10MB
38    /// #     .max_dbs(3000)
39    /// #     .open(dir.path())?
40    /// # };
41    /// type BEI64 = I64<BigEndian>;
42    ///
43    /// let mut wtxn = env.write_txn()?;
44    /// let db = env.database_options()
45    ///     .types::<BEI64, BEI64>()
46    ///     .flags(DatabaseFlags::DUP_SORT)
47    ///     .name("dup-sort")
48    ///     .create(&mut wtxn)?;
49    ///
50    /// # db.clear(&mut wtxn)?;
51    /// db.put(&mut wtxn, &68, &120)?;
52    /// db.put(&mut wtxn, &68, &121)?;
53    /// db.put(&mut wtxn, &68, &122)?;
54    /// db.put(&mut wtxn, &68, &123)?;
55    /// db.put(&mut wtxn, &35, &120)?;
56    /// db.put(&mut wtxn, &0, &120)?;
57    /// db.put(&mut wtxn, &42, &120)?;
58    ///
59    /// let mut iter = db.iter(&wtxn)?.move_between_keys();
60    /// assert_eq!(iter.next().transpose()?, Some((0, 120)));
61    /// assert_eq!(iter.next().transpose()?, Some((35, 120)));
62    /// assert_eq!(iter.next().transpose()?, Some((42, 120)));
63    /// assert_eq!(iter.next().transpose()?, Some((68, 120)));
64    /// assert_eq!(iter.next().transpose()?, None);
65    ///
66    /// drop(iter);
67    /// wtxn.commit()?;
68    /// # Ok(()) }
69    /// ```
70    pub fn move_between_keys(self) -> RoIter<'txn, KC, DC, MoveBetweenKeys> {
71        RoIter {
72            cursor: self.cursor,
73            move_on_first: self.move_on_first,
74            _phantom: marker::PhantomData,
75        }
76    }
77
78    /// Move through key/values entries and output duplicate values.
79    ///
80    /// ```
81    /// # use std::fs;
82    /// # use std::path::Path;
83    /// # use heed::{DatabaseFlags, EnvOpenOptions};
84    /// use heed::types::*;
85    /// use heed::byteorder::BigEndian;
86    ///
87    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
88    /// # let dir = tempfile::tempdir()?;
89    /// # let env = unsafe { EnvOpenOptions::new()
90    /// #     .map_size(10 * 1024 * 1024) // 10MB
91    /// #     .max_dbs(3000)
92    /// #     .open(dir.path())?
93    /// # };
94    /// type BEI64 = I64<BigEndian>;
95    ///
96    /// let mut wtxn = env.write_txn()?;
97    /// let db = env.database_options()
98    ///     .types::<BEI64, BEI64>()
99    ///     .flags(DatabaseFlags::DUP_SORT)
100    ///     .name("dup-sort")
101    ///     .create(&mut wtxn)?;
102    ///
103    /// # db.clear(&mut wtxn)?;
104    /// db.put(&mut wtxn, &68, &120)?;
105    /// db.put(&mut wtxn, &68, &121)?;
106    /// db.put(&mut wtxn, &68, &122)?;
107    /// db.put(&mut wtxn, &68, &123)?;
108    /// db.put(&mut wtxn, &35, &120)?;
109    /// db.put(&mut wtxn, &0, &120)?;
110    /// db.put(&mut wtxn, &42, &120)?;
111    ///
112    /// let mut iter = db.iter(&wtxn)?.move_through_duplicate_values();
113    /// assert_eq!(iter.next().transpose()?, Some((0, 120)));
114    /// assert_eq!(iter.next().transpose()?, Some((35, 120)));
115    /// assert_eq!(iter.next().transpose()?, Some((42, 120)));
116    /// assert_eq!(iter.next().transpose()?, Some((68, 120)));
117    /// assert_eq!(iter.next().transpose()?, Some((68, 121)));
118    /// assert_eq!(iter.next().transpose()?, Some((68, 122)));
119    /// assert_eq!(iter.next().transpose()?, Some((68, 123)));
120    /// assert_eq!(iter.next().transpose()?, None);
121    ///
122    /// drop(iter);
123    /// wtxn.commit()?;
124    /// # Ok(()) }
125    /// ```
126    pub fn move_through_duplicate_values(self) -> RoIter<'txn, KC, DC, MoveThroughDuplicateValues> {
127        RoIter {
128            cursor: self.cursor,
129            move_on_first: self.move_on_first,
130            _phantom: marker::PhantomData,
131        }
132    }
133
134    /// Change the codec types of this iterator, specifying the codecs.
135    pub fn remap_types<KC2, DC2>(self) -> RoIter<'txn, KC2, DC2, IM> {
136        RoIter {
137            cursor: self.cursor,
138            move_on_first: self.move_on_first,
139            _phantom: marker::PhantomData,
140        }
141    }
142
143    /// Change the key codec type of this iterator, specifying the new codec.
144    pub fn remap_key_type<KC2>(self) -> RoIter<'txn, KC2, DC, IM> {
145        self.remap_types::<KC2, DC>()
146    }
147
148    /// Change the data codec type of this iterator, specifying the new codec.
149    pub fn remap_data_type<DC2>(self) -> RoIter<'txn, KC, DC2, IM> {
150        self.remap_types::<KC, DC2>()
151    }
152
153    /// Wrap the data bytes into a lazy decoder.
154    pub fn lazily_decode_data(self) -> RoIter<'txn, KC, LazyDecode<DC>, IM> {
155        self.remap_types::<KC, LazyDecode<DC>>()
156    }
157}
158
159impl<'txn, KC, DC, IM> Iterator for RoIter<'txn, KC, DC, IM>
160where
161    KC: BytesDecode<'txn>,
162    DC: BytesDecode<'txn>,
163    IM: IterationMethod,
164{
165    type Item = Result<(KC::DItem, DC::DItem)>;
166
167    fn next(&mut self) -> Option<Self::Item> {
168        let result = if self.move_on_first {
169            self.move_on_first = false;
170            self.cursor.move_on_first(IM::MOVE_OPERATION)
171        } else {
172            self.cursor.move_on_next(IM::MOVE_OPERATION)
173        };
174
175        match result {
176            Ok(Some((key, data))) => match (KC::bytes_decode(key), DC::bytes_decode(data)) {
177                (Ok(key), Ok(data)) => Some(Ok((key, data))),
178                (Err(e), _) | (_, Err(e)) => Some(Err(Error::Decoding(e))),
179            },
180            Ok(None) => None,
181            Err(e) => Some(Err(e)),
182        }
183    }
184
185    fn last(mut self) -> Option<Self::Item> {
186        let result = if self.move_on_first {
187            self.cursor.move_on_last(IM::MOVE_OPERATION)
188        } else {
189            match (
190                self.cursor.current(),
191                self.cursor.move_on_last(IM::MOVE_OPERATION),
192            ) {
193                (Ok(Some((ckey, _))), Ok(Some((key, data)))) if ckey != key => {
194                    Ok(Some((key, data)))
195                }
196                (Ok(_), Ok(_)) => Ok(None),
197                (Err(e), _) | (_, Err(e)) => Err(e),
198            }
199        };
200
201        match result {
202            Ok(Some((key, data))) => match (KC::bytes_decode(key), DC::bytes_decode(data)) {
203                (Ok(key), Ok(data)) => Some(Ok((key, data))),
204                (Err(e), _) | (_, Err(e)) => Some(Err(Error::Decoding(e))),
205            },
206            Ok(None) => None,
207            Err(e) => Some(Err(e)),
208        }
209    }
210}
211
212impl<KC, DC, IM> fmt::Debug for RoIter<'_, KC, DC, IM> {
213    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214        f.debug_struct("RoIter").finish()
215    }
216}
217
218#[cfg(feature = "read-txn-no-tls")]
219unsafe impl<KC, DC, IM> Send for RoIter<'_, KC, DC, IM> {}
220
221/// A read-write iterator structure.
222pub struct RwIter<'txn, KC, DC, IM = MoveThroughDuplicateValues> {
223    cursor: RwCursor<'txn>,
224    move_on_first: bool,
225    _phantom: marker::PhantomData<(KC, DC, IM)>,
226}
227
228impl<'txn, KC, DC, IM> RwIter<'txn, KC, DC, IM> {
229    pub(crate) fn new(cursor: RwCursor<'txn>) -> RwIter<'txn, KC, DC, IM> {
230        RwIter {
231            cursor,
232            move_on_first: true,
233            _phantom: marker::PhantomData,
234        }
235    }
236
237    /// Delete the entry the cursor is currently pointing to.
238    ///
239    /// Returns `true` if the entry was successfully deleted.
240    ///
241    /// # Safety
242    ///
243    /// It is _[undefined behavior]_ to keep a reference of a value from this database
244    /// while modifying it.
245    ///
246    /// > [Values returned from the database are valid only until a subsequent update operation,
247    /// > or the end of the transaction.](http://www.lmdb.tech/doc/group__mdb.html#structMDB__val)
248    ///
249    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
250    pub unsafe fn del_current(&mut self) -> Result<bool> {
251        self.cursor.del_current()
252    }
253
254    /// Write a new value to the current entry.
255    ///
256    /// The given key **must** be equal to the one this cursor is pointing otherwise the database
257    /// can be put into an inconsistent state.
258    ///
259    /// Returns `true` if the entry was successfully written.
260    ///
261    /// > This is intended to be used when the new data is the same size as the old.
262    /// > Otherwise it will simply perform a delete of the old record followed by an insert.
263    ///
264    /// # Safety
265    ///
266    /// It is _[undefined behavior]_ to keep a reference of a value from this database while
267    /// modifying it, so you can't use the key/value that comes from the cursor to feed
268    /// this function.
269    ///
270    /// In other words: Transform the key and value that you borrow from this database into an owned
271    /// version of them (e.g. `&str` into `String`).
272    ///
273    /// > [Values returned from the database are valid only until a subsequent update operation,
274    /// > or the end of the transaction.](http://www.lmdb.tech/doc/group__mdb.html#structMDB__val)
275    ///
276    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
277    pub unsafe fn put_current<'a>(
278        &mut self,
279        key: &'a KC::EItem,
280        data: &'a DC::EItem,
281    ) -> Result<bool>
282    where
283        KC: BytesEncode<'a>,
284        DC: BytesEncode<'a>,
285    {
286        let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
287        let data_bytes: Cow<[u8]> = DC::bytes_encode(data).map_err(Error::Encoding)?;
288        self.cursor.put_current(&key_bytes, &data_bytes)
289    }
290
291    /// Write a new value to the current entry. The entry is written with the specified flags.
292    ///
293    /// The given key **must** be equal to the one this cursor is pointing otherwise the database
294    /// can be put into an inconsistent state.
295    ///
296    /// Returns `true` if the entry was successfully written.
297    ///
298    /// > This is intended to be used when the new data is the same size as the old.
299    /// > Otherwise it will simply perform a delete of the old record followed by an insert.
300    ///
301    /// # Safety
302    ///
303    /// Please read the safety notes of the [`RwIter::put_current`] method.
304    pub unsafe fn put_current_reserved_with_flags<'a, F>(
305        &mut self,
306        flags: PutFlags,
307        key: &'a KC::EItem,
308        data_size: usize,
309        write_func: F,
310    ) -> Result<bool>
311    where
312        KC: BytesEncode<'a>,
313        F: FnOnce(&mut ReservedSpace) -> io::Result<()>,
314    {
315        let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
316        self.cursor
317            .put_current_reserved_with_flags(flags, &key_bytes, data_size, write_func)
318    }
319
320    /// Insert a key-value pair in this database. The entry is written with the specified flags and data codec.
321    ///
322    /// For more info, see [`RwIter::put_current_with_options`].
323    ///
324    /// # Safety
325    ///
326    /// It is _[undefined behavior]_ to keep a reference of a value from this database while
327    /// modifying it, so you can't use the key/value that comes from the cursor to feed
328    /// this function.
329    ///
330    /// In other words: Transform the key and value that you borrow from this database into an owned
331    /// version of them (e.g. `&str` into `String`).
332    ///
333    /// > [Values returned from the database are valid only until a subsequent update operation,
334    /// > or the end of the transaction.](http://www.lmdb.tech/doc/group__mdb.html#structMDB__val)
335    ///
336    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
337    pub unsafe fn put_current_with_options<'a, NDC>(
338        &mut self,
339        flags: PutFlags,
340        key: &'a KC::EItem,
341        data: &'a NDC::EItem,
342    ) -> Result<()>
343    where
344        KC: BytesEncode<'a>,
345        NDC: BytesEncode<'a>,
346    {
347        let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
348        let data_bytes: Cow<[u8]> = NDC::bytes_encode(data).map_err(Error::Encoding)?;
349        self.cursor
350            .put_current_with_flags(flags, &key_bytes, &data_bytes)
351    }
352
353    /// Move on the first value of keys, ignoring duplicate values.
354    ///
355    /// For more info, see [`RoIter::move_between_keys`].
356    pub fn move_between_keys(self) -> RwIter<'txn, KC, DC, MoveBetweenKeys> {
357        RwIter {
358            cursor: self.cursor,
359            move_on_first: self.move_on_first,
360            _phantom: marker::PhantomData,
361        }
362    }
363
364    /// Move through key/values entries and output duplicate values.
365    ///
366    /// For more info, see [`RoIter::move_through_duplicate_values`].
367    pub fn move_through_duplicate_values(self) -> RwIter<'txn, KC, DC, MoveThroughDuplicateValues> {
368        RwIter {
369            cursor: self.cursor,
370            move_on_first: self.move_on_first,
371            _phantom: marker::PhantomData,
372        }
373    }
374
375    /// Change the codec types of this iterator, specifying the codecs.
376    pub fn remap_types<KC2, DC2>(self) -> RwIter<'txn, KC2, DC2, IM> {
377        RwIter {
378            cursor: self.cursor,
379            move_on_first: self.move_on_first,
380            _phantom: marker::PhantomData,
381        }
382    }
383
384    /// Change the key codec type of this iterator, specifying the new codec.
385    pub fn remap_key_type<KC2>(self) -> RwIter<'txn, KC2, DC, IM> {
386        self.remap_types::<KC2, DC>()
387    }
388
389    /// Change the data codec type of this iterator, specifying the new codec.
390    pub fn remap_data_type<DC2>(self) -> RwIter<'txn, KC, DC2, IM> {
391        self.remap_types::<KC, DC2>()
392    }
393
394    /// Wrap the data bytes into a lazy decoder.
395    pub fn lazily_decode_data(self) -> RwIter<'txn, KC, LazyDecode<DC>, IM> {
396        self.remap_types::<KC, LazyDecode<DC>>()
397    }
398}
399
400impl<'txn, KC, DC, IM> Iterator for RwIter<'txn, KC, DC, IM>
401where
402    KC: BytesDecode<'txn>,
403    DC: BytesDecode<'txn>,
404    IM: IterationMethod,
405{
406    type Item = Result<(KC::DItem, DC::DItem)>;
407
408    fn next(&mut self) -> Option<Self::Item> {
409        let result = if self.move_on_first {
410            self.move_on_first = false;
411            self.cursor.move_on_first(IM::MOVE_OPERATION)
412        } else {
413            self.cursor.move_on_next(IM::MOVE_OPERATION)
414        };
415
416        match result {
417            Ok(Some((key, data))) => match (KC::bytes_decode(key), DC::bytes_decode(data)) {
418                (Ok(key), Ok(data)) => Some(Ok((key, data))),
419                (Err(e), _) | (_, Err(e)) => Some(Err(Error::Decoding(e))),
420            },
421            Ok(None) => None,
422            Err(e) => Some(Err(e)),
423        }
424    }
425
426    fn last(mut self) -> Option<Self::Item> {
427        let result = if self.move_on_first {
428            self.cursor.move_on_last(IM::MOVE_OPERATION)
429        } else {
430            match (
431                self.cursor.current(),
432                self.cursor.move_on_last(IM::MOVE_OPERATION),
433            ) {
434                (Ok(Some((ckey, _))), Ok(Some((key, data)))) if ckey != key => {
435                    Ok(Some((key, data)))
436                }
437                (Ok(_), Ok(_)) => Ok(None),
438                (Err(e), _) | (_, Err(e)) => Err(e),
439            }
440        };
441
442        match result {
443            Ok(Some((key, data))) => match (KC::bytes_decode(key), DC::bytes_decode(data)) {
444                (Ok(key), Ok(data)) => Some(Ok((key, data))),
445                (Err(e), _) | (_, Err(e)) => Some(Err(Error::Decoding(e))),
446            },
447            Ok(None) => None,
448            Err(e) => Some(Err(e)),
449        }
450    }
451}
452
453impl<KC, DC, IM> fmt::Debug for RwIter<'_, KC, DC, IM> {
454    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
455        f.debug_struct("RwIter").finish()
456    }
457}
458
459/// A reverse read-only iterator structure.
460pub struct RoRevIter<'txn, KC, DC, IM = MoveThroughDuplicateValues> {
461    cursor: RoCursor<'txn>,
462    move_on_last: bool,
463    _phantom: marker::PhantomData<(KC, DC, IM)>,
464}
465
466impl<'txn, KC, DC, IM> RoRevIter<'txn, KC, DC, IM> {
467    pub(crate) fn new(cursor: RoCursor<'txn>) -> RoRevIter<'txn, KC, DC, IM> {
468        RoRevIter {
469            cursor,
470            move_on_last: true,
471            _phantom: marker::PhantomData,
472        }
473    }
474
475    /// Move on the first value of keys, ignoring duplicate values.
476    ///
477    /// For more info, see [`RoIter::move_between_keys`].
478    pub fn move_between_keys(self) -> RoRevIter<'txn, KC, DC, MoveBetweenKeys> {
479        RoRevIter {
480            cursor: self.cursor,
481            move_on_last: self.move_on_last,
482            _phantom: marker::PhantomData,
483        }
484    }
485
486    /// Move through key/values entries and output duplicate values.
487    ///
488    /// For more info, see [`RoIter::move_through_duplicate_values`].
489    pub fn move_through_duplicate_values(
490        self,
491    ) -> RoRevIter<'txn, KC, DC, MoveThroughDuplicateValues> {
492        RoRevIter {
493            cursor: self.cursor,
494            move_on_last: self.move_on_last,
495            _phantom: marker::PhantomData,
496        }
497    }
498
499    /// Change the codec types of this iterator, specifying the codecs.
500    pub fn remap_types<KC2, DC2>(self) -> RoRevIter<'txn, KC2, DC2, IM> {
501        RoRevIter {
502            cursor: self.cursor,
503            move_on_last: self.move_on_last,
504            _phantom: marker::PhantomData,
505        }
506    }
507
508    /// Change the key codec type of this iterator, specifying the new codec.
509    pub fn remap_key_type<KC2>(self) -> RoRevIter<'txn, KC2, DC, IM> {
510        self.remap_types::<KC2, DC>()
511    }
512
513    /// Change the data codec type of this iterator, specifying the new codec.
514    pub fn remap_data_type<DC2>(self) -> RoRevIter<'txn, KC, DC2, IM> {
515        self.remap_types::<KC, DC2>()
516    }
517
518    /// Wrap the data bytes into a lazy decoder.
519    pub fn lazily_decode_data(self) -> RoRevIter<'txn, KC, LazyDecode<DC>, IM> {
520        self.remap_types::<KC, LazyDecode<DC>>()
521    }
522}
523
524impl<'txn, KC, DC, IM> Iterator for RoRevIter<'txn, KC, DC, IM>
525where
526    KC: BytesDecode<'txn>,
527    DC: BytesDecode<'txn>,
528    IM: IterationMethod,
529{
530    type Item = Result<(KC::DItem, DC::DItem)>;
531
532    fn next(&mut self) -> Option<Self::Item> {
533        let result = if self.move_on_last {
534            self.move_on_last = false;
535            self.cursor.move_on_last(IM::MOVE_OPERATION)
536        } else {
537            self.cursor.move_on_prev(IM::MOVE_OPERATION)
538        };
539
540        match result {
541            Ok(Some((key, data))) => match (KC::bytes_decode(key), DC::bytes_decode(data)) {
542                (Ok(key), Ok(data)) => Some(Ok((key, data))),
543                (Err(e), _) | (_, Err(e)) => Some(Err(Error::Decoding(e))),
544            },
545            Ok(None) => None,
546            Err(e) => Some(Err(e)),
547        }
548    }
549
550    fn last(mut self) -> Option<Self::Item> {
551        let result = if self.move_on_last {
552            self.cursor.move_on_first(IM::MOVE_OPERATION)
553        } else {
554            match (
555                self.cursor.current(),
556                self.cursor.move_on_first(IM::MOVE_OPERATION),
557            ) {
558                (Ok(Some((ckey, _))), Ok(Some((key, data)))) if ckey != key => {
559                    Ok(Some((key, data)))
560                }
561                (Ok(_), Ok(_)) => Ok(None),
562                (Err(e), _) | (_, Err(e)) => Err(e),
563            }
564        };
565
566        match result {
567            Ok(Some((key, data))) => match (KC::bytes_decode(key), DC::bytes_decode(data)) {
568                (Ok(key), Ok(data)) => Some(Ok((key, data))),
569                (Err(e), _) | (_, Err(e)) => Some(Err(Error::Decoding(e))),
570            },
571            Ok(None) => None,
572            Err(e) => Some(Err(e)),
573        }
574    }
575}
576
577impl<KC, DC, IM> fmt::Debug for RoRevIter<'_, KC, DC, IM> {
578    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
579        f.debug_struct("RoRevIter").finish()
580    }
581}
582
583#[cfg(feature = "read-txn-no-tls")]
584unsafe impl<KC, DC, IM> Send for RoRevIter<'_, KC, DC, IM> {}
585
586/// A reverse read-write iterator structure.
587pub struct RwRevIter<'txn, KC, DC, IM = MoveThroughDuplicateValues> {
588    cursor: RwCursor<'txn>,
589    move_on_last: bool,
590    _phantom: marker::PhantomData<(KC, DC, IM)>,
591}
592
593impl<'txn, KC, DC, IM> RwRevIter<'txn, KC, DC, IM> {
594    pub(crate) fn new(cursor: RwCursor<'txn>) -> RwRevIter<'txn, KC, DC, IM> {
595        RwRevIter {
596            cursor,
597            move_on_last: true,
598            _phantom: marker::PhantomData,
599        }
600    }
601
602    /// Delete the entry the cursor is currently pointing to.
603    ///
604    /// Returns `true` if the entry was successfully deleted.
605    ///
606    /// # Safety
607    ///
608    /// It is _[undefined behavior]_ to keep a reference of a value from this database
609    /// while modifying it.
610    ///
611    /// > [Values returned from the database are valid only until a subsequent update operation,
612    /// > or the end of the transaction.](http://www.lmdb.tech/doc/group__mdb.html#structMDB__val)
613    ///
614    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
615    pub unsafe fn del_current(&mut self) -> Result<bool> {
616        self.cursor.del_current()
617    }
618
619    /// Write a new value to the current entry.
620    ///
621    /// The given key **must** be equal to the one this cursor is pointing otherwise the database
622    /// can be put into an inconsistent state.
623    ///
624    /// Returns `true` if the entry was successfully written.
625    ///
626    /// > This is intended to be used when the new data is the same size as the old.
627    /// > Otherwise it will simply perform a delete of the old record followed by an insert.
628    ///
629    /// # Safety
630    ///
631    /// It is _[undefined behavior]_ to keep a reference of a value from this database while
632    /// modifying it, so you can't use the key/value that comes from the cursor to feed
633    /// this function.
634    ///
635    /// In other words: Transform the key and value that you borrow from this database into an owned
636    /// version of them (e.g. `&str` into `String`).
637    ///
638    /// > [Values returned from the database are valid only until a subsequent update operation,
639    /// > or the end of the transaction.](http://www.lmdb.tech/doc/group__mdb.html#structMDB__val)
640    ///
641    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
642    pub unsafe fn put_current<'a>(
643        &mut self,
644        key: &'a KC::EItem,
645        data: &'a DC::EItem,
646    ) -> Result<bool>
647    where
648        KC: BytesEncode<'a>,
649        DC: BytesEncode<'a>,
650    {
651        let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
652        let data_bytes: Cow<[u8]> = DC::bytes_encode(data).map_err(Error::Encoding)?;
653        self.cursor.put_current(&key_bytes, &data_bytes)
654    }
655
656    /// Write a new value to the current entry. The entry is written with the specified flags.
657    ///
658    /// The given key **must** be equal to the one this cursor is pointing otherwise the database
659    /// can be put into an inconsistent state.
660    ///
661    /// Returns `true` if the entry was successfully written.
662    ///
663    /// > This is intended to be used when the new data is the same size as the old.
664    /// > Otherwise it will simply perform a delete of the old record followed by an insert.
665    ///
666    /// # Safety
667    ///
668    /// Please read the safety notes of the [`RwRevIter::put_current`] method.
669    pub unsafe fn put_current_reserved_with_flags<'a, F>(
670        &mut self,
671        flags: PutFlags,
672        key: &'a KC::EItem,
673        data_size: usize,
674        write_func: F,
675    ) -> Result<bool>
676    where
677        KC: BytesEncode<'a>,
678        F: FnOnce(&mut ReservedSpace) -> io::Result<()>,
679    {
680        let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
681        self.cursor
682            .put_current_reserved_with_flags(flags, &key_bytes, data_size, write_func)
683    }
684
685    /// Insert a key-value pair in this database. The entry is written with the specified flags and data codec.
686    ///
687    /// For more info, see [`RwIter::put_current_with_options`].
688    ///
689    /// # Safety
690    ///
691    /// It is _[undefined behavior]_ to keep a reference of a value from this database while
692    /// modifying it, so you can't use the key/value that comes from the cursor to feed
693    /// this function.
694    ///
695    /// In other words: Transform the key and value that you borrow from this database into an owned
696    /// version of them (e.g. `&str` into `String`).
697    ///
698    /// > [Values returned from the database are valid only until a subsequent update operation,
699    /// > or the end of the transaction.](http://www.lmdb.tech/doc/group__mdb.html#structMDB__val)
700    ///
701    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
702    pub unsafe fn put_current_with_options<'a, NDC>(
703        &mut self,
704        flags: PutFlags,
705        key: &'a KC::EItem,
706        data: &'a NDC::EItem,
707    ) -> Result<()>
708    where
709        KC: BytesEncode<'a>,
710        NDC: BytesEncode<'a>,
711    {
712        let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
713        let data_bytes: Cow<[u8]> = NDC::bytes_encode(data).map_err(Error::Encoding)?;
714        self.cursor
715            .put_current_with_flags(flags, &key_bytes, &data_bytes)
716    }
717
718    /// Move on the first value of keys, ignoring duplicate values.
719    ///
720    /// For more info, see [`RoIter::move_between_keys`].
721    pub fn move_between_keys(self) -> RwRevIter<'txn, KC, DC, MoveBetweenKeys> {
722        RwRevIter {
723            cursor: self.cursor,
724            move_on_last: self.move_on_last,
725            _phantom: marker::PhantomData,
726        }
727    }
728
729    /// Move through key/values entries and output duplicate values.
730    ///
731    /// For more info, see [`RoIter::move_through_duplicate_values`].
732    pub fn move_through_duplicate_values(
733        self,
734    ) -> RwRevIter<'txn, KC, DC, MoveThroughDuplicateValues> {
735        RwRevIter {
736            cursor: self.cursor,
737            move_on_last: self.move_on_last,
738            _phantom: marker::PhantomData,
739        }
740    }
741
742    /// Change the codec types of this iterator, specifying the codecs.
743    pub fn remap_types<KC2, DC2>(self) -> RwRevIter<'txn, KC2, DC2, IM> {
744        RwRevIter {
745            cursor: self.cursor,
746            move_on_last: self.move_on_last,
747            _phantom: marker::PhantomData,
748        }
749    }
750
751    /// Change the key codec type of this iterator, specifying the new codec.
752    pub fn remap_key_type<KC2>(self) -> RwRevIter<'txn, KC2, DC, IM> {
753        self.remap_types::<KC2, DC>()
754    }
755
756    /// Change the data codec type of this iterator, specifying the new codec.
757    pub fn remap_data_type<DC2>(self) -> RwRevIter<'txn, KC, DC2, IM> {
758        self.remap_types::<KC, DC2>()
759    }
760
761    /// Wrap the data bytes into a lazy decoder.
762    pub fn lazily_decode_data(self) -> RwRevIter<'txn, KC, LazyDecode<DC>, IM> {
763        self.remap_types::<KC, LazyDecode<DC>>()
764    }
765}
766
767impl<'txn, KC, DC, IM> Iterator for RwRevIter<'txn, KC, DC, IM>
768where
769    KC: BytesDecode<'txn>,
770    DC: BytesDecode<'txn>,
771    IM: IterationMethod,
772{
773    type Item = Result<(KC::DItem, DC::DItem)>;
774
775    fn next(&mut self) -> Option<Self::Item> {
776        let result = if self.move_on_last {
777            self.move_on_last = false;
778            self.cursor.move_on_last(IM::MOVE_OPERATION)
779        } else {
780            self.cursor.move_on_prev(IM::MOVE_OPERATION)
781        };
782
783        match result {
784            Ok(Some((key, data))) => match (KC::bytes_decode(key), DC::bytes_decode(data)) {
785                (Ok(key), Ok(data)) => Some(Ok((key, data))),
786                (Err(e), _) | (_, Err(e)) => Some(Err(Error::Decoding(e))),
787            },
788            Ok(None) => None,
789            Err(e) => Some(Err(e)),
790        }
791    }
792
793    fn last(mut self) -> Option<Self::Item> {
794        let result = if self.move_on_last {
795            self.cursor.move_on_first(IM::MOVE_OPERATION)
796        } else {
797            match (
798                self.cursor.current(),
799                self.cursor.move_on_first(IM::MOVE_OPERATION),
800            ) {
801                (Ok(Some((ckey, _))), Ok(Some((key, data)))) if ckey != key => {
802                    Ok(Some((key, data)))
803                }
804                (Ok(_), Ok(_)) => Ok(None),
805                (Err(e), _) | (_, Err(e)) => Err(e),
806            }
807        };
808
809        match result {
810            Ok(Some((key, data))) => match (KC::bytes_decode(key), DC::bytes_decode(data)) {
811                (Ok(key), Ok(data)) => Some(Ok((key, data))),
812                (Err(e), _) | (_, Err(e)) => Some(Err(Error::Decoding(e))),
813            },
814            Ok(None) => None,
815            Err(e) => Some(Err(e)),
816        }
817    }
818}
819
820impl<KC, DC, IM> fmt::Debug for RwRevIter<'_, KC, DC, IM> {
821    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
822        f.debug_struct("RwRevIter").finish()
823    }
824}