Skip to content

Commit 1c1ff62

Browse files
committed
use Iter enum to return error result only from Iter.next()
1 parent c64f0b4 commit 1c1ff62

File tree

1 file changed

+127
-55
lines changed

1 file changed

+127
-55
lines changed

src/cursor.rs

Lines changed: 127 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ pub trait Cursor<'txn> {
6060
fn iter_from<K>(&mut self, key: K) -> Iter<'txn> where K: AsRef<[u8]> {
6161
match self.get(Some(key.as_ref()), None, ffi::MDB_SET_RANGE) {
6262
Ok(_) | Err(Error::NotFound) => (),
63-
Err(error) => panic!("mdb_cursor_get returned an unexpected error: {}", error),
63+
Err(error) => return Iter::Err(error),
6464
};
6565
Iter::new(self.cursor(), ffi::MDB_GET_CURRENT, ffi::MDB_NEXT)
6666
}
@@ -83,7 +83,7 @@ pub trait Cursor<'txn> {
8383
fn iter_dup_from<K>(&mut self, key: &K) -> IterDup<'txn> where K: AsRef<[u8]> {
8484
match self.get(Some(key.as_ref()), None, ffi::MDB_SET_RANGE) {
8585
Ok(_) | Err(Error::NotFound) => (),
86-
Err(error) => panic!("mdb_cursor_get returned an unexpected error: {}", error),
86+
Err(error) => return IterDup::Err(error),
8787
};
8888
IterDup::new(self.cursor(), ffi::MDB_GET_CURRENT)
8989
}
@@ -92,7 +92,7 @@ pub trait Cursor<'txn> {
9292
fn iter_dup_of<K>(&mut self, key: &K) -> Iter<'txn> where K: AsRef<[u8]> {
9393
match self.get(Some(key.as_ref()), None, ffi::MDB_SET) {
9494
Ok(_) | Err(Error::NotFound) => (),
95-
Err(error) => panic!("mdb_cursor_get returned an unexpected error: {}", error),
95+
Err(error) => return Iter::Err(error),
9696
};
9797
Iter::new(self.cursor(), ffi::MDB_GET_CURRENT, ffi::MDB_NEXT_DUP)
9898
}
@@ -214,19 +214,39 @@ unsafe fn val_to_slice<'a>(val: ffi::MDB_val) -> &'a [u8] {
214214
slice::from_raw_parts(val.mv_data as *const u8, val.mv_size as usize)
215215
}
216216

