lmdb_zero/iter.rs
1// Copyright 2016 FullContact, Inc
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use std::iter::Iterator;
10use std::ops::{Deref, DerefMut};
11
12use cursor::Cursor;
13use error::Result;
14use tx::ConstAccessor;
15use traits::*;
16
17/// A mutable value which is either owned or borrowed from an owning context.
18///
19/// This is very different from `Cow` in that one can mutate the shared
20/// reference but cannot take ownership.
21#[derive(Debug)]
22#[allow(missing_docs)]
23pub enum MaybeOwned<'a, T : 'a> {
24 Owned(T),
25 Borrowed(&'a mut T),
26}
27
28impl<'a, T : 'a> Deref for MaybeOwned<'a, T> {
29 type Target = T;
30
31 fn deref(&self) -> &T {
32 match *self {
33 MaybeOwned::Owned(ref t) => t,
34 MaybeOwned::Borrowed(ref t) => *t,
35 }
36 }
37}
38
39impl<'a, T : 'a> DerefMut for MaybeOwned<'a, T> {
40 fn deref_mut(&mut self) -> &mut T {
41 match *self {
42 MaybeOwned::Owned(ref mut t) => t,
43 // `ref mut` is necessary so we can borrow the field out of the
44 // enum.
45 MaybeOwned::Borrowed(ref mut t) => *t,
46 }
47 }
48}
49
50/// An iterator over items returned by successive calls of some function on
51/// `Cursor` until a `NOTFOUND` error is returned.
52///
53/// Special handling is afforded the first item in the iterator, since the
54/// simple act of positioning the cursor produces the first item.
55pub struct CursorIter<'a, 'access: 'a, 'txn: 'access, 'db: 'txn, T> {
56 cursor: MaybeOwned<'a, Cursor<'txn,'db>>,
57 access: &'access ConstAccessor<'txn>,
58 head: Option<T>,
59 next: fn (&mut Cursor<'txn,'db>, &'access ConstAccessor<'txn>)
60 -> Result<T>,
61}
62
63impl<'a, 'access: 'a, 'txn: 'access, 'db: 'txn, T>
64CursorIter<'a, 'access, 'txn, 'db, T> {
65 /// Creates a cursor iterator from the given cursor and accessor.
66 ///
67 /// `head` is invoked immediately on `cursor` and `accessor` to position
68 /// the cursor. The value it returns (if any) will be used as the first
69 /// value produced by the cursor.
70 ///
71 /// Beyond the first item, `next` will be invoked on `cursor` and
72 /// `accessor` to produce further items. Note that this is a plain function
73 /// pointer and not a function object so that the type does not need to be
74 /// encoded in the type of this iterator.
75 ///
76 /// ## Example
77 ///
78 /// ```
79 /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
80 /// # fn main() {
81 /// # let env = create_env();
82 /// # let db = dupdb(&env);
83 /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
84 /// {
85 /// let mut access = txn.access();
86 /// let f = lmdb::put::Flags::empty();
87 /// access.put(&db, "Fruit", "Apple", f).unwrap();
88 /// access.put(&db, "Fruit", "Orange", f).unwrap();
89 /// access.put(&db, "Animal", "Badger", f).unwrap();
90 /// access.put(&db, "Veggie", "Carrot", f).unwrap();
91 ///
92 /// let mut cursor = txn.cursor(&db).unwrap();
93 /// let mut iter = lmdb::CursorIter::new(
94 /// lmdb::MaybeOwned::Borrowed(&mut cursor), &*access,
95 /// |c, a| c.first(a), lmdb::Cursor::next::<str,str>).unwrap();
96 /// assert_eq!(("Animal", "Badger"), iter.next().unwrap().unwrap());
97 /// assert_eq!(("Fruit", "Apple"), iter.next().unwrap().unwrap());
98 /// assert_eq!(("Fruit", "Orange"), iter.next().unwrap().unwrap());
99 /// assert_eq!(("Veggie", "Carrot"), iter.next().unwrap().unwrap());
100 /// assert!(iter.next().is_none());
101 /// }
102 /// txn.commit().unwrap();
103 /// # }
104 /// ```
105 pub fn new<H : FnOnce(&mut Cursor<'txn,'db>,
106 &'access ConstAccessor<'txn>)
107 -> Result<T>>
108 (mut cursor: MaybeOwned<'a, Cursor<'txn,'db>>,
109 access: &'access ConstAccessor<'txn>,
110 head: H,
111 next: fn (&mut Cursor<'txn,'db>, &'access ConstAccessor<'txn>)
112 -> Result<T>)
113 -> Result<Self>
114 {
115 let head_val = try!(head(&mut*cursor, access).to_opt());
116 Ok(CursorIter {
117 cursor: cursor,
118 access: access,
119 head: head_val,
120 next: next,
121 })
122 }
123}
124
125impl<'a, 'access: 'a, 'txn: 'access, 'db: 'txn, T> Iterator
126for CursorIter<'a, 'access, 'txn, 'db, T> {
127 type Item = Result<T>;
128
129 fn next(&mut self) -> Option<Result<T>> {
130 if let Some(head) = self.head.take() {
131 Some(Ok(head))
132 } else {
133 match (self.next)(&mut*self.cursor, self.access).to_opt() {
134 Ok(Some(v)) => Some(Ok(v)),
135 Ok(None) => None,
136 Err(err) => Some(Err(err.into())),
137 }
138 }
139 }
140}