lmdb_zero/
cursor.rs

1// Copyright 2016 FullContact, Inc
2// Copyright 2017, 2018 Jason Lingle
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10use std::mem;
11use std::ptr;
12use libc::{self, c_void};
13
14use ffi;
15use supercow::{NonSyncSupercow, Supercow, Phantomcow};
16
17use env::Environment;
18use error::Result;
19use mdb_vals::*;
20use traits::*;
21use dbi::Database;
22use tx::{self, put, del, ConstAccessor, ConstTransaction, WriteAccessor};
23use tx::assert_sensible_cursor;
24
25#[derive(Debug)]
26struct CursorHandle(*mut ffi::MDB_cursor);
27impl Drop for CursorHandle {
28    fn drop(&mut self) {
29        unsafe {
30            ffi::mdb_cursor_close(self.0);
31        }
32    }
33}
34
35/// A cursor into an LMDB database.
36///
37/// Depending on the context, a cursor's lifetime may be scoped to a
38/// transaction or to the whole environment. Its lifetime is also naturally
39/// bound to the lifetime of the database it cursors into.
40///
41/// ## Creation and Ownership
42///
43/// Cursors are normally created by calling `.cursor()` on the transaction that
44/// is to own them. Since a `Cursor` is associated with a `Database`, this also
45/// involves passing a reference or other handle to that `Database` to the
46/// call.
47///
48/// For the `Database`, all three ownership models are permitted, though owned
49/// likely is not useful. The transaction can be used with borrowed or shared
50/// ownership, but note that shared ownership requires having the
51/// `CreateCursor` trait imported.
52///
53/// ### Example — Traditional "keep everything on the stack" style
54///
55/// This is the simplest way to use `Cursor`, but not always the easiest. Most
56/// examples in the documentation use this method. Here, the `Cursor` holds
57/// references to the transaction and the database. This makes it somewhat
58/// inflexible; for example, you cannot make a structure which owns both the
59/// transaction and some set of cursors.
60///
61/// ```
62/// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
63/// # fn main() {
64/// # let env = create_env();
65/// # let db = defdb(&env);
66/// # let txn = lmdb::WriteTransaction::new(&env).unwrap();
67/// # run(&txn, &mut txn.access(), &db);
68/// # }
69/// // N.B. Unneeded type and lifetime annotations here for clarity.
70/// fn run<'db, 'txn>(txn: &'txn lmdb::WriteTransaction,
71///                   access: &'txn mut lmdb::WriteAccessor,
72///                   db: &'db lmdb::Database) {
73///   let mut cursor: lmdb::Cursor<'txn, 'db> = txn.cursor(db).unwrap();
74///   // Do stuff with cursor.
75/// # ::std::mem::drop(cursor);
76/// }
77/// ```
78///
79/// ### Example — Use reference counting for more flexibility
80///
81/// ```
82/// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
83/// use std::sync::Arc;
84///
85/// // We need to import the `CreateCursor` trait to be able to use shared
86/// // mode cursors. `TxExt` also gets us `to_const()` used below.
87/// use lmdb::traits::{CreateCursor, TxExt};
88///
89/// // This approach lets us make this `Context` struct wherein we can pass
90/// // around everything our functions might need in one piece as well as
91/// // having more flexible transaction lifetimes.
92/// struct Context {
93///   txn: Arc<lmdb::ConstTransaction<'static>>,
94///   cursor: Arc<lmdb::Cursor<'static,'static>>,
95/// }
96///
97/// // N.B. Unneeded type and lifetime annotations here for clarity.
98///
99/// # fn main() {
100/// // Everything at higher levels also needs to have `'static` lifetimes.
101/// // Here, we just stuff everything into `Arc`s for simplicity.
102/// let env: Arc<lmdb::Environment> = Arc::new(create_env());
103/// let db: Arc<lmdb::Database<'static>> = Arc::new(lmdb::Database::open(
104///   env.clone(), None, &lmdb::DatabaseOptions::defaults()).unwrap());
105///
106/// // Now we can make our transaction and cursor and pass them around as one.
107/// // Note that you can also use plain `Rc` at this level, too.
108/// let txn: Arc<lmdb::WriteTransaction<'static>> =
109///   Arc::new(lmdb::WriteTransaction::new(env.clone()).unwrap());
110/// let cursor: Arc<lmdb::Cursor<'static, 'static>> = Arc::new(
111///   txn.cursor(db.clone()).unwrap());
112/// let context = Context { txn: txn.clone().to_const(), cursor: cursor };
113/// do_stuff(&context);
114///
115/// // Drop the context so we can get the `WriteTransaction` back
116/// // and commit it.
117/// drop(context);
118/// let txn = Arc::try_unwrap(txn).unwrap();
119/// txn.commit().unwrap();
120/// # }
121///
122/// #[allow(unused_vars)]
123/// fn do_stuff(context: &Context) {
124///   // do stuff
125/// }
126/// ```
127///
128/// ## Lifetime
129///
130/// A cursor must be strictly outlived by both the transaction that created it
131/// and by the database into which it indexes. The two lifetimes are needed to
132/// permit a cursor to be disassociated from its transaction and rebound to a
133/// later transaction.
134///
135/// `Cursor` is covariant on both of its lifetimes. If you have an owned
136/// `Cursor` as a structure member and don't plan on using the `dissoc_cursor`
137/// API, you can use one lifetime parameter to fill both without issue.
138///
139/// ```rust,norun
140/// # #![allow(dead_code)]
141/// # extern crate lmdb_zero as lmdb;
142/// # fn main() { }
143/// #
144/// struct CursorOwner<'a> {
145///   cursor: lmdb::Cursor<'a, 'a>,
146/// }
147/// fn covariance<'a, 'txn: 'a, 'db: 'a>(c: lmdb::Cursor<'txn,'db>)
148///                                     -> CursorOwner<'a> {
149///   let c: lmdb::Cursor<'a, 'a> = c;
150///   CursorOwner { cursor: c }
151/// }
152/// ```
153///
154/// Note that an `&mut Cursor<'txn,'db>` is naturally _invariant_ on both
155/// lifetimes. This means that structures containing `&mut Cursor` or functions
156/// taking them as references should generally include both.
157///
158/// ```rust,norun
159/// # #![allow(dead_code)]
160/// # extern crate lmdb_zero as lmdb;
161/// # fn main() { }
162/// #
163/// // Write this
164/// fn do_stuff_with_cursor<'txn, 'db>(c: &mut lmdb::Cursor<'txn,'db>) {
165///   // Stuff
166/// }
167/// // Not this
168/// fn do_stuff_with_cursor_2<'a>(c: &mut lmdb::Cursor<'a,'a>) {
169///   // Stuff
170/// }
171/// ```
172///
173/// Attempting to unify the lifetimes on a `&mut Cursor` will often work, but
174/// can also cause the compiler to infer lifetimes in unfavourable ways.
175#[derive(Debug)]
176pub struct Cursor<'txn,'db> {
177    cursor: CursorHandle,
178    txn: NonSyncSupercow<'txn, ConstTransaction<'txn>>,
179    _db: Phantomcow<'db, Database<'db>>,
180}
181
182// Used by transactions to construct/query cursors
183pub unsafe fn create_cursor<'txn, 'db>(
184    raw: *mut ffi::MDB_cursor,
185    txn: NonSyncSupercow<'txn, ConstTransaction<'txn>>,
186    db: Phantomcow<'db, Database<'db>>)
187    -> Cursor<'txn, 'db>
188{
189    Cursor {
190        cursor: CursorHandle(raw),
191        txn: txn,
192        _db: db,
193    }
194}
195pub fn txn_ref<'a,'txn: 'a,'db>(cursor: &'a Cursor<'txn,'db>)
196                                -> &'a ConstTransaction<'txn> {
197    &*cursor.txn
198}
199
200/// A read-only cursor which has been dissociated from its original
201/// transaction, so that it can be rebound later.
202///
203/// A `StaleCursor` remains bound to the original database.
204#[derive(Debug)]
205pub struct StaleCursor<'db> {
206    cursor: CursorHandle,
207    env: NonSyncSupercow<'db, Environment>,
208    _db: Phantomcow<'db, Database<'db>>,
209}
210
211// Internal
212pub fn to_stale<'a,'db>(cursor: Cursor<'a,'db>,
213                        env: NonSyncSupercow<'db, Environment>)
214                        -> StaleCursor<'db> {
215    StaleCursor {
216        cursor: cursor.cursor,
217        env: env,
218        _db: cursor._db,
219    }
220}
221pub fn env_ref<'a,'db>(cursor: &'a StaleCursor<'db>)
222                       -> &'a Environment {
223    &*cursor.env
224}
225pub fn stale_cursor_ptr<'db>(cursor: &StaleCursor<'db>)
226                             -> *mut ffi::MDB_cursor {
227    cursor.cursor.0
228}
229
230macro_rules! cursor_get_0_kv {
231    ($(#[$doc:meta])* fn $method:ident, $op:path) => {
232        $(#[$doc])*
233        #[inline]
234        pub fn $method<'access, K : FromLmdbBytes + ?Sized,
235                       V : FromLmdbBytes + ?Sized>
236            (&mut self, access: &'access ConstAccessor)
237             -> Result<(&'access K, &'access V)>
238        {
239            self.get_0_kv(access, $op)
240        }
241    }
242}
243
244macro_rules! cursor_get_0_v {
245    ($(#[$doc:meta])* fn $method:ident, $op:path) => {
246        $(#[$doc])*
247        #[inline]
248        pub fn $method<'access, V : FromLmdbBytes + ?Sized>
249            (&mut self, access: &'access ConstAccessor)
250             -> Result<(&'access V)>
251        {
252            self.get_0_v(access, $op)
253        }
254    }
255}
256
257impl<'txn,'db> Cursor<'txn,'db> {
258    /// Directly construct a cursor with the given transaction and database
259    /// handles.
260    ///
261    /// This is a low-level function intended only for use by implementations
262    /// of the `CreateCursor` trait. (There is nothing less safe about it being
263    /// low-level; it's simply inconvenient.)
264    pub fn construct(
265        txn: NonSyncSupercow<'txn, ConstTransaction<'txn>>,
266        db: Supercow<'db, Database<'db>>)
267        -> Result<Self>
268    {
269        try!(tx::assert_same_env(&txn, &db));
270
271        let mut raw: *mut ffi::MDB_cursor = ptr::null_mut();
272        unsafe {
273            lmdb_call!(ffi::mdb_cursor_open(tx::txptr(&txn), db.as_raw(),
274                                            &mut raw));
275        }
276
277        Ok(unsafe { create_cursor(raw, txn,
278                                  Supercow::phantom(db)) })
279    }
280
281    /// Directly renew a `StaleCursor` into a functional `Cursor` using the
282    /// given database handle.
283    ///
284    /// This is a low-level function intended only for use by implementations
285    /// of the `AssocCursor` trait. (There is nothing less safe about it being
286    /// low-level; it's simply inconvenient.)
287    ///
288    /// It is an error if `txn` is not actually a `ReadTransaction`.
289    pub fn from_stale(
290        stale: StaleCursor<'db>,
291        txn: NonSyncSupercow<'txn, ConstTransaction<'txn>>)
292        -> Result<Self>
293    {
294        try!(tx::assert_in_env(&txn, env_ref(&stale)));
295
296        unsafe {
297            lmdb_call!(ffi::mdb_cursor_renew(
298                tx::txptr(&txn), stale_cursor_ptr(&stale)));
299        }
300
301        Ok(Cursor {
302            cursor: stale.cursor,
303            txn: txn,
304            _db: stale._db,
305        })
306    }
307
308    #[inline]
309    fn get_0_kv<'access, K : FromLmdbBytes + ?Sized,
310                V : FromLmdbBytes + ?Sized>
311        (&mut self, access: &'access ConstAccessor,
312         op: ffi::MDB_cursor_op) -> Result<(&'access K, &'access V)>
313    {
314        try!(assert_sensible_cursor(access, self));
315
316        let mut out_key = EMPTY_VAL;
317        let mut out_val = EMPTY_VAL;
318        unsafe {
319            lmdb_call!(ffi::mdb_cursor_get(
320                self.cursor.0, &mut out_key, &mut out_val, op));
321        }
322
323        Ok((try!(from_val(access, &out_key)),
324            try!(from_val(access, &out_val))))
325    }
326
327    #[inline]
328    fn get_0_v<'access, V : FromLmdbBytes + ?Sized>
329        (&mut self, access: &'access ConstAccessor,
330         op: ffi::MDB_cursor_op) -> Result<&'access V>
331    {
332        try!(assert_sensible_cursor(access, self));
333
334        let mut null_key = EMPTY_VAL;
335        let mut out_val = EMPTY_VAL;
336        unsafe {
337            lmdb_call!(ffi::mdb_cursor_get(
338                self.cursor.0, &mut null_key, &mut out_val, op));
339        }
340
341        from_val(access, &out_val)
342    }
343
344    #[inline]
345    fn get_kv_0<K: AsLmdbBytes + ?Sized, V : AsLmdbBytes + ?Sized>
346        (&mut self, key: &K, val: &V, op: ffi::MDB_cursor_op) -> Result<()>
347    {
348        let mut mv_key = as_val(key);
349        let mut mv_val = as_val(val);
350        unsafe {
351            lmdb_call!(ffi::mdb_cursor_get(
352                self.cursor.0, &mut mv_key, &mut mv_val, op));
353        }
354
355        Ok(())
356    }
357
358    #[inline]
359    fn get_kv_v<'access, K : AsLmdbBytes + ?Sized,
360                V : AsLmdbBytes + FromLmdbBytes + ?Sized>
361        (&mut self, access: &'access ConstAccessor,
362         key: &K, val: &V, op: ffi::MDB_cursor_op) -> Result<&'access V>
363    {
364        try!(assert_sensible_cursor(access, self));
365
366        let mut mv_key = as_val(key);
367        let mut inout_val = as_val(val);
368
369        unsafe {
370            lmdb_call!(ffi::mdb_cursor_get(
371                self.cursor.0, &mut mv_key, &mut inout_val, op));
372        }
373
374        from_val(access, &inout_val)
375    }
376
377    #[inline]
378    fn get_k_v<'access, K : AsLmdbBytes + ?Sized,
379               V : FromLmdbBytes + ?Sized>
380        (&mut self, access: &'access ConstAccessor,
381         key: &K, op: ffi::MDB_cursor_op) -> Result<&'access V>
382    {
383        try!(assert_sensible_cursor(access, self));
384
385        let mut mv_key = as_val(key);
386        let mut out_val = EMPTY_VAL;
387
388        unsafe {
389            lmdb_call!(ffi::mdb_cursor_get(
390                self.cursor.0, &mut mv_key, &mut out_val, op));
391        }
392
393        from_val(access, &out_val)
394    }
395
396    #[inline]
397    fn get_k_kv<'access, K : AsLmdbBytes + FromLmdbBytes + ?Sized,
398                V : FromLmdbBytes + ?Sized>
399        (&mut self, access: &'access ConstAccessor,
400         key: &K, op: ffi::MDB_cursor_op) -> Result<(&'access K, &'access V)>
401    {
402        try!(assert_sensible_cursor(access, self));
403
404        let mut inout_key = as_val(key);
405        let mut out_val = EMPTY_VAL;
406
407        unsafe {
408            lmdb_call!(ffi::mdb_cursor_get(
409                self.cursor.0, &mut inout_key, &mut out_val, op));
410        }
411
412        Ok((try!(from_val(access, &inout_key)),
413            try!(from_val(access, &out_val))))
414    }
415
416    cursor_get_0_kv! {
417        /// Positions the cursor at the first key/value pair in the database
418        /// and returns that pair.
419        ///
420        /// This corresponds to the `mdb_cursor_get` function with the
421        /// `MDB_FIRST` operation.
422        ///
423        /// ## Example
424        ///
425        /// ```
426        /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
427        /// # fn main() {
428        /// # let env = create_env();
429        /// # let db = dupdb(&env);
430        /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
431        /// {
432        ///   let mut access = txn.access();
433        ///   let f = lmdb::put::Flags::empty();
434        ///   access.put(&db, "Germany", "Berlin", f).unwrap();
435        ///   access.put(&db, "France", "Paris", f).unwrap();
436        ///   access.put(&db, "Latvia", "Rīga", f).unwrap();
437        ///
438        ///   let mut cursor = txn.cursor(&db).unwrap();
439        ///   assert_eq!(("France", "Paris"), cursor.first(&access).unwrap());
440        /// }
441        /// txn.commit().unwrap();
442        /// # }
443        /// ```
444        fn first, ffi::MDB_cursor_op::MDB_FIRST
445    }
446
447    cursor_get_0_v! {
448        /// Positions the cursor at the first key/value pair whose key is equal
449        /// to the current key, returning the value of that pair.
450        ///
451        /// This only makes sense on `DUPSORT` databases.
452        ///
453        /// This correspnods to the `mdb_cursor_get` function with the
454        /// `MDB_FIRST_DUP` operation.
455        ///
456        /// ## Example
457        ///
458        /// ```
459        /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
460        /// # fn main() {
461        /// # let env = create_env();
462        /// # let db = dupdb(&env);
463        /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
464        /// {
465        ///   let mut access = txn.access();
466        ///   let f = lmdb::put::Flags::empty();
467        ///   access.put(&db, "Fruit", "Apple", f).unwrap();
468        ///   access.put(&db, "Fruit", "Orange", f).unwrap();
469        ///   access.put(&db, "Fruit", "Durian", f).unwrap();
470        ///   access.put(&db, "Animal", "Badger", f).unwrap();
471        ///
472        ///   let mut cursor = txn.cursor(&db).unwrap();
473        ///   assert_eq!(("Fruit", "Orange"), cursor.last(&access).unwrap());
474        ///   assert_eq!("Apple", cursor.first_dup::<str>(&access).unwrap());
475        /// }
476        /// txn.commit().unwrap();
477        /// # }
478        /// ```
479        fn first_dup, ffi::MDB_cursor_op::MDB_FIRST_DUP
480    }
481
482    /// Positions the cursor at the given (key,value) pair.
483    ///
484    /// This only makes sense on `DUPSORT` databases.
485    ///
486    /// This corresponds to the `mdb_cursor_get` function with the
487    /// `MDB_GET_BOTH` operation.
488    ///
489    /// ## Example
490    ///
491    /// ```
492    /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
493    /// # fn main() {
494    /// # let env = create_env();
495    /// # let db = dupdb(&env);
496    /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
497    /// {
498    ///   let mut access = txn.access();
499    ///   let f = lmdb::put::Flags::empty();
500    ///   access.put(&db, "Fruit", "Apple", f).unwrap();
501    ///   access.put(&db, "Fruit", "Orange", f).unwrap();
502    ///   access.put(&db, "Fruit", "Durian", f).unwrap();
503    ///   access.put(&db, "Animal", "Badger", f).unwrap();
504    ///
505    ///   let mut cursor = txn.cursor(&db).unwrap();
506    ///   cursor.seek_kv("Fruit", "Durian").unwrap();
507    ///   assert_eq!(("Fruit", "Orange"), cursor.next(&access).unwrap());
508    ///   assert!(cursor.seek_kv("Fruit", "Lychee").is_err());
509    /// }
510    /// txn.commit().unwrap();
511    /// # }
512    /// ```
513    #[inline]
514    pub fn seek_kv<K : AsLmdbBytes + ?Sized, V : AsLmdbBytes + ?Sized>
515        (&mut self, key: &K, val: &V) -> Result<()>
516    {
517        self.get_kv_0(key, val, ffi::MDB_cursor_op::MDB_GET_BOTH)
518    }
519
520    /// Positions the cursor at the given key and the "nearest" value to `val`,
521    /// that is, the first (according to sorting) item whose key equals `key`
522    /// and whose value is greater than or equal to `val`.
523    ///
524    /// The actual value found is returned.
525    ///
526    /// This only makes sense on `DUPSORT` databases.
527    ///
528    /// This corresponds to the `mdb_cursor_get` function with the
529    /// `MDB_GET_BOTH_RANGE` operation.
530    ///
531    /// ## Example
532    ///
533    /// ```
534    /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
535    /// # fn main() {
536    /// # let env = create_env();
537    /// # let db = dupdb(&env);
538    /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
539    /// {
540    ///   let mut access = txn.access();
541    ///   let f = lmdb::put::Flags::empty();
542    ///   access.put(&db, "Animal", "Badger", f).unwrap();
543    ///   access.put(&db, "Fruit", "Banana", f).unwrap();
544    ///   access.put(&db, "Fruit", "Orange", f).unwrap();
545    ///   access.put(&db, "Fruit", "Durian", f).unwrap();
546    ///   access.put(&db, "Veggie", "Carrot", f).unwrap();
547    ///
548    ///   let mut cursor = txn.cursor(&db).unwrap();
549    ///   assert_eq!("Durian", cursor.seek_k_nearest_v::<str,str>(
550    ///     &access, "Fruit", "Durian").unwrap());
551    ///   assert_eq!("Orange", cursor.seek_k_nearest_v::<str,str>(
552    ///     &access, "Fruit", "Lychee").unwrap());
553    ///   assert!(cursor.seek_k_nearest_v::<str,str>(
554    ///     &access, "Fruit", "Watermelon").is_err());
555    ///   assert_eq!("Banana", cursor.seek_k_nearest_v::<str,str>(
556    ///     &access, "Fruit", "Apple").unwrap());
557    ///   assert!(cursor.seek_k_nearest_v::<str,str>(
558    ///     &access, "Plant", "Tree").is_err());
559    /// }
560    /// txn.commit().unwrap();
561    /// # }
562    /// ```
563    #[inline]
564    pub fn seek_k_nearest_v<'access, K : AsLmdbBytes + ?Sized,
565                            V : AsLmdbBytes + FromLmdbBytes + ?Sized>
566        (&mut self, access: &'access ConstAccessor,
567         key: &K, val: &V) -> Result<&'access V>
568    {
569        self.get_kv_v(access, key, val, ffi::MDB_cursor_op::MDB_GET_BOTH_RANGE)
570    }
571
572    cursor_get_0_kv! {
573        /// Returns the current key/value pair under this cursor.
574        ///
575        /// This corresponds to the `mdb_cursor_get` function with the
576        /// `MDB_CURRENT` operation.
577        ///
578        /// ## Example
579        ///
580        /// ```
581        /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
582        /// # fn main() {
583        /// # let env = create_env();
584        /// # let db = dupdb(&env);
585        /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
586        /// {
587        ///   let mut access = txn.access();
588        ///   let f = lmdb::put::Flags::empty();
589        ///   access.put(&db, "Germany", "Berlin", f).unwrap();
590        ///   access.put(&db, "France", "Paris", f).unwrap();
591        ///   access.put(&db, "Latvia", "Rīga", f).unwrap();
592        ///
593        ///   let mut cursor = txn.cursor(&db).unwrap();
594        ///   cursor.seek_k::<str,str>(&access, "Latvia").unwrap();
595        ///   assert_eq!(("Latvia", "Rīga"), cursor.get_current(&access).unwrap());
596        /// }
597        /// txn.commit().unwrap();
598        /// # }
599        /// ```
600        fn get_current, ffi::MDB_cursor_op::MDB_GET_CURRENT
601    }
602
603    /// Returns as many items as possible with the current key from the
604    /// current cursor position.
605    ///
606    /// The cursor is advanced so that `next_multiple()` returns the next
607    /// group of items, if any. Note that this does _not_ return the actual
608    /// key (which LMDB itself does not return, contrary to documentation).
609    ///
610    /// The easiest way to use this is for `V` to be a slice of `LmdbRaw`
611    /// types.
612    ///
613    /// This only makes sense on `DUPSORT` databases with `DUPFIXED` set.
614    ///
615    /// This corresponds to the `mdb_cursor_get` function with the
616    /// `MDB_GET_MULTIPLE` operation, except that it does not have a special
617    /// case if exactly one value is bound to the key.
618    ///
619    /// See `lmdb_zero::db::DUPFIXED` for examples of usage.
620    #[inline]
621    pub fn get_multiple<'access, V : FromLmdbBytes + ?Sized>
622        (&mut self, access: &'access ConstAccessor)
623         -> Result<(&'access V)>
624    {
625        try!(assert_sensible_cursor(access, self));
626
627        let mut null_key = EMPTY_VAL;
628        let mut out_val = EMPTY_VAL;
629        unsafe {
630            lmdb_call!(ffi::mdb_cursor_get(
631                self.cursor.0, &mut null_key, &mut out_val,
632                ffi::MDB_cursor_op::MDB_GET_MULTIPLE));
633        }
634
635        if out_val.mv_data.is_null() {
636            // LMDB seemingly intentionally returns SUCCESS but a NULL data
637            // pointer if there's exactly one element.
638            // https://github.com/LMDB/lmdb/blob/0a2622317f189c7062d03d050be6766586a548b2/libraries/liblmdb/mdb.c#L7228
639            // Presumably it has something to do with the fact that single
640            // values are stored differently than dup values, though it's
641            // unclear why it doesn't do what we do here. If we see this
642            // condition, simply fall back to MDB_GET_CURRENT which doesn't
643            // modify the cursor, so the caller's follow-up call to
644            // next_multiple() will still be sound.
645            unsafe {
646                lmdb_call!(ffi::mdb_cursor_get(
647                    self.cursor.0, &mut null_key, &mut out_val,
648                    ffi::MDB_cursor_op::MDB_GET_CURRENT));
649            }
650        }
651
652        from_val(access, &out_val)
653
654    }
655
656    cursor_get_0_v! {
657        /// Continues fetching items from a cursor positioned by a call to
658        /// `get_multiple()`.
659        ///
660        /// This corresponds to the `mdb_cursor_get` function with the
661        /// `MDB_NEXT_MULTIPLE` operation.
662        ///
663        /// See `lmdb_zero::db::DUPFIXED` for examples of usage.
664        fn next_multiple, ffi::MDB_cursor_op::MDB_NEXT_MULTIPLE
665    }
666
667    cursor_get_0_kv! {
668        /// Positions the cursor at the last key/value pair in the database,
669        /// and returns that pair.
670        ///
671        /// This corresponds to the `mdb_cursor_get` function with the
672        /// `MDB_LAST` operation.
673        ///
674        /// ## Example
675        ///
676        /// ```
677        /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
678        /// # fn main() {
679        /// # let env = create_env();
680        /// # let db = dupdb(&env);
681        /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
682        /// {
683        ///   let mut access = txn.access();
684        ///   let f = lmdb::put::Flags::empty();
685        ///   access.put(&db, "Germany", "Berlin", f).unwrap();
686        ///   access.put(&db, "France", "Paris", f).unwrap();
687        ///   access.put(&db, "Latvia", "Rīga", f).unwrap();
688        ///
689        ///   let mut cursor = txn.cursor(&db).unwrap();
690        ///   assert_eq!(("Latvia", "Rīga"), cursor.last(&access).unwrap());
691        /// }
692        /// txn.commit().unwrap();
693        /// # }
694        /// ```
695        fn last, ffi::MDB_cursor_op::MDB_LAST
696    }
697
698    cursor_get_0_v! {
699        /// Positions the cursor at the last key/value pair whose key is equal
700        /// to the current key.
701        ///
702        /// This only makes sense on `DUPSORT` databases.
703        ///
704        /// This correspnods to the `mdb_cursor_get` function with the
705        /// `MDB_LAST_DUP` operation.
706        ///
707        /// ## Example
708        ///
709        /// ```
710        /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
711        /// # fn main() {
712        /// # let env = create_env();
713        /// # let db = dupdb(&env);
714        /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
715        /// {
716        ///   let mut access = txn.access();
717        ///   let f = lmdb::put::Flags::empty();
718        ///   access.put(&db, "Fruit", "Apple", f).unwrap();
719        ///   access.put(&db, "Fruit", "Orange", f).unwrap();
720        ///   access.put(&db, "Fruit", "Durian", f).unwrap();
721        ///   access.put(&db, "Animal", "Badger", f).unwrap();
722        ///   access.put(&db, "Veggie", "Carrot", f).unwrap();
723        ///
724        ///   let mut cursor = txn.cursor(&db).unwrap();
725        ///   assert_eq!("Apple", cursor.seek_k::<str,str>(&access, "Fruit").unwrap());
726        ///   assert_eq!("Orange", cursor.last_dup::<str>(&access).unwrap());
727        /// }
728        /// txn.commit().unwrap();
729        /// # }
730        /// ```
731        fn last_dup, ffi::MDB_cursor_op::MDB_LAST_DUP
732    }
733
734    cursor_get_0_kv! {
735        /// Advances the cursor to the key/value pair following this one.
736        ///
737        /// If the current key has multiple values, this will remain on the
738        /// same key unless it is already on the last value.
739        ///
740        /// This corresponds to the `mdb_cursor_get` function with the
741        /// `MDB_NEXT` operation.
742        ///
743        /// ## Example
744        ///
745        /// ```
746        /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
747        /// # fn main() {
748        /// # let env = create_env();
749        /// # let db = dupdb(&env);
750        /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
751        /// {
752        ///   let mut access = txn.access();
753        ///   let f = lmdb::put::Flags::empty();
754        ///   access.put(&db, "Fruit", "Apple", f).unwrap();
755        ///   access.put(&db, "Fruit", "Orange", f).unwrap();
756        ///   access.put(&db, "Animal", "Badger", f).unwrap();
757        ///   access.put(&db, "Veggie", "Carrot", f).unwrap();
758        ///
759        ///   let mut cursor = txn.cursor(&db).unwrap();
760        ///   assert_eq!(("Animal", "Badger"), cursor.first(&access).unwrap());
761        ///   assert_eq!(("Fruit", "Apple"), cursor.next(&access).unwrap());
762        ///   assert_eq!(("Fruit", "Orange"), cursor.next(&access).unwrap());
763        ///   assert_eq!(("Veggie", "Carrot"), cursor.next(&access).unwrap());
764        ///   assert!(cursor.next::<str,str>(&access).is_err());
765        /// }
766        /// txn.commit().unwrap();
767        /// # }
768        /// ```
769        fn next, ffi::MDB_cursor_op::MDB_NEXT
770    }
771
772    cursor_get_0_kv! {
773        /// Advances the cursor to the next value in the current key.
774        ///
775        /// This only makes sense on `DUPSORT` databases. This call fails if
776        /// there are no more values in the current key.
777        ///
778        /// This corresponds to the `mdb_cursor_get` function with the
779        /// `MDB_NEXT_DUP` operation.
780        ///
781        /// ## Example
782        ///
783        /// ```
784        /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
785        /// # fn main() {
786        /// # let env = create_env();
787        /// # let db = dupdb(&env);
788        /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
789        /// {
790        ///   let mut access = txn.access();
791        ///   let f = lmdb::put::Flags::empty();
792        ///   access.put(&db, "Fruit", "Apple", f).unwrap();
793        ///   access.put(&db, "Fruit", "Orange", f).unwrap();
794        ///   access.put(&db, "Animal", "Badger", f).unwrap();
795        ///   access.put(&db, "Veggie", "Carrot", f).unwrap();
796        ///
797        ///   let mut cursor = txn.cursor(&db).unwrap();
798        ///   assert_eq!("Apple", cursor.seek_k::<str,str>(&access, "Fruit").unwrap());
799        ///   assert_eq!(("Fruit", "Orange"), cursor.next_dup(&access).unwrap());
800        ///   assert!(cursor.next_dup::<str,str>(&access).is_err());
801        /// }
802        /// txn.commit().unwrap();
803        /// # }
804        /// ```
805        fn next_dup, ffi::MDB_cursor_op::MDB_NEXT_DUP
806    }
807
808    cursor_get_0_kv! {
809        /// Advances the cursor to the first item of the key following the
810        /// current key.
811        ///
812        /// This is permitted in all databases, but only behaves distinctly
813        /// from `next()` in `DUPSORT` databases.
814        ///
815        /// This corresponds to the `mdb_cursor_get` function with the
816        /// `MDB_NEXT_NODUP` operation.
817        ///
818        /// ## Example
819        ///
820        /// ```
821        /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
822        /// # fn main() {
823        /// # let env = create_env();
824        /// # let db = dupdb(&env);
825        /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
826        /// {
827        ///   let mut access = txn.access();
828        ///   let f = lmdb::put::Flags::empty();
829        ///   access.put(&db, "Fruit", "Apple", f).unwrap();
830        ///   access.put(&db, "Fruit", "Orange", f).unwrap();
831        ///   access.put(&db, "Animal", "Badger", f).unwrap();
832        ///   access.put(&db, "Veggie", "Carrot", f).unwrap();
833        ///
834        ///   let mut cursor = txn.cursor(&db).unwrap();
835        ///   assert_eq!(("Animal", "Badger"), cursor.first(&access).unwrap());
836        ///   assert_eq!(("Fruit", "Apple"), cursor.next_nodup(&access).unwrap());
837        ///   assert_eq!(("Veggie", "Carrot"), cursor.next_nodup(&access).unwrap());
838        ///   assert!(cursor.next_nodup::<str,str>(&access).is_err());
839        /// }
840        /// txn.commit().unwrap();
841        /// # }
842        /// ```
843        fn next_nodup, ffi::MDB_cursor_op::MDB_NEXT_NODUP
844    }
845
846    cursor_get_0_kv! {
847        /// Retreats the cursor to the previous key/value pair.
848        ///
849        /// If the current key has multiple values, this will remain on the
850        /// same key unless it is already on the first value.
851        ///
852        /// This corresponds to the `mdb_cursor_get` function with the
853        /// `MDB_PREV` operation.
854        ///
855        /// ## Example
856        ///
857        /// ```
858        /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
859        /// # fn main() {
860        /// # let env = create_env();
861        /// # let db = dupdb(&env);
862        /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
863        /// {
864        ///   let mut access = txn.access();
865        ///   let f = lmdb::put::Flags::empty();
866        ///   access.put(&db, "Fruit", "Apple", f).unwrap();
867        ///   access.put(&db, "Fruit", "Orange", f).unwrap();
868        ///   access.put(&db, "Animal", "Badger", f).unwrap();
869        ///   access.put(&db, "Veggie", "Carrot", f).unwrap();
870        ///
871        ///   let mut cursor = txn.cursor(&db).unwrap();
872        ///   assert_eq!(("Veggie", "Carrot"), cursor.last(&access).unwrap());
873        ///   assert_eq!(("Fruit", "Orange"), cursor.prev(&access).unwrap());
874        ///   assert_eq!(("Fruit", "Apple"), cursor.prev(&access).unwrap());
875        ///   assert_eq!(("Animal", "Badger"), cursor.prev(&access).unwrap());
876        ///   assert!(cursor.prev::<str,str>(&access).is_err());
877        /// }
878        /// txn.commit().unwrap();
879        /// # }
880        /// ```
881        fn prev, ffi::MDB_cursor_op::MDB_PREV
882    }
883
884    cursor_get_0_kv! {
885        /// Retreats the cursor to the previous value in the current key.
886        ///
887        /// This only makes sense on `DUPSORT` databases. This call fails if
888        /// there are no prior values in the current key.
889        ///
890        /// This corresponds to the `mdb_cursor_get` function with the
891        /// `MDB_PREV_DUP` operation.
892        ///
893        /// ## Example
894        ///
895        /// ```
896        /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
897        /// # fn main() {
898        /// # let env = create_env();
899        /// # let db = dupdb(&env);
900        /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
901        /// {
902        ///   let mut access = txn.access();
903        ///   let f = lmdb::put::Flags::empty();
904        ///   access.put(&db, "Fruit", "Apple", f).unwrap();
905        ///   access.put(&db, "Fruit", "Orange", f).unwrap();
906        ///   access.put(&db, "Animal", "Badger", f).unwrap();
907        ///   access.put(&db, "Veggie", "Carrot", f).unwrap();
908        ///
909        ///   let mut cursor = txn.cursor(&db).unwrap();
910        ///   assert_eq!("Apple", cursor.seek_k::<str,str>(&access, "Fruit").unwrap());
911        ///   assert_eq!(("Fruit", "Orange"), cursor.next_dup(&access).unwrap());
912        ///   assert_eq!(("Fruit", "Apple"), cursor.prev_dup(&access).unwrap());
913        ///   assert!(cursor.prev_dup::<str,str>(&access).is_err());
914        /// }
915        /// txn.commit().unwrap();
916        /// # }
917        /// ```
918        fn prev_dup, ffi::MDB_cursor_op::MDB_PREV_DUP
919    }
920
921    cursor_get_0_kv! {
922        /// Retreats the cursor to the final item of the previous key.
923        ///
924        /// This is permitted in all databases, but only behaves distinctly
925        /// from `prev()` in `DUPSORT` databases.
926        ///
927        /// This corresponds to the `mdb_cursor_get` function with the
928        /// `MDB_PREV_NODUP` operation.
929        ///
930        /// ## Example
931        ///
932        /// ```
933        /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
934        /// # fn main() {
935        /// # let env = create_env();
936        /// # let db = dupdb(&env);
937        /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
938        /// {
939        ///   let mut access = txn.access();
940        ///   let f = lmdb::put::Flags::empty();
941        ///   access.put(&db, "Fruit", "Apple", f).unwrap();
942        ///   access.put(&db, "Fruit", "Orange", f).unwrap();
943        ///   access.put(&db, "Animal", "Badger", f).unwrap();
944        ///   access.put(&db, "Veggie", "Carrot", f).unwrap();
945        ///
946        ///   let mut cursor = txn.cursor(&db).unwrap();
947        ///   assert_eq!(("Veggie", "Carrot"), cursor.last(&access).unwrap());
948        ///   assert_eq!(("Fruit", "Orange"), cursor.prev_nodup(&access).unwrap());
949        ///   assert_eq!(("Animal", "Badger"), cursor.prev_nodup(&access).unwrap());
950        ///   assert!(cursor.prev_nodup::<str,str>(&access).is_err());
951        /// }
952        /// txn.commit().unwrap();
953        /// # }
954        /// ```
955        fn prev_nodup, ffi::MDB_cursor_op::MDB_PREV_NODUP
956    }
957
958    /// Positions the cursor at the first item of the given key.
959    ///
960    /// Returns the value of that item.
961    ///
962    /// This corresponds to the `mdb_cursor_get` function with the `MDB_SET`
963    /// operation.
964    ///
965    /// ## Example
966    ///
967    /// ```
968    /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
969    /// # fn main() {
970    /// # let env = create_env();
971    /// # let db = dupdb(&env);
972    /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
973    /// {
974    ///   let mut access = txn.access();
975    ///   let f = lmdb::put::Flags::empty();
976    ///   access.put(&db, "Fruit", "Apple", f).unwrap();
977    ///   access.put(&db, "Fruit", "Orange", f).unwrap();
978    ///   access.put(&db, "Animal", "Badger", f).unwrap();
979    ///   access.put(&db, "Veggie", "Carrot", f).unwrap();
980    ///
981    ///   let mut cursor = txn.cursor(&db).unwrap();
982    ///   assert_eq!("Apple", cursor.seek_k::<str,str>(&access, "Fruit").unwrap());
983    /// }
984    /// txn.commit().unwrap();
985    /// # }
986    /// ```
987    #[inline]
988    pub fn seek_k<'access, K : AsLmdbBytes + ?Sized,
989                  V : FromLmdbBytes + ?Sized>
990        (&mut self, access: &'access ConstAccessor, key: &K)
991        -> Result<&'access V>
992    {
993        self.get_k_v(access, key, ffi::MDB_cursor_op::MDB_SET)
994    }
995
996    /// Positions the cursor at the first item of the given key.
997    ///
998    /// Returns the key and value of that item.
999    ///
1000    /// This corresponds to the `mdb_cursor_get` function with the
1001    /// `MDB_SET_KEY` operation.
1002    ///
1003    /// ## Example
1004    ///
1005    /// ```
1006    /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
1007    /// # fn main() {
1008    /// # let env = create_env();
1009    /// # let db = dupdb(&env);
1010    /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
1011    /// {
1012    ///   let mut access = txn.access();
1013    ///   let f = lmdb::put::Flags::empty();
1014    ///   access.put(&db, "Fruit", "Apple", f).unwrap();
1015    ///   access.put(&db, "Fruit", "Orange", f).unwrap();
1016    ///   access.put(&db, "Animal", "Badger", f).unwrap();
1017    ///   access.put(&db, "Veggie", "Carrot", f).unwrap();
1018    ///
1019    ///   let mut cursor = txn.cursor(&db).unwrap();
1020    ///   assert_eq!(("Fruit", "Apple"), cursor.seek_k_both(&access, "Fruit").unwrap());
1021    /// }
1022    /// txn.commit().unwrap();
1023    /// # }
1024    /// ```
1025    #[inline]
1026    pub fn seek_k_both<'access, K : AsLmdbBytes + FromLmdbBytes + ?Sized,
1027                       V : FromLmdbBytes + ?Sized>
1028        (&mut self, access: &'access ConstAccessor, key: &K)
1029         -> Result<(&'access K, &'access V)>
1030    {
1031        self.get_k_kv(access, key, ffi::MDB_cursor_op::MDB_SET_KEY)
1032    }
1033
1034    /// Positions the cursor at the first item whose key is greater than or
1035    /// equal to `key`.
1036    ///
1037    /// Return the key and value of that item.
1038    ///
1039    /// This corresponds to the `mdb_cursor_get` function with the
1040    /// `MDB_SET_RANGE` operation.
1041    ///
1042    /// ## Example
1043    ///
1044    /// ```
1045    /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
1046    /// # fn main() {
1047    /// # let env = create_env();
1048    /// # let db = dupdb(&env);
1049    /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
1050    /// {
1051    ///   let mut access = txn.access();
1052    ///   let f = lmdb::put::Flags::empty();
1053    ///   access.put(&db, "Fruit", "Apple", f).unwrap();
1054    ///   access.put(&db, "Fruit", "Orange", f).unwrap();
1055    ///   access.put(&db, "Animal", "Badger", f).unwrap();
1056    ///
1057    ///   let mut cursor = txn.cursor(&db).unwrap();
1058    ///   assert_eq!(("Fruit", "Apple"), cursor.seek_range_k(&access, "Fog").unwrap());
1059    ///   assert!(cursor.seek_range_k::<str,str>(&access, "Veggie").is_err());
1060    /// }
1061    /// txn.commit().unwrap();
1062    /// # }
1063    /// ```
1064    #[inline]
1065    pub fn seek_range_k<'access, K : AsLmdbBytes + FromLmdbBytes + ?Sized,
1066                        V : FromLmdbBytes + ?Sized>
1067        (&mut self, access: &'access ConstAccessor, key: &K)
1068         -> Result<(&'access K, &'access V)>
1069    {
1070        self.get_k_kv(access, key, ffi::MDB_cursor_op::MDB_SET_RANGE)
1071    }
1072
1073    /// Writes a single value through this cursor.
1074    ///
1075    /// By default, any item with the same key (if not `DUPSORT`) or any
1076    /// exactly matching item (if `DUPSORT`) is replaced silently. `flags` can
1077    /// be used to override this.
1078    ///
1079    /// This does not inherently overwrite the current item. See `overwrite()`
1080    /// for that.
1081    ///
1082    /// The cursor is positioned at the new item, or on failure usually near
1083    /// it.
1084    ///
1085    /// ## Example
1086    ///
1087    /// ```
1088    /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
1089    /// # fn main() {
1090    /// # let env = create_env();
1091    /// # let db = dupdb(&env);
1092    /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
1093    /// {
1094    ///   let mut access = txn.access();
1095    ///   let f = lmdb::put::Flags::empty();
1096    ///   let mut cursor = txn.cursor(&db).unwrap();
1097    ///   cursor.put(&mut access, "Germany", "Berlin", f).unwrap();
1098    ///   assert_eq!(("Germany", "Berlin"), cursor.get_current(&access).unwrap());
1099    /// }
1100    /// txn.commit().unwrap();
1101    /// # }
1102    /// ```
1103    #[inline]
1104    pub fn put<K : AsLmdbBytes + ?Sized, V : AsLmdbBytes + ?Sized>
1105        (&mut self, access: &mut WriteAccessor,
1106         key: &K, val: &V, flags: put::Flags) -> Result<()>
1107    {
1108        try!(assert_sensible_cursor(&*access, self));
1109
1110        let mut mv_key = as_val(key);
1111        let mut mv_val = as_val(val);
1112
1113        unsafe {
1114            lmdb_call!(ffi::mdb_cursor_put(
1115                self.cursor.0, &mut mv_key, &mut mv_val,
1116                flags.bits()));
1117        }
1118
1119        Ok(())
1120    }
1121
1122    /// Overwrites the current item referenced by the cursor.
1123    ///
1124    /// `key` must match the key of the current item. If the database is
1125    /// `DUPSORT`, `val` must still sort into the same position relative to the
1126    /// other items with the same key.
1127    ///
1128    /// This is intended to be used when the new data is the same size as the
1129    /// old. Otherwise it will simply perform a delete of the old record
1130    /// followed by an insert.
1131    ///
1132    /// The cursor is positioned at the new item, or on failure usually near
1133    /// it.
1134    ///
1135    /// ## Example
1136    ///
1137    /// ```
1138    /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
1139    /// # fn main() {
1140    /// # let env = create_env();
1141    /// # let db = defdb(&env);
1142    /// use lmdb::unaligned as u;
1143    ///
1144    /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
1145    /// {
1146    ///   let mut access = txn.access();
1147    ///   let f = lmdb::put::Flags::empty();
1148    ///   let mut cursor = txn.cursor(&db).unwrap();
1149    ///   cursor.put(&mut access, "Fourty-two", &42u32, f).unwrap();
1150    ///   cursor.overwrite(&mut access, "Fourty-two", &54u32, f).unwrap();
1151    ///   assert_eq!(("Fourty-two", u(&54u32)),
1152    ///              cursor.get_current(&access).unwrap());
1153    /// }
1154    /// txn.commit().unwrap();
1155    /// # }
1156    /// ```
1157    #[inline]
1158    pub fn overwrite<K : AsLmdbBytes + ?Sized, V : AsLmdbBytes + ?Sized>
1159        (&mut self, access: &mut WriteAccessor,
1160         key: &K, val: &V, flags: put::Flags) -> Result<()>
1161    {
1162        try!(assert_sensible_cursor(&*access, self));
1163
1164        let mut mv_key = as_val(key);
1165        let mut mv_val = as_val(val);
1166
1167        unsafe {
1168            lmdb_call!(ffi::mdb_cursor_put(
1169                self.cursor.0, &mut mv_key, &mut mv_val,
1170                flags.bits() | ffi::MDB_CURRENT));
1171        }
1172
1173        Ok(())
1174    }
1175
1176    /// Reserves space for an entry with the given key and returns a pointer to
1177    /// that entry.
1178    ///
1179    /// The size of the entry is simply the size of `V`.
1180    ///
1181    /// This cannot be used on a `DUPSORT` database.
1182    ///
1183    /// The cursor is positioned at the new item, or on failure usually near
1184    /// it.
1185    ///
1186    /// ## Example
1187    ///
1188    /// ```
1189    /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
1190    /// #[repr(C, packed)]
1191    /// #[derive(Clone,Copy,Debug,PartialEq,Eq)]
1192    /// struct MyStruct {
1193    ///   x: i32,
1194    ///   y: i32,
1195    /// }
1196    /// unsafe impl lmdb::traits::LmdbRaw for MyStruct { }
1197    ///
1198    /// # fn main() {
1199    /// # let env = create_env();
1200    /// # let db = defdb(&env);
1201    /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
1202    /// {
1203    ///   let mut access = txn.access();
1204    ///   let f = lmdb::put::Flags::empty();
1205    ///   let mut cursor = txn.cursor(&db).unwrap();
1206    ///   {
1207    ///     let v: &mut MyStruct = cursor.reserve(&mut access, "foo", f).unwrap();
1208    ///     // Write directly into the database
1209    ///     v.x = 42;
1210    ///     v.y = 56;
1211    ///   }
1212    ///
1213    ///   assert_eq!(("foo", &MyStruct { x: 42, y: 56 }),
1214    ///              cursor.get_current(&access).unwrap());
1215    /// }
1216    /// txn.commit().unwrap();
1217    /// # }
1218    /// ```
1219    #[inline]
1220    pub fn reserve<'access, K : AsLmdbBytes + ?Sized,
1221                   V : FromReservedLmdbBytes + Sized>
1222        (&mut self, access: &'access mut WriteAccessor,
1223         key: &K, flags: put::Flags) -> Result<&'access mut V>
1224    {
1225        unsafe {
1226            self.reserve_unsized(access, key, mem::size_of::<V>(), flags)
1227        }
1228    }
1229
1230    /// Reserves space for an entry with the given key and returns a pointer to
1231    /// an array of values backing that entry.
1232    ///
1233    /// The size of the entry is simply the size of `V` times the desired
1234    /// number of elements.
1235    ///
1236    /// This cannot be used on a `DUPSORT` database. (Do not confuse with
1237    /// `put_multiple`, which does support `DUPSORT` but is not zero-copy.)
1238    ///
1239    /// The cursor is positioned at the new item, or on failure usually near
1240    /// it.
1241    ///
1242    /// ## Example
1243    ///
1244    /// ```
1245    /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
1246    /// #[repr(C, packed)]
1247    /// #[derive(Clone,Copy,Debug,PartialEq,Eq)]
1248    /// struct MyStruct {
1249    ///   x: i32,
1250    ///   y: i32,
1251    /// }
1252    /// unsafe impl lmdb::traits::LmdbRaw for MyStruct { }
1253    ///
1254    /// # fn main() {
1255    /// # let env = create_env();
1256    /// # let db = defdb(&env);
1257    /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
1258    /// {
1259    ///   let mut access = txn.access();
1260    ///   let f = lmdb::put::Flags::empty();
1261    ///   let mut cursor = txn.cursor(&db).unwrap();
1262    ///   {
1263    ///     let v: &mut [u8] = cursor.reserve_array(&mut access, "foo", 4, f).unwrap();
1264    ///     // Write directly into the database
1265    ///     v[0] = b'b'; v[1] = b'y'; v[2] = b't'; v[3] = b'e';
1266    ///   }
1267    ///
1268    ///   assert_eq!(("foo", "byte"), cursor.get_current(&access).unwrap());
1269    /// }
1270    /// txn.commit().unwrap();
1271    /// # }
1272    /// ```
1273    #[inline]
1274    pub fn reserve_array<'access, K : AsLmdbBytes + ?Sized,
1275                         V : LmdbRaw>
1276        (&mut self, access: &'access mut WriteAccessor,
1277         key: &K, count: usize, flags: put::Flags)
1278         -> Result<&'access mut [V]>
1279    {
1280        unsafe {
1281            self.reserve_unsized(
1282                access, key, count * mem::size_of::<V>(), flags)
1283        }
1284    }
1285
1286    /// Reserves space for an entry with the given key and returns a pointer to
1287    /// that entry.
1288    ///
1289    /// This cannot be used on a `DUPSORT` database.
1290    ///
1291    /// The cursor is positioned at the new item, or on failure usually near
1292    /// it.
1293    ///
1294    /// ## Unsafety
1295    ///
1296    /// The caller must ensure that `size` is a valid size for `V`.
1297    pub unsafe fn reserve_unsized<'access, K : AsLmdbBytes + ?Sized,
1298                                  V : FromReservedLmdbBytes + ?Sized>
1299        (&mut self, access: &'access mut WriteAccessor,
1300         key: &K, size: usize, flags: put::Flags) -> Result<&'access mut V>
1301    {
1302        try!(assert_sensible_cursor(&*access, self));
1303
1304        let mut mv_key = as_val(key);
1305        let mut out_val = EMPTY_VAL;
1306        out_val.mv_size = size;
1307
1308        lmdb_call!(ffi::mdb_cursor_put(
1309            self.cursor.0, &mut mv_key, &mut out_val,
1310            flags.bits() | ffi::MDB_RESERVE));
1311
1312        Ok(from_reserved(access, &out_val))
1313    }
1314
1315    /// Returns a writable reference to the value belonging to the given key in
1316    /// the database.
1317    ///
1318    /// This has all the caveats of both `overwrite()` and `reserve()`.
1319    ///
1320    /// ## Updating by mutation
1321    ///
1322    /// It is possible to use this call to perform a read-modify-write
1323    /// operation on the data in the database, provided you are certain that
1324    /// the value exists with the exact size of `V`, for example if you just
1325    /// read the value as a `V` using something that requires a particular size
1326    /// (such as `LmdbRaw`).
1327    ///
1328    /// ## Example
1329    ///
1330    /// ```
1331    /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
1332    /// # fn main() {
1333    /// # let env = create_env();
1334    /// # let db = defdb(&env);
1335    /// use lmdb::Unaligned as U;
1336    /// use lmdb::unaligned as u;
1337    ///
1338    /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
1339    /// {
1340    ///   let mut access = txn.access();
1341    ///   let f = lmdb::put::Flags::empty();
1342    ///   let mut cursor = txn.cursor(&db).unwrap();
1343    ///   cursor.put(&mut access, "count", &1u32, f).unwrap();
1344    ///   {
1345    ///     let count: &mut U<u32> = cursor.overwrite_in_place(
1346    ///       &mut access, "count", f).unwrap();
1347    ///     // Directly edit the value in the database
1348    ///     let count2 = count.get() + 1;
1349    ///     count.set(count2);
1350    ///   }
1351    ///   assert_eq!(("count", u(&2u32)), cursor.get_current(&access).unwrap());
1352    /// }
1353    /// txn.commit().unwrap();
1354    /// # }
1355    /// ```
1356    #[inline]
1357    pub fn overwrite_in_place<'access, K : AsLmdbBytes + ?Sized,
1358                              V : FromReservedLmdbBytes + Sized>
1359        (&mut self, access: &'access mut WriteAccessor,
1360         key: &K, flags: put::Flags) -> Result<&'access mut V>
1361    {
1362        unsafe {
1363            self.overwrite_in_place_unsized(
1364                access, key, mem::size_of::<V>(), flags)
1365        }
1366    }
1367
1368    /// Returns a writable reference to the array of values belonging to the
1369    /// given key in the database.
1370    ///
1371    /// This has all the caveats of both `overwrite()` and `reserve_array()`.
1372    ///
1373    /// ## Updating by mutation
1374    ///
1375    /// It is possible to use this call to perform a read-modify-write
1376    /// operation on the data in the database, provided you are certain that
1377    /// the value exists with the exact size of `V` times `count`.
1378    ///
1379    /// ## Example
1380    ///
1381    /// ```
1382    /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
1383    /// # fn main() {
1384    /// # let env = create_env();
1385    /// # let db = defdb(&env);
1386    /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
1387    /// {
1388    ///   let mut access = txn.access();
1389    ///   let f = lmdb::put::Flags::empty();
1390    ///   let mut cursor = txn.cursor(&db).unwrap();
1391    ///   cursor.put(&mut access, "foo", "bar", f).unwrap();
1392    ///   {
1393    ///     let data: &mut [u8] = cursor.overwrite_in_place_array(
1394    ///       &mut access, "foo", 3, f).unwrap();
1395    ///     // Directly edit the value in the database
1396    ///     data[2] = b'z';
1397    ///   }
1398    ///   assert_eq!(("foo", "baz"), cursor.get_current(&access).unwrap());
1399    /// }
1400    /// txn.commit().unwrap();
1401    /// # }
1402    /// ```
1403    #[inline]
1404    pub fn overwrite_in_place_array<'access, K : AsLmdbBytes + ?Sized,
1405                                    V : LmdbRaw>
1406        (&mut self, access: &'access mut WriteAccessor,
1407         key: &K, count: usize, flags: put::Flags)
1408         -> Result<&'access mut [V]>
1409    {
1410        unsafe {
1411            self.overwrite_in_place_unsized(
1412                access, key, count * mem::size_of::<V>(), flags)
1413        }
1414    }
1415
1416    /// Returns a writable reference to the value belonging to the given key in
1417    /// the database.
1418    ///
1419    /// This has all the caveats of both `overwrite()` and `reserve_unsized()`.
1420    ///
1421    /// ## Unsafety
1422    ///
1423    /// The caller must ensure `size` is a valid size of `V`.
1424    pub unsafe fn overwrite_in_place_unsized
1425        <'access, K : AsLmdbBytes + ?Sized, V : FromReservedLmdbBytes + ?Sized>
1426        (&mut self, access: &'access mut WriteAccessor,
1427         key: &K, size: usize, flags: put::Flags) -> Result<&'access mut V>
1428    {
1429        try!(assert_sensible_cursor(&*access, self));
1430
1431        let mut mv_key = as_val(key);
1432        let mut out_val = EMPTY_VAL;
1433        out_val.mv_size = size;
1434
1435        lmdb_call!(ffi::mdb_cursor_put(
1436            self.cursor.0, &mut mv_key, &mut out_val,
1437            flags.bits() | ffi::MDB_RESERVE | ffi::MDB_CURRENT));
1438
1439        Ok(from_reserved(access, &out_val))
1440    }
1441
1442    /// Stores multiple data elements with the same key in a single request.
1443    ///
1444    /// This is only permitted for `DUPFIXED` databases.
1445    ///
1446    /// Note that `values` must be a slice of `LmdbRaw`, since this function
1447    /// needs to know the exact size of each individual item and must be able
1448    /// to directly reinterpret the slice as a byte array.
1449    ///
1450    /// On success, returns the number of items that were actually written.
1451    ///
1452    /// ## Warning
1453    ///
1454    /// `MDB_MULTIPLE` has historically been rather problematic. Using this
1455    /// function may result in erratic behaviour on many versions of LMDB.
1456    ///
1457    /// ## Example
1458    ///
1459    /// ```
1460    /// # include!(concat!(env!("CARGO_MANIFEST_DIR"),"/src/example_helpers.rs"));
1461    /// # fn main() {
1462    /// # let env = create_env();
1463    /// # let db = dupfixeddb(&env);
1464    /// use lmdb::Unaligned as U;
1465    /// use lmdb::unaligned as u;
1466    ///
1467    /// let txn = lmdb::WriteTransaction::new(&env).unwrap();
1468    /// {
1469    ///   let mut access = txn.access();
1470    ///   let f = lmdb::put::Flags::empty();
1471    ///   let mut cursor = txn.cursor(&db).unwrap();
1472    ///   // XXX Whether this is supposed to be 4 or 3 is unclear.
1473    ///   assert_eq!(4, cursor.put_multiple(
1474    ///     &mut access, "bar", &[U::new(0u32), U::new(1u32),
1475    ///                           U::new(2u32), U::new(1u32)], f).unwrap());
1476    /// # // XXX I wanted a lot more assertions here, but I kept running into
1477    /// # // issues that I think but am not sure are bugs.
1478    ///
1479    ///   assert_eq!(("bar", u(&0u32)), cursor.first(&access).unwrap());
1480    ///   assert_eq!(("bar", u(&1u32)), cursor.next(&access).unwrap());
1481    ///   assert_eq!(("bar", u(&2u32)), cursor.next(&access).unwrap());
1482    ///   assert!(cursor.next::<str,U<u32>>(&access).is_err());
1483    /// }
1484    /// txn.commit().unwrap();
1485    /// # }
1486    /// ```
1487    pub fn put_multiple<K : AsLmdbBytes + ?Sized, V : LmdbRaw>
1488        (&mut self, access: &mut WriteAccessor,
1489         key: &K, values: &[V], flags: put::Flags)
1490         -> Result<usize>
1491    {
1492        try!(assert_sensible_cursor(&*access, self));
1493
1494        // Some LMDB versions didn't (don't?) handle count=0 correctly
1495        if values.is_empty() {
1496            return Ok(0);
1497        }
1498
1499        let mut mv_key = as_val(key);
1500        let mut mv_vals = [ ffi::MDB_val {
1501            mv_size: mem::size_of::<V>() as libc::size_t,
1502            mv_data: values.as_lmdb_bytes().as_ptr() as *mut c_void,
1503        }, ffi::MDB_val {
1504            mv_size: values.len() as libc::size_t,
1505            mv_data: ptr::null_mut(),
1506        }];
1507
1508        unsafe {
1509            lmdb_call!(ffi::mdb_cursor_put(
1510                self.cursor.0, &mut mv_key, mv_vals.as_mut_ptr(),
1511                flags.bits() | ffi::MDB_MULTIPLE));
1512        }
1513
1514        Ok(mv_vals[1].mv_size as usize)
1515    }
1516
1517    /// Delete current key/value pair.
1518    ///
1519    /// By default, this deletes only the current pair. `flags` can be set to
1520    /// `NODUPDATA` for `DUPDATA` databases to delete everything with the
1521    /// current key.
1522    ///
1523    /// See `lmdb_zero::del::NODUPDATA` for examples on how `flags` can be used
1524    /// to control behaviour.
1525    #[inline]
1526    pub fn del(&mut self, access: &mut WriteAccessor,
1527               flags: del::Flags) -> Result<()> {
1528        try!(assert_sensible_cursor(&*access, self));
1529
1530        unsafe {
1531            lmdb_call!(ffi::mdb_cursor_del(self.cursor.0, flags.bits()));
1532        }
1533
1534        Ok(())
1535    }
1536
1537    /// Return count of duplicates for current key.
1538    ///
1539    /// This call is only valid on `DUPSORT` databases.
1540    #[inline]
1541    pub fn count(&mut self) -> Result<usize> {
1542        let mut raw: libc::size_t = 0;
1543        unsafe {
1544            lmdb_call!(ffi::mdb_cursor_count(self.cursor.0, &mut raw));
1545        }
1546        Ok(raw as usize)
1547    }
1548}
1549
1550#[cfg(test)]
1551mod test {
1552    use dbi::{db, Database, DatabaseOptions};
1553    use error::LmdbResultExt;
1554    use tx::{put, WriteTransaction};
1555    use test_helpers::*;
1556    use unaligned::Unaligned as U;
1557    use unaligned::unaligned;
1558
1559    #[test]
1560    fn get_multiple_with_one_item() {
1561        let env = create_env();
1562        let db = Database::open(
1563            &env, None, &DatabaseOptions::new(
1564                db::DUPSORT | db::INTEGERKEY | db::DUPFIXED | db::INTEGERDUP |
1565                db::CREATE)).unwrap();
1566        let txn = WriteTransaction::new(&env).unwrap();
1567        {
1568            let key: i32 = 42;
1569            let val: i32 = 56;
1570
1571            let mut access = txn.access();
1572            access.put(&db, &key, &val, put::Flags::empty()).unwrap();
1573
1574            let mut cursor = txn.cursor(&db).unwrap();
1575            cursor.seek_k::<U<i32>, U<i32>>(&access, unaligned(&key)).unwrap();
1576            let vals = cursor.get_multiple::<[U<i32>]>(&access).unwrap();
1577            assert_eq!(1, vals.len());
1578            assert_eq!(val, vals[0].get());
1579
1580            assert!(cursor.next_multiple::<[U<i32>]>(&access)
1581                    .to_opt().unwrap().is_none());
1582        }
1583    }
1584}