217-
/// An iterator over the values in an LMDB database.
218-
pub struct Iter<'txn> {
219-
cursor: *mut ffi::MDB_cursor,
220-
op: c_uint,
221-
next_op: c_uint,
222-
_marker: PhantomData<fn(&'txn ())>,
217+
/// An iterator over the key/value pairs in an LMDB database.
218+
pub enum Iter<'txn> {
219+
/// An iterator that returns an error on every call to Iter.next().
220+
/// Cursor.iter*() creates an Iter of this type when LMDB returns an error
221+
/// on retrieval of a cursor. Using this variant instead of returning
222+
/// an error makes Cursor.iter()* methods infallible, so consumers only
223+
/// need to check the result of Iter.next().
224+
Err(Error),
225+
226+
/// An iterator that returns an Item on calls to Iter.next().
227+
/// The Item is a Result<(&'txn [u8], &'txn [u8])>, so this variant
228+
/// might still return an error, if retrieval of the key/value pair
229+
/// fails for some reason.
230+
Ok {
231+
/// The LMDB cursor with which to iterate.
232+
cursor: *mut ffi::MDB_cursor,
233+
234+
/// The first operation to perform when the consumer calls Iter.next().
235+
op: c_uint,
236+
237+
/// The next and subsequent operations to perform.
238+
next_op: c_uint,
239+
240+
/// A marker to ensure the iterator doesn't outlive the transaction.
241+
_marker: PhantomData<fn(&'txn ())>,
242+
},
223243
}
224244

225245
impl <'txn> Iter<'txn> {
226246

227247
/// Creates a new iterator backed by the given cursor.
228248
fn new<'t>(cursor: *mut ffi::MDB_cursor, op: c_uint, next_op: c_uint) -> Iter<'t> {
229-
Iter { cursor: cursor, op: op, next_op: next_op, _marker: PhantomData }
249+
Iter::Ok { cursor: cursor, op: op, next_op: next_op, _marker: PhantomData }
230250
}
231251
}
232252

@@ -238,20 +258,25 @@ impl <'txn> fmt::Debug for Iter<'txn> {
238258

239259
impl <'txn> Iterator for Iter<'txn> {
240260

241-
type Item = (&'txn [u8], &'txn [u8]);
242-
243-
fn next(&mut self) -> Option<(&'txn [u8], &'txn [u8])> {
244-
let mut key = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
245-
let mut data = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
246-
let op = mem::replace(&mut self.op, self.next_op);
247-
unsafe {
248-
match ffi::mdb_cursor_get(self.cursor, &mut key, &mut data, op) {
249-
ffi::MDB_SUCCESS => Some((val_to_slice(key), val_to_slice(data))),
250-
// EINVAL can occur when the cursor was previously seeked to a non-existent value,
251-
// e.g. iter_from with a key greater than all values in the database.
252-
ffi::MDB_NOTFOUND | EINVAL => None,
253-
error => panic!("mdb_cursor_get returned an unexpected error: {}", error),
254-
}
261+
type Item = Result<(&'txn [u8], &'txn [u8])>;
262+
263+
fn next(&mut self) -> Option<Result<(&'txn [u8], &'txn [u8])>> {
264+
match self {
265+
&mut Iter::Ok { cursor, ref mut op, next_op, _marker } => {
266+
let mut key = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
267+
let mut data = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
268+
let op = mem::replace(op, next_op);
269+
unsafe {
270+
match ffi::mdb_cursor_get(cursor, &mut key, &mut data, op) {
271+
ffi::MDB_SUCCESS => Some(Ok((val_to_slice(key), val_to_slice(data)))),
272+
// EINVAL can occur when the cursor was previously seeked to a non-existent value,
273+
// e.g. iter_from with a key greater than all values in the database.
274+
ffi::MDB_NOTFOUND | EINVAL => None,
275+
error => Some(Err(Error::from_err_code(error))),
276+
}
277+
}
278+
},
279+
&mut Iter::Err(err) => Some(Err(err)),
255280
}
256281
}
257282
}
@@ -260,17 +285,35 @@ impl <'txn> Iterator for Iter<'txn> {
260285
///
261286
/// The yielded items of the iterator are themselves iterators over the duplicate values for a
262287
/// specific key.
263-
pub struct IterDup<'txn> {
264-
cursor: *mut ffi::MDB_cursor,
265-
op: c_uint,
266-
_marker: PhantomData<fn(&'txn ())>,
288+
pub enum IterDup<'txn> {
289+
/// An iterator that returns an error on every call to Iter.next().
290+
/// Cursor.iter*() creates an Iter of this type when LMDB returns an error
291+
/// on retrieval of a cursor. Using this variant instead of returning
292+
/// an error makes Cursor.iter()* methods infallible, so consumers only
293+
/// need to check the result of Iter.next().
294+
Err(Error),
295+
296+
/// An iterator that returns an Item on calls to Iter.next().
297+
/// The Item is a Result<(&'txn [u8], &'txn [u8])>, so this variant
298+
/// might still return an error, if retrieval of the key/value pair
299+
/// fails for some reason.
300+
Ok {
301+
/// The LMDB cursor with which to iterate.
302+
cursor: *mut ffi::MDB_cursor,
303+
304+
/// The first operation to perform when the consumer calls Iter.next().
305+
op: c_uint,
306+
307+
/// A marker to ensure the iterator doesn't outlive the transaction.
308+
_marker: PhantomData<fn(&'txn ())>,
309+
},
267310
}
268311

269312
impl <'txn> IterDup<'txn> {
270313

271314
/// Creates a new iterator backed by the given cursor.
272315
fn new<'t>(cursor: *mut ffi::MDB_cursor, op: c_uint) -> IterDup<'t> {
273-
IterDup { cursor: cursor, op: op, _marker: PhantomData }
316+
IterDup::Ok { cursor: cursor, op: op, _marker: PhantomData }
274317
}
275318
}
276319

@@ -285,17 +328,22 @@ impl <'txn> Iterator for IterDup<'txn> {
285328
type Item = Iter<'txn>;
286329

287330
fn next(&mut self) -> Option<Iter<'txn>> {
288-
let mut key = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
289-
let mut data = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
290-
let op = mem::replace(&mut self.op, ffi::MDB_NEXT_NODUP);
291-
let err_code = unsafe {
292-
ffi::mdb_cursor_get(self.cursor, &mut key, &mut data, op)
293-
};
294-
295-
if err_code == ffi::MDB_SUCCESS {
296-
Some(Iter::new(self.cursor, ffi::MDB_GET_CURRENT, ffi::MDB_NEXT_DUP))
297-
} else {
298-
None
331+
match self {
332+
&mut IterDup::Ok { cursor, ref mut op, _marker } => {
333+
let mut key = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
334+
let mut data = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() };
335+
let op = mem::replace(op, ffi::MDB_NEXT_NODUP);
336+
let err_code = unsafe {
337+
ffi::mdb_cursor_get(cursor, &mut key, &mut data, op)
338+
};
339+
340+
if err_code == ffi::MDB_SUCCESS {
341+
Some(Iter::new(cursor, ffi::MDB_GET_CURRENT, ffi::MDB_NEXT_DUP))
342+
} else {
343+
None
344+
}
345+
},
346+
&mut IterDup::Err(err) => Some(Iter::Err(err)),
299347
}
300348
}
301349
}
@@ -433,22 +481,30 @@ mod test {
433481

434482
let txn = env.begin_ro_txn().unwrap();
435483
let mut cursor = txn.open_ro_cursor(db).unwrap();
436-
assert_eq!(items, cursor.iter().collect::<Vec<_>>());
484+
485+
// Because Result implements FromIterator, we can collect the iterator
486+
// of items of type Result<_, E> into a Result<Vec<_, E>> by specifying
487+
// the collection type via the turbofish syntax.
488+
assert_eq!(items, cursor.iter().collect::<Result<Vec<_>>>().unwrap());
489+
490+
// Alternately, we can collect it into an appropriately typed variable.
491+
let retr: Result<Vec<_>> = cursor.iter_start().collect();
492+
assert_eq!(items, retr.unwrap());
437493

438494
cursor.get(Some(b"key2"), None, MDB_SET).unwrap();
439495
assert_eq!(items.clone().into_iter().skip(2).collect::<Vec<_>>(),
440-
cursor.iter().collect::<Vec<_>>());
496+
cursor.iter().collect::<Result<Vec<_>>>().unwrap());
441497

442-
assert_eq!(items, cursor.iter_start().collect::<Vec<_>>());
498+
assert_eq!(items, cursor.iter_start().collect::<Result<Vec<_>>>().unwrap());
443499

444500
assert_eq!(items.clone().into_iter().skip(1).collect::<Vec<_>>(),
445-
cursor.iter_from(b"key2").collect::<Vec<_>>());
501+
cursor.iter_from(b"key2").collect::<Result<Vec<_>>>().unwrap());
446502

447503
assert_eq!(items.clone().into_iter().skip(3).collect::<Vec<_>>(),
448-
cursor.iter_from(b"key4").collect::<Vec<_>>());
504+
cursor.iter_from(b"key4").collect::<Result<Vec<_>>>().unwrap());
449505

450506
assert_eq!(vec!().into_iter().collect::<Vec<(&[u8], &[u8])>>(),
451-
cursor.iter_from(b"key6").collect::<Vec<_>>());
507+
cursor.iter_from(b"key6").collect::<Result<Vec<_>>>().unwrap());
452508
}
453509

454510
#[test]
@@ -510,29 +566,29 @@ mod test {
510566

511567
let txn = env.begin_ro_txn().unwrap();
512568
let mut cursor = txn.open_ro_cursor(db).unwrap();
513-
assert_eq!(items, cursor.iter_dup().flat_map(|x| x).collect::<Vec<_>>());
569+
assert_eq!(items, cursor.iter_dup().flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap());
514570

515571
cursor.get(Some(b"b"), None, MDB_SET).unwrap();
516572
assert_eq!(items.clone().into_iter().skip(4).collect::<Vec<(&[u8], &[u8])>>(),
517-
cursor.iter_dup().flat_map(|x| x).collect::<Vec<_>>());
573+
cursor.iter_dup().flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap());
518574

519575
assert_eq!(items,
520-
cursor.iter_dup_start().flat_map(|x| x).collect::<Vec<(&[u8], &[u8])>>());
576+
cursor.iter_dup_start().flat_map(|x| x).collect::<Result<Vec<(&[u8], &[u8])>>>().unwrap());
521577

