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}