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
27pub trait Cursor<'txn> {
29 fn cursor(&self) -> *mut ffi::MDB_cursor;
34
35 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 fn iter(&mut self) -> Iter<'txn> {
61 Iter::new(self.cursor(), ffi::MDB_NEXT, ffi::MDB_NEXT)
62 }
63
64 fn iter_start(&mut self) -> Iter<'txn> {
70 Iter::new(self.cursor(), ffi::MDB_FIRST, ffi::MDB_NEXT)
71 }
72
73 fn iter_end(&mut self) -> Iter<'txn> {
79 Iter::new(self.cursor(), ffi::MDB_LAST, ffi::MDB_PREV)
80 }
81
82 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 fn iter_dup(&mut self) -> IterDup<'txn> {
102 IterDup::new(self.cursor(), ffi::MDB_NEXT)
103 }
104
105 fn iter_dup_start(&mut self) -> IterDup<'txn> {
108 IterDup::new(self.cursor(), ffi::MDB_FIRST)
109 }
110
111 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 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
141pub 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 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
183pub 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 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 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 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
272pub enum Iter<'txn> {
274 Err(Error),
280
281 Ok {
286 cursor: *mut ffi::MDB_cursor,
288
289 op: c_uint,
291
292 next_op: c_uint,
294
295 _marker: PhantomData<fn(&'txn ())>,
297 },
298}
299
300impl<'txn> Iter<'txn> {
301 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 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
353pub enum IterDup<'txn> {
358 Err(Error),
364
365 Ok {
370 cursor: *mut ffi::MDB_cursor,
372
373 op: c_uint,
375
376 _marker: PhantomData<fn(&'txn ())>,
378 },
379}
380
381impl<'txn> IterDup<'txn> {
382 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 assert_eq!(items, cursor.iter().collect::<Result<Vec<_>>>().unwrap());
539
540 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}