522578
assert_eq!(items.clone().into_iter().skip(3).collect::<Vec<(&[u8], &[u8])>>(),
523-
cursor.iter_dup_from(b"b").flat_map(|x| x).collect::<Vec<_>>());
579+
cursor.iter_dup_from(b"b").flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap());
524580

525581
assert_eq!(items.clone().into_iter().skip(3).collect::<Vec<(&[u8], &[u8])>>(),
526-
cursor.iter_dup_from(b"ab").flat_map(|x| x).collect::<Vec<_>>());
582+
cursor.iter_dup_from(b"ab").flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap());
527583

528584
assert_eq!(items.clone().into_iter().skip(9).collect::<Vec<(&[u8], &[u8])>>(),
529-
cursor.iter_dup_from(b"d").flat_map(|x| x).collect::<Vec<_>>());
585+
cursor.iter_dup_from(b"d").flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap());
530586

531587
assert_eq!(vec!().into_iter().collect::<Vec<(&[u8], &[u8])>>(),
532-
cursor.iter_dup_from(b"f").flat_map(|x| x).collect::<Vec<_>>());
588+
cursor.iter_dup_from(b"f").flat_map(|x| x).collect::<Result<Vec<_>>>().unwrap());
533589

534590
assert_eq!(items.clone().into_iter().skip(3).take(3).collect::<Vec<(&[u8], &[u8])>>(),
535-
cursor.iter_dup_of(b"b").collect::<Vec<_>>());
591+
cursor.iter_dup_of(b"b").collect::<Result<Vec<_>>>().unwrap());
536592

537593
assert_eq!(0, cursor.iter_dup_of(b"foo").count());
538594
}
@@ -571,10 +627,26 @@ mod test {
571627
let mut i = 0;
572628
let mut count = 0u32;
573629

574-
for (key, data) in cursor.iter() {
630+
for (key, data) in cursor.iter().map(Result::unwrap) {
575631
i = i + key.len() + data.len();
576632
count = count + 1;
577633
}
634+
for (key, data) in cursor.iter().filter_map(Result::ok) {
635+
i = i + key.len() + data.len();
636+
count = count + 1;
637+
}
638+
639+
fn iterate<'a>(cursor: &mut RoCursor) -> Result<()> {
640+
let mut i = 0;
641+
let mut count = 0u32;
642+
for result in cursor.iter() {
643+
let (key, data) = result?;
644+
i = i + key.len() + data.len();
645+
count = count + 1;
646+
}
647+
Ok(())
648+
}
649+
iterate(&mut cursor).unwrap();
578650

579651
black_box(i);
580652
assert_eq!(count, n);

0 commit comments

Comments
 (0)