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