@@ -60,7 +60,7 @@ pub trait Cursor<'txn> {
60
60
fn iter_from < K > ( & mut self , key : K ) -> Iter < ' txn > where K : AsRef < [ u8 ] > {
61
61
match self . get ( Some ( key. as_ref ( ) ) , None , ffi:: MDB_SET_RANGE ) {
62
62
Ok ( _) | Err ( Error :: NotFound ) => ( ) ,
63
- Err ( error) => panic ! ( "mdb_cursor_get returned an unexpected error: {}" , error) ,
63
+ Err ( error) => return Iter :: Err ( error) ,
64
64
} ;
65
65
Iter :: new ( self . cursor ( ) , ffi:: MDB_GET_CURRENT , ffi:: MDB_NEXT )
66
66
}
@@ -83,7 +83,7 @@ pub trait Cursor<'txn> {
83
83
fn iter_dup_from < K > ( & mut self , key : & K ) -> IterDup < ' txn > where K : AsRef < [ u8 ] > {
84
84
match self . get ( Some ( key. as_ref ( ) ) , None , ffi:: MDB_SET_RANGE ) {
85
85
Ok ( _) | Err ( Error :: NotFound ) => ( ) ,
86
- Err ( error) => panic ! ( "mdb_cursor_get returned an unexpected error: {}" , error) ,
86
+ Err ( error) => return IterDup :: Err ( error) ,
87
87
} ;
88
88
IterDup :: new ( self . cursor ( ) , ffi:: MDB_GET_CURRENT )
89
89
}
@@ -92,7 +92,7 @@ pub trait Cursor<'txn> {
92
92
fn iter_dup_of < K > ( & mut self , key : & K ) -> Iter < ' txn > where K : AsRef < [ u8 ] > {
93
93
match self . get ( Some ( key. as_ref ( ) ) , None , ffi:: MDB_SET ) {
94
94
Ok ( _) | Err ( Error :: NotFound ) => ( ) ,
95
- Err ( error) => panic ! ( "mdb_cursor_get returned an unexpected error: {}" , error) ,
95
+ Err ( error) => return Iter :: Err ( error) ,
96
96
} ;
97
97
Iter :: new ( self . cursor ( ) , ffi:: MDB_GET_CURRENT , ffi:: MDB_NEXT_DUP )
98
98
}
@@ -214,19 +214,39 @@ unsafe fn val_to_slice<'a>(val: ffi::MDB_val) -> &'a [u8] {
214
214
slice:: from_raw_parts ( val. mv_data as * const u8 , val. mv_size as usize )
215
215
}
216
216
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
+ } ,
223
243
}
224
244
225
245
impl < ' txn > Iter < ' txn > {
226
246
227
247
/// Creates a new iterator backed by the given cursor.
228
248
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 }
230
250
}
231
251
}
232
252
@@ -238,20 +258,25 @@ impl <'txn> fmt::Debug for Iter<'txn> {
238
258
239
259
impl < ' txn > Iterator for Iter < ' txn > {
240
260
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) ) ,
255
280
}
256
281
}
257
282
}
@@ -260,17 +285,35 @@ impl <'txn> Iterator for Iter<'txn> {
260
285
///
261
286
/// The yielded items of the iterator are themselves iterators over the duplicate values for a
262
287
/// 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
+ } ,
267
310
}
268
311
269
312
impl < ' txn > IterDup < ' txn > {
270
313
271
314
/// Creates a new iterator backed by the given cursor.
272
315
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 }
274
317
}
275
318
}
276
319
@@ -285,17 +328,22 @@ impl <'txn> Iterator for IterDup<'txn> {
285
328
type Item = Iter < ' txn > ;
286
329
287
330
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) ) ,
299
347
}
300
348
}
301
349
}
@@ -433,22 +481,30 @@ mod test {
433
481
434
482
let txn = env. begin_ro_txn ( ) . unwrap ( ) ;
435
483
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( ) ) ;
437
493
438
494
cursor. get ( Some ( b"key2" ) , None , MDB_SET ) . unwrap ( ) ;
439
495
assert_eq ! ( items. clone( ) . into_iter( ) . skip( 2 ) . collect:: <Vec <_>>( ) ,
440
- cursor. iter( ) . collect:: <Vec <_>>( ) ) ;
496
+ cursor. iter( ) . collect:: <Result < Vec <_>>> ( ) . unwrap ( ) ) ;
441
497
442
- assert_eq ! ( items, cursor. iter_start( ) . collect:: <Vec <_>>( ) ) ;
498
+ assert_eq ! ( items, cursor. iter_start( ) . collect:: <Result < Vec <_>>> ( ) . unwrap ( ) ) ;
443
499
444
500
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 ( ) ) ;
446
502
447
503
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 ( ) ) ;
449
505
450
506
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 ( ) ) ;
452
508
}
453
509
454
510
#[ test]
@@ -510,29 +566,29 @@ mod test {
510
566
511
567
let txn = env. begin_ro_txn ( ) . unwrap ( ) ;
512
568
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 ( ) ) ;
514
570
515
571
cursor. get ( Some ( b"b" ) , None , MDB_SET ) . unwrap ( ) ;
516
572
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 ( ) ) ;
518
574
519
575
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 ( ) ) ;
521
577
522
578
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 ( ) ) ;
524
580
525
581
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 ( ) ) ;
527
583
528
584
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 ( ) ) ;
530
586
531
587
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 ( ) ) ;
533
589
534
590
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 ( ) ) ;
536
592
537
593
assert_eq ! ( 0 , cursor. iter_dup_of( b"foo" ) . count( ) ) ;
538
594
}
@@ -571,10 +627,26 @@ mod test {
571
627
let mut i = 0 ;
572
628
let mut count = 0u32 ;
573
629
574
- for ( key, data) in cursor. iter ( ) {
630
+ for ( key, data) in cursor. iter ( ) . map ( Result :: unwrap ) {
575
631
i = i + key. len ( ) + data. len ( ) ;
576
632
count = count + 1 ;
577
633
}
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 ( ) ;
578
650
579
651
black_box ( i) ;
580
652
assert_eq ! ( count, n) ;
0 commit comments