heed/
database.rs

1use std::borrow::Cow;
2use std::ops::{Bound, RangeBounds};
3use std::{any, fmt, marker, mem, ptr};
4
5use heed_traits::{Comparator, LexicographicComparator};
6use types::{DecodeIgnore, LazyDecode};
7
8use crate::cursor::MoveOperation;
9use crate::env::DefaultComparator;
10use crate::iteration_method::MoveOnCurrentKeyDuplicates;
11use crate::mdb::error::mdb_result;
12use crate::mdb::ffi;
13use crate::mdb::lmdb_flags::{AllDatabaseFlags, DatabaseFlags};
14use crate::*;
15
16/// Options and flags which can be used to configure how a [`Database`] is opened.
17///
18/// # Examples
19///
20/// Opening a file to read:
21///
22/// ```
23/// # use std::fs;
24/// # use std::path::Path;
25/// # use heed::EnvOpenOptions;
26/// use heed::types::*;
27/// use heed::byteorder::BigEndian;
28///
29/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
30/// # let dir = tempfile::tempdir()?;
31/// # let env = unsafe { EnvOpenOptions::new()
32/// #     .map_size(10 * 1024 * 1024) // 10MB
33/// #     .max_dbs(3000)
34/// #     .open(dir.path())?
35/// # };
36/// type BEI64 = I64<BigEndian>;
37///
38/// // Imagine you have an optional name
39/// let conditional_name = Some("big-endian-iter");
40///
41/// let mut wtxn = env.write_txn()?;
42/// let mut options = env.database_options().types::<BEI64, Unit>();
43/// if let Some(name) = conditional_name {
44///    options.name(name);
45/// }
46/// let db = options.create(&mut wtxn)?;
47///
48/// # db.clear(&mut wtxn)?;
49/// db.put(&mut wtxn, &68, &())?;
50/// db.put(&mut wtxn, &35, &())?;
51/// db.put(&mut wtxn, &0, &())?;
52/// db.put(&mut wtxn, &42, &())?;
53///
54/// wtxn.commit()?;
55/// # Ok(()) }
56/// ```
57#[derive(Debug)]
58pub struct DatabaseOpenOptions<'e, 'n, KC, DC, C = DefaultComparator> {
59    env: &'e Env,
60    types: marker::PhantomData<(KC, DC, C)>,
61    name: Option<&'n str>,
62    flags: AllDatabaseFlags,
63}
64
65impl<'e> DatabaseOpenOptions<'e, 'static, Unspecified, Unspecified> {
66    /// Create an options struct to open/create a database with specific flags.
67    pub fn new(env: &'e Env) -> Self {
68        DatabaseOpenOptions {
69            env,
70            types: Default::default(),
71            name: None,
72            flags: AllDatabaseFlags::empty(),
73        }
74    }
75}
76
77impl<'e, 'n, KC, DC, C> DatabaseOpenOptions<'e, 'n, KC, DC, C> {
78    /// Change the type of the database.
79    ///
80    /// The default types are [`Unspecified`] and require a call to [`Database::remap_types`]
81    /// to use the [`Database`].
82    pub fn types<NKC, NDC>(self) -> DatabaseOpenOptions<'e, 'n, NKC, NDC> {
83        DatabaseOpenOptions {
84            env: self.env,
85            types: Default::default(),
86            name: self.name,
87            flags: self.flags,
88        }
89    }
90    /// Change the customized key compare function of the database.
91    ///
92    /// By default no customized compare function will be set when opening a database.
93    pub fn key_comparator<NC>(self) -> DatabaseOpenOptions<'e, 'n, KC, DC, NC> {
94        DatabaseOpenOptions {
95            env: self.env,
96            types: Default::default(),
97            name: self.name,
98            flags: self.flags,
99        }
100    }
101
102    /// Change the name of the database.
103    ///
104    /// By default the database is unnamed and there only is a single unnamed database.
105    pub fn name(&mut self, name: &'n str) -> &mut Self {
106        self.name = Some(name);
107        self
108    }
109
110    /// Specify the set of flags used to open the database.
111    pub fn flags(&mut self, flags: DatabaseFlags) -> &mut Self {
112        self.flags = AllDatabaseFlags::from_bits(flags.bits()).unwrap();
113        self
114    }
115
116    /// Opens a typed database that already exists in this environment.
117    ///
118    /// If the database was previously opened in this program run, types will be checked.
119    ///
120    /// ## Important Information
121    ///
122    /// LMDB has an important restriction on the unnamed database when named ones are opened.
123    /// The names of the named databases are stored as keys in the unnamed one and are immutable,
124    /// and these keys can only be read and not written.
125    ///
126    /// ## LMDB read-only access of existing database
127    ///
128    /// In the case of accessing a database in a read-only manner from another process
129    /// where you wrote, you might need to manually call [`RoTxn::commit`] to get metadata
130    /// and the database handles opened and shared with the global [`Env`] handle.
131    ///
132    /// If not done, you might raise `Io(Os { code: 22, kind: InvalidInput, message: "Invalid argument" })`
133    /// known as `EINVAL`.
134    pub fn open(&self, rtxn: &RoTxn) -> Result<Option<Database<KC, DC, C>>>
135    where
136        KC: 'static,
137        DC: 'static,
138        C: Comparator + 'static,
139    {
140        assert_eq_env_txn!(self.env, rtxn);
141
142        match self.env.raw_init_database::<C>(rtxn.txn, self.name, self.flags) {
143            Ok(dbi) => Ok(Some(Database::new(self.env.env_mut_ptr() as _, dbi))),
144            Err(Error::Mdb(e)) if e.not_found() => Ok(None),
145            Err(e) => Err(e),
146        }
147    }
148
149    /// Creates a typed database that can already exist in this environment.
150    ///
151    /// If the database was previously opened in this program run, types will be checked.
152    ///
153    /// ## Important Information
154    ///
155    /// LMDB has an important restriction on the unnamed database when named ones are opened.
156    /// The names of the named databases are stored as keys in the unnamed one and are immutable,
157    /// and these keys can only be read and not written.
158    pub fn create(&self, wtxn: &mut RwTxn) -> Result<Database<KC, DC, C>>
159    where
160        KC: 'static,
161        DC: 'static,
162        C: Comparator + 'static,
163    {
164        assert_eq_env_txn!(self.env, wtxn);
165
166        let flags = self.flags | AllDatabaseFlags::CREATE;
167        match self.env.raw_init_database::<C>(wtxn.txn.txn, self.name, flags) {
168            Ok(dbi) => Ok(Database::new(self.env.env_mut_ptr() as _, dbi)),
169            Err(e) => Err(e),
170        }
171    }
172}
173
174impl<KC, DC, C> Clone for DatabaseOpenOptions<'_, '_, KC, DC, C> {
175    fn clone(&self) -> Self {
176        *self
177    }
178}
179
180impl<KC, DC, C> Copy for DatabaseOpenOptions<'_, '_, KC, DC, C> {}
181
182/// A typed database that accepts only the types it was created with.
183///
184/// # Example: Iterate over databases entries
185///
186/// In this example we store numbers in big endian this way those are ordered.
187/// Thanks to their bytes representation, heed is able to iterate over them
188/// from the lowest to the highest.
189///
190/// ```
191/// # use std::fs;
192/// # use std::path::Path;
193/// # use heed::EnvOpenOptions;
194/// use heed::Database;
195/// use heed::types::*;
196/// use heed::byteorder::BigEndian;
197///
198/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
199/// # let dir = tempfile::tempdir()?;
200/// # let env = unsafe { EnvOpenOptions::new()
201/// #     .map_size(10 * 1024 * 1024) // 10MB
202/// #     .max_dbs(3000)
203/// #     .open(dir.path())?
204/// # };
205/// type BEI64 = I64<BigEndian>;
206///
207/// let mut wtxn = env.write_txn()?;
208/// let db: Database<BEI64, Unit> = env.create_database(&mut wtxn, Some("big-endian-iter"))?;
209///
210/// # db.clear(&mut wtxn)?;
211/// db.put(&mut wtxn, &68, &())?;
212/// db.put(&mut wtxn, &35, &())?;
213/// db.put(&mut wtxn, &0, &())?;
214/// db.put(&mut wtxn, &42, &())?;
215///
216/// // you can iterate over database entries in order
217/// let rets: Result<_, _> = db.iter(&wtxn)?.collect();
218/// let rets: Vec<(i64, _)> = rets?;
219///
220/// let expected = vec![
221///     (0, ()),
222///     (35, ()),
223///     (42, ()),
224///     (68, ()),
225/// ];
226///
227/// assert_eq!(rets, expected);
228/// wtxn.commit()?;
229/// # Ok(()) }
230/// ```
231///
232/// # Example: Iterate over and delete ranges of entries
233///
234/// Discern also support ranges and ranges deletions.
235/// Same configuration as above, numbers are ordered, therefore it is safe to specify
236/// a range and be able to iterate over and/or delete it.
237///
238/// ```
239/// # use std::fs;
240/// # use std::path::Path;
241/// # use heed::EnvOpenOptions;
242/// use heed::Database;
243/// use heed::types::*;
244/// use heed::byteorder::BigEndian;
245///
246/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
247/// # let dir = tempfile::tempdir()?;
248/// # let env = unsafe { EnvOpenOptions::new()
249/// #     .map_size(10 * 1024 * 1024) // 10MB
250/// #     .max_dbs(3000)
251/// #     .open(dir.path())?
252/// # };
253/// type BEI64 = I64<BigEndian>;
254///
255/// let mut wtxn = env.write_txn()?;
256/// let db: Database<BEI64, Unit> = env.create_database(&mut wtxn, Some("big-endian-iter"))?;
257///
258/// # db.clear(&mut wtxn)?;
259/// db.put(&mut wtxn, &0, &())?;
260/// db.put(&mut wtxn, &68, &())?;
261/// db.put(&mut wtxn, &35, &())?;
262/// db.put(&mut wtxn, &42, &())?;
263///
264/// // you can iterate over ranges too!!!
265/// let range = 35..=42;
266/// let rets: Result<_, _> = db.range(&wtxn, &range)?.collect();
267/// let rets: Vec<(i64, _)> = rets?;
268///
269/// let expected = vec![
270///     (35, ()),
271///     (42, ()),
272/// ];
273///
274/// assert_eq!(rets, expected);
275///
276/// // even delete a range of keys
277/// let range = 35..=42;
278/// let deleted: usize = db.delete_range(&mut wtxn, &range)?;
279///
280/// let rets: Result<_, _> = db.iter(&wtxn)?.collect();
281/// let rets: Vec<(i64, _)> = rets?;
282///
283/// let expected = vec![
284///     (0, ()),
285///     (68, ()),
286/// ];
287///
288/// assert_eq!(deleted, 2);
289/// assert_eq!(rets, expected);
290///
291/// wtxn.commit()?;
292/// # Ok(()) }
293/// ```
294pub struct Database<KC, DC, C = DefaultComparator> {
295    pub(crate) env_ident: usize,
296    pub(crate) dbi: ffi::MDB_dbi,
297    marker: marker::PhantomData<(KC, DC, C)>,
298}
299
300impl<KC, DC, C> Database<KC, DC, C> {
301    pub(crate) fn new(env_ident: usize, dbi: ffi::MDB_dbi) -> Database<KC, DC, C> {
302        Database { env_ident, dbi, marker: std::marker::PhantomData }
303    }
304
305    /// Retrieves the value associated with a key.
306    ///
307    /// If the key does not exist, then `None` is returned.
308    ///
309    /// ```
310    /// # use std::fs;
311    /// # use std::path::Path;
312    /// # use heed::EnvOpenOptions;
313    /// use heed::Database;
314    /// use heed::types::*;
315    /// use heed::byteorder::BigEndian;
316    ///
317    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
318    /// # let dir = tempfile::tempdir()?;
319    /// # let env = unsafe { EnvOpenOptions::new()
320    /// #     .map_size(10 * 1024 * 1024) // 10MB
321    /// #     .max_dbs(3000)
322    /// #     .open(dir.path())?
323    /// # };
324    /// type BEI32= U32<BigEndian>;
325    ///
326    /// let mut wtxn = env.write_txn()?;
327    /// let db: Database<Str, BEI32> = env.create_database(&mut wtxn, Some("get-i32"))?;
328    ///
329    /// # db.clear(&mut wtxn)?;
330    /// db.put(&mut wtxn, "i-am-forty-two", &42)?;
331    /// db.put(&mut wtxn, "i-am-twenty-seven", &27)?;
332    ///
333    /// let ret = db.get(&wtxn, "i-am-forty-two")?;
334    /// assert_eq!(ret, Some(42));
335    ///
336    /// let ret = db.get(&wtxn, "i-am-twenty-one")?;
337    /// assert_eq!(ret, None);
338    ///
339    /// wtxn.commit()?;
340    /// # Ok(()) }
341    /// ```
342    pub fn get<'a, 'txn>(&self, txn: &'txn RoTxn, key: &'a KC::EItem) -> Result<Option<DC::DItem>>
343    where
344        KC: BytesEncode<'a>,
345        DC: BytesDecode<'txn>,
346    {
347        assert_eq_env_db_txn!(self, txn);
348
349        let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
350
351        let mut key_val = unsafe { crate::into_val(&key_bytes) };
352        let mut data_val = mem::MaybeUninit::uninit();
353
354        let result = unsafe {
355            mdb_result(ffi::mdb_get(txn.txn, self.dbi, &mut key_val, data_val.as_mut_ptr()))
356        };
357
358        match result {
359            Ok(()) => {
360                let data = unsafe { crate::from_val(data_val.assume_init()) };
361                let data = DC::bytes_decode(data).map_err(Error::Decoding)?;
362                Ok(Some(data))
363            }
364            Err(e) if e.not_found() => Ok(None),
365            Err(e) => Err(e.into()),
366        }
367    }
368
369    /// Returns an iterator over all of the values of a single key.
370    ///
371    /// You can make this iterator `Send`able between threads by
372    /// using the `read-txn-no-tls` crate feature.
373    ///
374    /// ```
375    /// # use std::fs;
376    /// # use std::path::Path;
377    /// # use heed::{DatabaseFlags, EnvOpenOptions};
378    /// use heed::types::*;
379    /// use heed::byteorder::BigEndian;
380    ///
381    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
382    /// # let dir = tempfile::tempdir()?;
383    /// # let env = unsafe { EnvOpenOptions::new()
384    /// #     .map_size(10 * 1024 * 1024) // 10MB
385    /// #     .max_dbs(3000)
386    /// #     .open(dir.path())?
387    /// # };
388    /// type BEI64 = I64<BigEndian>;
389    ///
390    /// let mut wtxn = env.write_txn()?;
391    /// let db = env.database_options()
392    ///     .types::<BEI64, BEI64>()
393    ///     .flags(DatabaseFlags::DUP_SORT)
394    ///     .name("dup-sort")
395    ///     .create(&mut wtxn)?;
396    ///
397    /// # db.clear(&mut wtxn)?;
398    /// db.put(&mut wtxn, &68, &120)?;
399    /// db.put(&mut wtxn, &68, &121)?;
400    /// db.put(&mut wtxn, &68, &122)?;
401    /// db.put(&mut wtxn, &68, &123)?;
402    /// db.put(&mut wtxn, &92, &32)?;
403    /// db.put(&mut wtxn, &35, &120)?;
404    /// db.put(&mut wtxn, &0, &120)?;
405    /// db.put(&mut wtxn, &42, &120)?;
406    ///
407    /// let mut iter = db.get_duplicates(&wtxn, &68)?.expect("the key exists");
408    /// assert_eq!(iter.next().transpose()?, Some((68, 120)));
409    /// assert_eq!(iter.next().transpose()?, Some((68, 121)));
410    /// assert_eq!(iter.next().transpose()?, Some((68, 122)));
411    /// assert_eq!(iter.next().transpose()?, Some((68, 123)));
412    /// assert_eq!(iter.next().transpose()?, None);
413    /// drop(iter);
414    ///
415    /// let mut iter = db.get_duplicates(&wtxn, &68)?.expect("the key exists");
416    /// assert_eq!(iter.last().transpose()?, Some((68, 123)));
417    ///
418    /// wtxn.commit()?;
419    /// # Ok(()) }
420    /// ```
421    pub fn get_duplicates<'a, 'txn>(
422        &self,
423        txn: &'txn RoTxn,
424        key: &'a KC::EItem,
425    ) -> Result<Option<RoIter<'txn, KC, DC, MoveOnCurrentKeyDuplicates>>>
426    where
427        KC: BytesEncode<'a>,
428    {
429        assert_eq_env_db_txn!(self, txn);
430
431        let mut cursor = RoCursor::new(txn, self.dbi)?;
432        let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
433        if cursor.move_on_key(&key_bytes)? {
434            Ok(Some(RoIter::new(cursor)))
435        } else {
436            Ok(None)
437        }
438    }
439
440    /// Retrieves the key/value pair lower than the given one in this database.
441    ///
442    /// If the database if empty or there is no key lower than the given one,
443    /// then `None` is returned.
444    ///
445    /// Comparisons are made by using the bytes representation of the key.
446    ///
447    /// ```
448    /// # use std::fs;
449    /// # use std::path::Path;
450    /// # use heed::EnvOpenOptions;
451    /// use heed::Database;
452    /// use heed::types::*;
453    /// use heed::byteorder::BigEndian;
454    ///
455    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
456    /// # let dir = tempfile::tempdir()?;
457    /// # let env = unsafe { EnvOpenOptions::new()
458    /// #     .map_size(10 * 1024 * 1024) // 10MB
459    /// #     .max_dbs(3000)
460    /// #     .open(dir.path())?
461    /// # };
462    /// type BEU32 = U32<BigEndian>;
463    ///
464    /// let mut wtxn = env.write_txn()?;
465    /// let db = env.create_database::<BEU32, Unit>(&mut wtxn, Some("get-lt-u32"))?;
466    ///
467    /// # db.clear(&mut wtxn)?;
468    /// db.put(&mut wtxn, &27, &())?;
469    /// db.put(&mut wtxn, &42, &())?;
470    /// db.put(&mut wtxn, &43, &())?;
471    ///
472    /// let ret = db.get_lower_than(&wtxn, &4404)?;
473    /// assert_eq!(ret, Some((43, ())));
474    ///
475    /// let ret = db.get_lower_than(&wtxn, &43)?;
476    /// assert_eq!(ret, Some((42, ())));
477    ///
478    /// let ret = db.get_lower_than(&wtxn, &27)?;
479    /// assert_eq!(ret, None);
480    ///
481    /// wtxn.commit()?;
482    /// # Ok(()) }
483    /// ```
484    pub fn get_lower_than<'a, 'txn>(
485        &self,
486        txn: &'txn RoTxn,
487        key: &'a KC::EItem,
488    ) -> Result<Option<(KC::DItem, DC::DItem)>>
489    where
490        KC: BytesEncode<'a> + BytesDecode<'txn>,
491        DC: BytesDecode<'txn>,
492    {
493        assert_eq_env_db_txn!(self, txn);
494
495        let mut cursor = RoCursor::new(txn, self.dbi)?;
496        let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
497        cursor.move_on_key_greater_than_or_equal_to(&key_bytes)?;
498
499        match cursor.move_on_prev(MoveOperation::NoDup) {
500            Ok(Some((key, data))) => match (KC::bytes_decode(key), DC::bytes_decode(data)) {
501                (Ok(key), Ok(data)) => Ok(Some((key, data))),
502                (Err(e), _) | (_, Err(e)) => Err(Error::Decoding(e)),
503            },
504            Ok(None) => Ok(None),
505            Err(e) => Err(e),
506        }
507    }
508
509    /// Retrieves the key/value pair lower than or equal to the given one in this database.
510    ///
511    /// If the database if empty or there is no key lower than or equal to the given one,
512    /// then `None` is returned.
513    ///
514    /// Comparisons are made by using the bytes representation of the key.
515    ///
516    /// ```
517    /// # use std::fs;
518    /// # use std::path::Path;
519    /// # use heed::EnvOpenOptions;
520    /// use heed::Database;
521    /// use heed::types::*;
522    /// use heed::byteorder::BigEndian;
523    ///
524    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
525    /// # let dir = tempfile::tempdir()?;
526    /// # let env = unsafe { EnvOpenOptions::new()
527    /// #     .map_size(10 * 1024 * 1024) // 10MB
528    /// #     .max_dbs(3000)
529    /// #     .open(dir.path())?
530    /// # };
531    /// type BEU32 = U32<BigEndian>;
532    ///
533    /// let mut wtxn = env.write_txn()?;
534    /// let db = env.create_database::<BEU32, Unit>(&mut wtxn, Some("get-lt-u32"))?;
535    ///
536    /// # db.clear(&mut wtxn)?;
537    /// db.put(&mut wtxn, &27, &())?;
538    /// db.put(&mut wtxn, &42, &())?;
539    /// db.put(&mut wtxn, &43, &())?;
540    ///
541    /// let ret = db.get_lower_than_or_equal_to(&wtxn, &4404)?;
542    /// assert_eq!(ret, Some((43, ())));
543    ///
544    /// let ret = db.get_lower_than_or_equal_to(&wtxn, &43)?;
545    /// assert_eq!(ret, Some((43, ())));
546    ///
547    /// let ret = db.get_lower_than_or_equal_to(&wtxn, &26)?;
548    /// assert_eq!(ret, None);
549    ///
550    /// wtxn.commit()?;
551    /// # Ok(()) }
552    /// ```
553    pub fn get_lower_than_or_equal_to<'a, 'txn>(
554        &self,
555        txn: &'txn RoTxn,
556        key: &'a KC::EItem,
557    ) -> Result<Option<(KC::DItem, DC::DItem)>>
558    where
559        KC: BytesEncode<'a> + BytesDecode<'txn>,
560        DC: BytesDecode<'txn>,
561    {
562        assert_eq_env_db_txn!(self, txn);
563
564        let mut cursor = RoCursor::new(txn, self.dbi)?;
565        let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
566        let result = match cursor.move_on_key_greater_than_or_equal_to(&key_bytes) {
567            Ok(Some((key, data))) if key == &key_bytes[..] => Ok(Some((key, data))),
568            Ok(_) => cursor.move_on_prev(MoveOperation::NoDup),
569            Err(e) => Err(e),
570        };
571
572        match result {
573            Ok(Some((key, data))) => match (KC::bytes_decode(key), DC::bytes_decode(data)) {
574                (Ok(key), Ok(data)) => Ok(Some((key, data))),
575                (Err(e), _) | (_, Err(e)) => Err(Error::Decoding(e)),
576            },
577            Ok(None) => Ok(None),
578            Err(e) => Err(e),
579        }
580    }
581
582    /// Retrieves the key/value pair greater than the given one in this database.
583    ///
584    /// If the database if empty or there is no key greater than the given one,
585    /// then `None` is returned.
586    ///
587    /// Comparisons are made by using the bytes representation of the key.
588    ///
589    /// ```
590    /// # use std::fs;
591    /// # use std::path::Path;
592    /// # use heed::EnvOpenOptions;
593    /// use heed::Database;
594    /// use heed::types::*;
595    /// use heed::byteorder::BigEndian;
596    ///
597    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
598    /// # let dir = tempfile::tempdir()?;
599    /// # let env = unsafe { EnvOpenOptions::new()
600    /// #     .map_size(10 * 1024 * 1024) // 10MB
601    /// #     .max_dbs(3000)
602    /// #     .open(dir.path())?
603    /// # };
604    /// type BEU32 = U32<BigEndian>;
605    ///
606    /// let mut wtxn = env.write_txn()?;
607    /// let db = env.create_database::<BEU32, Unit>(&mut wtxn, Some("get-lt-u32"))?;
608    ///
609    /// # db.clear(&mut wtxn)?;
610    /// db.put(&mut wtxn, &27, &())?;
611    /// db.put(&mut wtxn, &42, &())?;
612    /// db.put(&mut wtxn, &43, &())?;
613    ///
614    /// let ret = db.get_greater_than(&wtxn, &0)?;
615    /// assert_eq!(ret, Some((27, ())));
616    ///
617    /// let ret = db.get_greater_than(&wtxn, &42)?;
618    /// assert_eq!(ret, Some((43, ())));
619    ///
620    /// let ret = db.get_greater_than(&wtxn, &43)?;
621    /// assert_eq!(ret, None);
622    ///
623    /// wtxn.commit()?;
624    /// # Ok(()) }
625    /// ```
626    pub fn get_greater_than<'a, 'txn>(
627        &self,
628        txn: &'txn RoTxn,
629        key: &'a KC::EItem,
630    ) -> Result<Option<(KC::DItem, DC::DItem)>>
631    where
632        KC: BytesEncode<'a> + BytesDecode<'txn>,
633        DC: BytesDecode<'txn>,
634    {
635        assert_eq_env_db_txn!(self, txn);
636
637        let mut cursor = RoCursor::new(txn, self.dbi)?;
638        let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
639        let entry = match cursor.move_on_key_greater_than_or_equal_to(&key_bytes)? {
640            Some((key, data)) if key > &key_bytes[..] => Some((key, data)),
641            Some((_key, _data)) => cursor.move_on_next(MoveOperation::NoDup)?,
642            None => None,
643        };
644
645        match entry {
646            Some((key, data)) => match (KC::bytes_decode(key), DC::bytes_decode(data)) {
647                (Ok(key), Ok(data)) => Ok(Some((key, data))),
648                (Err(e), _) | (_, Err(e)) => Err(Error::Decoding(e)),
649            },
650            None => Ok(None),
651        }
652    }
653
654    /// Retrieves the key/value pair greater than or equal to the given one in this database.
655    ///
656    /// If the database if empty or there is no key greater than or equal to the given one,
657    /// then `None` is returned.
658    ///
659    /// Comparisons are made by using the bytes representation of the key.
660    ///
661    /// ```
662    /// # use std::fs;
663    /// # use std::path::Path;
664    /// # use heed::EnvOpenOptions;
665    /// use heed::Database;
666    /// use heed::types::*;
667    /// use heed::byteorder::BigEndian;
668    ///
669    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
670    /// # let dir = tempfile::tempdir()?;
671    /// # let env = unsafe { EnvOpenOptions::new()
672    /// #     .map_size(10 * 1024 * 1024) // 10MB
673    /// #     .max_dbs(3000)
674    /// #     .open(dir.path())?
675    /// # };
676    /// type BEU32 = U32<BigEndian>;
677    ///
678    /// let mut wtxn = env.write_txn()?;
679    /// let db = env.create_database::<BEU32, Unit>(&mut wtxn, Some("get-lt-u32"))?;
680    ///
681    /// # db.clear(&mut wtxn)?;
682    /// db.put(&mut wtxn, &27, &())?;
683    /// db.put(&mut wtxn, &42, &())?;
684    /// db.put(&mut wtxn, &43, &())?;
685    ///
686    /// let ret = db.get_greater_than_or_equal_to(&wtxn, &0)?;
687    /// assert_eq!(ret, Some((27, ())));
688    ///
689    /// let ret = db.get_greater_than_or_equal_to(&wtxn, &42)?;
690    /// assert_eq!(ret, Some((42, ())));
691    ///
692    /// let ret = db.get_greater_than_or_equal_to(&wtxn, &44)?;
693    /// assert_eq!(ret, None);
694    ///
695    /// wtxn.commit()?;
696    /// # Ok(()) }
697    /// ```
698    pub fn get_greater_than_or_equal_to<'a, 'txn>(
699        &self,
700        txn: &'txn RoTxn,
701        key: &'a KC::EItem,
702    ) -> Result<Option<(KC::DItem, DC::DItem)>>
703    where
704        KC: BytesEncode<'a> + BytesDecode<'txn>,
705        DC: BytesDecode<'txn>,
706    {
707        assert_eq_env_db_txn!(self, txn);
708
709        let mut cursor = RoCursor::new(txn, self.dbi)?;
710        let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
711        match cursor.move_on_key_greater_than_or_equal_to(&key_bytes) {
712            Ok(Some((key, data))) => match (KC::bytes_decode(key), DC::bytes_decode(data)) {
713                (Ok(key), Ok(data)) => Ok(Some((key, data))),
714                (Err(e), _) | (_, Err(e)) => Err(Error::Decoding(e)),
715            },
716            Ok(None) => Ok(None),
717            Err(e) => Err(e),
718        }
719    }
720
721    /// Retrieves the first key/value pair of this database.
722    ///
723    /// If the database if empty, then `None` is returned.
724    ///
725    /// Comparisons are made by using the bytes representation of the key.
726    ///
727    /// ```
728    /// # use std::fs;
729    /// # use std::path::Path;
730    /// # use heed::EnvOpenOptions;
731    /// use heed::Database;
732    /// use heed::types::*;
733    /// use heed::byteorder::BigEndian;
734    ///
735    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
736    /// # let dir = tempfile::tempdir()?;
737    /// # let env = unsafe { EnvOpenOptions::new()
738    /// #     .map_size(10 * 1024 * 1024) // 10MB
739    /// #     .max_dbs(3000)
740    /// #     .open(dir.path())?
741    /// # };
742    /// type BEI32 = I32<BigEndian>;
743    ///
744    /// let mut wtxn = env.write_txn()?;
745    /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("first-i32"))?;
746    ///
747    /// # db.clear(&mut wtxn)?;
748    /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
749    /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
750    ///
751    /// let ret = db.first(&wtxn)?;
752    /// assert_eq!(ret, Some((27, "i-am-twenty-seven")));
753    ///
754    /// wtxn.commit()?;
755    /// # Ok(()) }
756    /// ```
757    pub fn first<'txn>(&self, txn: &'txn RoTxn) -> Result<Option<(KC::DItem, DC::DItem)>>
758    where
759        KC: BytesDecode<'txn>,
760        DC: BytesDecode<'txn>,
761    {
762        assert_eq_env_db_txn!(self, txn);
763
764        let mut cursor = RoCursor::new(txn, self.dbi)?;
765        match cursor.move_on_first(MoveOperation::Any) {
766            Ok(Some((key, data))) => match (KC::bytes_decode(key), DC::bytes_decode(data)) {
767                (Ok(key), Ok(data)) => Ok(Some((key, data))),
768                (Err(e), _) | (_, Err(e)) => Err(Error::Decoding(e)),
769            },
770            Ok(None) => Ok(None),
771            Err(e) => Err(e),
772        }
773    }
774
775    /// Retrieves the last key/value pair of this database.
776    ///
777    /// If the database if empty, then `None` is returned.
778    ///
779    /// Comparisons are made by using the bytes representation of the key.
780    ///
781    /// ```
782    /// # use std::fs;
783    /// # use std::path::Path;
784    /// # use heed::EnvOpenOptions;
785    /// use heed::Database;
786    /// use heed::types::*;
787    /// use heed::byteorder::BigEndian;
788    ///
789    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
790    /// # let dir = tempfile::tempdir()?;
791    /// # let env = unsafe { EnvOpenOptions::new()
792    /// #     .map_size(10 * 1024 * 1024) // 10MB
793    /// #     .max_dbs(3000)
794    /// #     .open(dir.path())?
795    /// # };
796    /// type BEI32 = I32<BigEndian>;
797    ///
798    /// let mut wtxn = env.write_txn()?;
799    /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("last-i32"))?;
800    ///
801    /// # db.clear(&mut wtxn)?;
802    /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
803    /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
804    ///
805    /// let ret = db.last(&wtxn)?;
806    /// assert_eq!(ret, Some((42, "i-am-forty-two")));
807    ///
808    /// wtxn.commit()?;
809    /// # Ok(()) }
810    /// ```
811    pub fn last<'txn>(&self, txn: &'txn RoTxn) -> Result<Option<(KC::DItem, DC::DItem)>>
812    where
813        KC: BytesDecode<'txn>,
814        DC: BytesDecode<'txn>,
815    {
816        assert_eq_env_db_txn!(self, txn);
817
818        let mut cursor = RoCursor::new(txn, self.dbi)?;
819        match cursor.move_on_last(MoveOperation::Any) {
820            Ok(Some((key, data))) => match (KC::bytes_decode(key), DC::bytes_decode(data)) {
821                (Ok(key), Ok(data)) => Ok(Some((key, data))),
822                (Err(e), _) | (_, Err(e)) => Err(Error::Decoding(e)),
823            },
824            Ok(None) => Ok(None),
825            Err(e) => Err(e),
826        }
827    }
828
829    /// Returns the number of elements in this database.
830    ///
831    /// ```
832    /// # use std::fs;
833    /// # use std::path::Path;
834    /// # use heed::EnvOpenOptions;
835    /// use heed::Database;
836    /// use heed::types::*;
837    /// use heed::byteorder::BigEndian;
838    ///
839    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
840    /// # let dir = tempfile::tempdir()?;
841    /// # let env = unsafe { EnvOpenOptions::new()
842    /// #     .map_size(10 * 1024 * 1024) // 10MB
843    /// #     .max_dbs(3000)
844    /// #     .open(dir.path())?
845    /// # };
846    /// type BEI32 = I32<BigEndian>;
847    ///
848    /// let mut wtxn = env.write_txn()?;
849    /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
850    ///
851    /// # db.clear(&mut wtxn)?;
852    /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
853    /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
854    /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
855    /// db.put(&mut wtxn, &521, "i-am-five-hundred-and-twenty-one")?;
856    ///
857    /// let ret = db.len(&wtxn)?;
858    /// assert_eq!(ret, 4);
859    ///
860    /// db.delete(&mut wtxn, &27)?;
861    ///
862    /// let ret = db.len(&wtxn)?;
863    /// assert_eq!(ret, 3);
864    ///
865    /// wtxn.commit()?;
866    /// # Ok(()) }
867    /// ```
868    pub fn len(&self, txn: &RoTxn) -> Result<u64> {
869        self.stat(txn).map(|stat| stat.entries as u64)
870    }
871
872    /// Returns `true` if and only if this database is empty.
873    ///
874    /// ```
875    /// # use std::fs;
876    /// # use std::path::Path;
877    /// # use heed::EnvOpenOptions;
878    /// use heed::Database;
879    /// use heed::types::*;
880    /// use heed::byteorder::BigEndian;
881    ///
882    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
883    /// # let dir = tempfile::tempdir()?;
884    /// # let env = unsafe { EnvOpenOptions::new()
885    /// #     .map_size(10 * 1024 * 1024) // 10MB
886    /// #     .max_dbs(3000)
887    /// #     .open(dir.path())?
888    /// # };
889    /// type BEI32 = I32<BigEndian>;
890    ///
891    /// let mut wtxn = env.write_txn()?;
892    /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
893    ///
894    /// # db.clear(&mut wtxn)?;
895    /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
896    /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
897    /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
898    /// db.put(&mut wtxn, &521, "i-am-five-hundred-and-twenty-one")?;
899    ///
900    /// let ret = db.is_empty(&wtxn)?;
901    /// assert_eq!(ret, false);
902    ///
903    /// db.clear(&mut wtxn)?;
904    ///
905    /// let ret = db.is_empty(&wtxn)?;
906    /// assert_eq!(ret, true);
907    ///
908    /// wtxn.commit()?;
909    /// # Ok(()) }
910    /// ```
911    pub fn is_empty(&self, txn: &RoTxn) -> Result<bool> {
912        self.len(txn).map(|l| l == 0)
913    }
914
915    /// Returns some statistics for this database.
916    ///
917    /// ```
918    /// # use std::fs;
919    /// # use std::path::Path;
920    /// # use heed::EnvOpenOptions;
921    /// use heed::Database;
922    /// use heed::types::*;
923    /// use heed::byteorder::BigEndian;
924    ///
925    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
926    /// # let dir = tempfile::tempdir()?;
927    /// # let env = unsafe { EnvOpenOptions::new()
928    /// #     .map_size(10 * 1024 * 1024) // 10MB
929    /// #     .max_dbs(3000)
930    /// #     .open(dir.path())?
931    /// # };
932    /// type BEI32 = I32<BigEndian>;
933    ///
934    /// let mut wtxn = env.write_txn()?;
935    /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
936    ///
937    /// # db.clear(&mut wtxn)?;
938    /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
939    /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
940    /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
941    /// db.put(&mut wtxn, &521, "i-am-five-hundred-and-twenty-one")?;
942    ///
943    /// let stat = db.stat(&wtxn)?;
944    /// assert_eq!(stat.depth, 1);
945    /// assert_eq!(stat.branch_pages, 0);
946    /// assert_eq!(stat.leaf_pages, 1);
947    /// assert_eq!(stat.overflow_pages, 0);
948    /// assert_eq!(stat.entries, 4);
949    ///
950    /// wtxn.commit()?;
951    /// # Ok(()) }
952    /// ```
953    pub fn stat(&self, txn: &RoTxn) -> Result<DatabaseStat> {
954        assert_eq_env_db_txn!(self, txn);
955
956        let mut db_stat = mem::MaybeUninit::uninit();
957        let result = unsafe { mdb_result(ffi::mdb_stat(txn.txn, self.dbi, db_stat.as_mut_ptr())) };
958
959        match result {
960            Ok(()) => {
961                let stats = unsafe { db_stat.assume_init() };
962                Ok(DatabaseStat {
963                    page_size: stats.ms_psize,
964                    depth: stats.ms_depth,
965                    branch_pages: stats.ms_branch_pages,
966                    leaf_pages: stats.ms_leaf_pages,
967                    overflow_pages: stats.ms_overflow_pages,
968                    entries: stats.ms_entries,
969                })
970            }
971            Err(e) => Err(e.into()),
972        }
973    }
974
975    /// Return a lexicographically ordered iterator of all key-value pairs in this database.
976    ///
977    /// You can make this iterator `Send`able between threads by
978    /// using the `read-txn-no-tls` crate feature.
979    ///
980    /// ```
981    /// # use std::fs;
982    /// # use std::path::Path;
983    /// # use heed::EnvOpenOptions;
984    /// use heed::Database;
985    /// use heed::types::*;
986    /// use heed::byteorder::BigEndian;
987    ///
988    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
989    /// # let dir = tempfile::tempdir()?;
990    /// # let env = unsafe { EnvOpenOptions::new()
991    /// #     .map_size(10 * 1024 * 1024) // 10MB
992    /// #     .max_dbs(3000)
993    /// #     .open(dir.path())?
994    /// # };
995    /// type BEI32 = I32<BigEndian>;
996    ///
997    /// let mut wtxn = env.write_txn()?;
998    /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
999    ///
1000    /// # db.clear(&mut wtxn)?;
1001    /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
1002    /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
1003    /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
1004    ///
1005    /// let mut iter = db.iter(&wtxn)?;
1006    /// assert_eq!(iter.next().transpose()?, Some((13, "i-am-thirteen")));
1007    /// assert_eq!(iter.next().transpose()?, Some((27, "i-am-twenty-seven")));
1008    /// assert_eq!(iter.next().transpose()?, Some((42, "i-am-forty-two")));
1009    /// assert_eq!(iter.next().transpose()?, None);
1010    ///
1011    /// drop(iter);
1012    /// wtxn.commit()?;
1013    /// # Ok(()) }
1014    /// ```
1015    pub fn iter<'txn>(&self, txn: &'txn RoTxn) -> Result<RoIter<'txn, KC, DC>> {
1016        assert_eq_env_db_txn!(self, txn);
1017        RoCursor::new(txn, self.dbi).map(|cursor| RoIter::new(cursor))
1018    }
1019
1020    /// Return a mutable lexicographically ordered iterator of all key-value pairs in this database.
1021    ///
1022    /// ```
1023    /// # use std::fs;
1024    /// # use std::path::Path;
1025    /// # use heed::EnvOpenOptions;
1026    /// use heed::Database;
1027    /// use heed::types::*;
1028    /// use heed::byteorder::BigEndian;
1029    ///
1030    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1031    /// # let dir = tempfile::tempdir()?;
1032    /// # let env = unsafe { EnvOpenOptions::new()
1033    /// #     .map_size(10 * 1024 * 1024) // 10MB
1034    /// #     .max_dbs(3000)
1035    /// #     .open(dir.path())?
1036    /// # };
1037    /// type BEI32 = I32<BigEndian>;
1038    ///
1039    /// let mut wtxn = env.write_txn()?;
1040    /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
1041    ///
1042    /// # db.clear(&mut wtxn)?;
1043    /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
1044    /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
1045    /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
1046    ///
1047    /// let mut iter = db.iter_mut(&mut wtxn)?;
1048    /// assert_eq!(iter.next().transpose()?, Some((13, "i-am-thirteen")));
1049    /// let ret = unsafe { iter.del_current()? };
1050    /// assert!(ret);
1051    ///
1052    /// assert_eq!(iter.next().transpose()?, Some((27, "i-am-twenty-seven")));
1053    /// assert_eq!(iter.next().transpose()?, Some((42, "i-am-forty-two")));
1054    /// let ret = unsafe { iter.put_current(&42, "i-am-the-new-forty-two")? };
1055    /// assert!(ret);
1056    ///
1057    /// assert_eq!(iter.next().transpose()?, None);
1058    ///
1059    /// drop(iter);
1060    ///
1061    /// let ret = db.get(&wtxn, &13)?;
1062    /// assert_eq!(ret, None);
1063    ///
1064    /// let ret = db.get(&wtxn, &42)?;
1065    /// assert_eq!(ret, Some("i-am-the-new-forty-two"));
1066    ///
1067    /// wtxn.commit()?;
1068    /// # Ok(()) }
1069    /// ```
1070    pub fn iter_mut<'txn>(&self, txn: &'txn mut RwTxn) -> Result<RwIter<'txn, KC, DC>> {
1071        assert_eq_env_db_txn!(self, txn);
1072
1073        RwCursor::new(txn, self.dbi).map(|cursor| RwIter::new(cursor))
1074    }
1075
1076    /// Return a reversed lexicographically ordered iterator of all key-value pairs in this database.
1077    ///
1078    /// You can make this iterator `Send`able between threads by
1079    /// using the `read-txn-no-tls` crate feature.
1080    ///
1081    /// ```
1082    /// # use std::fs;
1083    /// # use std::path::Path;
1084    /// # use heed::EnvOpenOptions;
1085    /// use heed::Database;
1086    /// use heed::types::*;
1087    /// use heed::byteorder::BigEndian;
1088    ///
1089    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1090    /// # let dir = tempfile::tempdir()?;
1091    /// # let env = unsafe { EnvOpenOptions::new()
1092    /// #     .map_size(10 * 1024 * 1024) // 10MB
1093    /// #     .max_dbs(3000)
1094    /// #     .open(dir.path())?
1095    /// # };
1096    /// type BEI32 = I32<BigEndian>;
1097    ///
1098    /// let mut wtxn = env.write_txn()?;
1099    /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
1100    ///
1101    /// # db.clear(&mut wtxn)?;
1102    /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
1103    /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
1104    /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
1105    ///
1106    /// let mut iter = db.rev_iter(&wtxn)?;
1107    /// assert_eq!(iter.next().transpose()?, Some((42, "i-am-forty-two")));
1108    /// assert_eq!(iter.next().transpose()?, Some((27, "i-am-twenty-seven")));
1109    /// assert_eq!(iter.next().transpose()?, Some((13, "i-am-thirteen")));
1110    /// assert_eq!(iter.next().transpose()?, None);
1111    ///
1112    /// drop(iter);
1113    /// wtxn.commit()?;
1114    /// # Ok(()) }
1115    /// ```
1116    pub fn rev_iter<'txn>(&self, txn: &'txn RoTxn) -> Result<RoRevIter<'txn, KC, DC>> {
1117        assert_eq_env_db_txn!(self, txn);
1118
1119        RoCursor::new(txn, self.dbi).map(|cursor| RoRevIter::new(cursor))
1120    }
1121
1122    /// Return a mutable reversed lexicographically ordered iterator of all key-value\
1123    /// pairs in this database.
1124    ///
1125    /// ```
1126    /// # use std::fs;
1127    /// # use std::path::Path;
1128    /// # use heed::EnvOpenOptions;
1129    /// use heed::Database;
1130    /// use heed::types::*;
1131    /// use heed::byteorder::BigEndian;
1132    ///
1133    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1134    /// # let dir = tempfile::tempdir()?;
1135    /// # let env = unsafe { EnvOpenOptions::new()
1136    /// #     .map_size(10 * 1024 * 1024) // 10MB
1137    /// #     .max_dbs(3000)
1138    /// #     .open(dir.path())?
1139    /// # };
1140    /// type BEI32 = I32<BigEndian>;
1141    ///
1142    /// let mut wtxn = env.write_txn()?;
1143    /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
1144    ///
1145    /// # db.clear(&mut wtxn)?;
1146    /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
1147    /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
1148    /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
1149    ///
1150    /// let mut iter = db.rev_iter_mut(&mut wtxn)?;
1151    /// assert_eq!(iter.next().transpose()?, Some((42, "i-am-forty-two")));
1152    /// let ret = unsafe { iter.del_current()? };
1153    /// assert!(ret);
1154    ///
1155    /// assert_eq!(iter.next().transpose()?, Some((27, "i-am-twenty-seven")));
1156    /// assert_eq!(iter.next().transpose()?, Some((13, "i-am-thirteen")));
1157    /// let ret = unsafe { iter.put_current(&13, "i-am-the-new-thirteen")? };
1158    /// assert!(ret);
1159    ///
1160    /// assert_eq!(iter.next().transpose()?, None);
1161    ///
1162    /// drop(iter);
1163    ///
1164    /// let ret = db.get(&wtxn, &42)?;
1165    /// assert_eq!(ret, None);
1166    ///
1167    /// let ret = db.get(&wtxn, &13)?;
1168    /// assert_eq!(ret, Some("i-am-the-new-thirteen"));
1169    ///
1170    /// wtxn.commit()?;
1171    /// # Ok(()) }
1172    /// ```
1173    pub fn rev_iter_mut<'txn>(&self, txn: &'txn mut RwTxn) -> Result<RwRevIter<'txn, KC, DC>> {
1174        assert_eq_env_db_txn!(self, txn);
1175
1176        RwCursor::new(txn, self.dbi).map(|cursor| RwRevIter::new(cursor))
1177    }
1178
1179    /// Return a lexicographically ordered iterator of a range of key-value pairs in this database.
1180    ///
1181    /// Comparisons are made by using the bytes representation of the key.
1182    ///
1183    /// You can make this iterator `Send`able between threads by
1184    /// using the `read-txn-no-tls` crate feature.
1185    ///
1186    /// ```
1187    /// # use std::fs;
1188    /// # use std::path::Path;
1189    /// # use heed::EnvOpenOptions;
1190    /// use heed::Database;
1191    /// use heed::types::*;
1192    /// use heed::byteorder::BigEndian;
1193    ///
1194    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1195    /// # let dir = tempfile::tempdir()?;
1196    /// # let env = unsafe { EnvOpenOptions::new()
1197    /// #     .map_size(10 * 1024 * 1024) // 10MB
1198    /// #     .max_dbs(3000)
1199    /// #     .open(dir.path())?
1200    /// # };
1201    /// type BEI32 = I32<BigEndian>;
1202    ///
1203    /// let mut wtxn = env.write_txn()?;
1204    /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
1205    ///
1206    /// # db.clear(&mut wtxn)?;
1207    /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
1208    /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
1209    /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
1210    /// db.put(&mut wtxn, &521, "i-am-five-hundred-and-twenty-one")?;
1211    ///
1212    /// let range = 27..=42;
1213    /// let mut iter = db.range(&wtxn, &range)?;
1214    /// assert_eq!(iter.next().transpose()?, Some((27, "i-am-twenty-seven")));
1215    /// assert_eq!(iter.next().transpose()?, Some((42, "i-am-forty-two")));
1216    /// assert_eq!(iter.next().transpose()?, None);
1217    ///
1218    /// drop(iter);
1219    /// wtxn.commit()?;
1220    /// # Ok(()) }
1221    /// ```
1222    pub fn range<'a, 'txn, R>(
1223        &self,
1224        txn: &'txn RoTxn,
1225        range: &'a R,
1226    ) -> Result<RoRange<'txn, KC, DC>>
1227    where
1228        KC: BytesEncode<'a>,
1229        R: RangeBounds<KC::EItem>,
1230    {
1231        assert_eq_env_db_txn!(self, txn);
1232
1233        let start_bound = match range.start_bound() {
1234            Bound::Included(bound) => {
1235                let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1236                Bound::Included(bytes.into_owned())
1237            }
1238            Bound::Excluded(bound) => {
1239                let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1240                Bound::Excluded(bytes.into_owned())
1241            }
1242            Bound::Unbounded => Bound::Unbounded,
1243        };
1244
1245        let end_bound = match range.end_bound() {
1246            Bound::Included(bound) => {
1247                let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1248                Bound::Included(bytes.into_owned())
1249            }
1250            Bound::Excluded(bound) => {
1251                let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1252                Bound::Excluded(bytes.into_owned())
1253            }
1254            Bound::Unbounded => Bound::Unbounded,
1255        };
1256
1257        RoCursor::new(txn, self.dbi).map(|cursor| RoRange::new(cursor, start_bound, end_bound))
1258    }
1259
1260    /// Return a mutable lexicographically ordered iterator of a range of
1261    /// key-value pairs in this database.
1262    ///
1263    /// Comparisons are made by using the bytes representation of the key.
1264    ///
1265    /// ```
1266    /// # use std::fs;
1267    /// # use std::path::Path;
1268    /// # use heed::EnvOpenOptions;
1269    /// use heed::Database;
1270    /// use heed::types::*;
1271    /// use heed::byteorder::BigEndian;
1272    ///
1273    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1274    /// # let dir = tempfile::tempdir()?;
1275    /// # let env = unsafe { EnvOpenOptions::new()
1276    /// #     .map_size(10 * 1024 * 1024) // 10MB
1277    /// #     .max_dbs(3000)
1278    /// #     .open(dir.path())?
1279    /// # };
1280    /// type BEI32 = I32<BigEndian>;
1281    ///
1282    /// let mut wtxn = env.write_txn()?;
1283    /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
1284    ///
1285    /// # db.clear(&mut wtxn)?;
1286    /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
1287    /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
1288    /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
1289    /// db.put(&mut wtxn, &521, "i-am-five-hundred-and-twenty-one")?;
1290    ///
1291    /// let range = 27..=42;
1292    /// let mut range = db.range_mut(&mut wtxn, &range)?;
1293    /// assert_eq!(range.next().transpose()?, Some((27, "i-am-twenty-seven")));
1294    /// let ret = unsafe { range.del_current()? };
1295    /// assert!(ret);
1296    /// assert_eq!(range.next().transpose()?, Some((42, "i-am-forty-two")));
1297    /// let ret = unsafe { range.put_current(&42, "i-am-the-new-forty-two")? };
1298    /// assert!(ret);
1299    ///
1300    /// assert_eq!(range.next().transpose()?, None);
1301    /// drop(range);
1302    ///
1303    ///
1304    /// let mut iter = db.iter(&wtxn)?;
1305    /// assert_eq!(iter.next().transpose()?, Some((13, "i-am-thirteen")));
1306    /// assert_eq!(iter.next().transpose()?, Some((42, "i-am-the-new-forty-two")));
1307    /// assert_eq!(iter.next().transpose()?, Some((521, "i-am-five-hundred-and-twenty-one")));
1308    /// assert_eq!(iter.next().transpose()?, None);
1309    ///
1310    /// drop(iter);
1311    /// wtxn.commit()?;
1312    /// # Ok(()) }
1313    /// ```
1314    pub fn range_mut<'a, 'txn, R>(
1315        &self,
1316        txn: &'txn mut RwTxn,
1317        range: &'a R,
1318    ) -> Result<RwRange<'txn, KC, DC>>
1319    where
1320        KC: BytesEncode<'a>,
1321        R: RangeBounds<KC::EItem>,
1322    {
1323        assert_eq_env_db_txn!(self, txn);
1324
1325        let start_bound = match range.start_bound() {
1326            Bound::Included(bound) => {
1327                let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1328                Bound::Included(bytes.into_owned())
1329            }
1330            Bound::Excluded(bound) => {
1331                let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1332                Bound::Excluded(bytes.into_owned())
1333            }
1334            Bound::Unbounded => Bound::Unbounded,
1335        };
1336
1337        let end_bound = match range.end_bound() {
1338            Bound::Included(bound) => {
1339                let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1340                Bound::Included(bytes.into_owned())
1341            }
1342            Bound::Excluded(bound) => {
1343                let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1344                Bound::Excluded(bytes.into_owned())
1345            }
1346            Bound::Unbounded => Bound::Unbounded,
1347        };
1348
1349        RwCursor::new(txn, self.dbi).map(|cursor| RwRange::new(cursor, start_bound, end_bound))
1350    }
1351
1352    /// Return a reversed lexicographically ordered iterator of a range of key-value
1353    /// pairs in this database.
1354    ///
1355    /// Comparisons are made by using the bytes representation of the key.
1356    ///
1357    /// You can make this iterator `Send`able between threads by
1358    /// using the `read-txn-no-tls` crate feature.
1359    ///
1360    /// ```
1361    /// # use std::fs;
1362    /// # use std::path::Path;
1363    /// # use heed::EnvOpenOptions;
1364    /// use heed::Database;
1365    /// use heed::types::*;
1366    /// use heed::byteorder::BigEndian;
1367    ///
1368    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1369    /// # let dir = tempfile::tempdir()?;
1370    /// # let env = unsafe { EnvOpenOptions::new()
1371    /// #     .map_size(10 * 1024 * 1024) // 10MB
1372    /// #     .max_dbs(3000)
1373    /// #     .open(dir.path())?
1374    /// # };
1375    /// type BEI32 = I32<BigEndian>;
1376    ///
1377    /// let mut wtxn = env.write_txn()?;
1378    /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
1379    ///
1380    /// # db.clear(&mut wtxn)?;
1381    /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
1382    /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
1383    /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
1384    /// db.put(&mut wtxn, &521, "i-am-five-hundred-and-twenty-one")?;
1385    ///
1386    /// let range = 27..=43;
1387    /// let mut iter = db.rev_range(&wtxn, &range)?;
1388    /// assert_eq!(iter.next().transpose()?, Some((42, "i-am-forty-two")));
1389    /// assert_eq!(iter.next().transpose()?, Some((27, "i-am-twenty-seven")));
1390    /// assert_eq!(iter.next().transpose()?, None);
1391    ///
1392    /// drop(iter);
1393    /// wtxn.commit()?;
1394    /// # Ok(()) }
1395    /// ```
1396    pub fn rev_range<'a, 'txn, R>(
1397        &self,
1398        txn: &'txn RoTxn,
1399        range: &'a R,
1400    ) -> Result<RoRevRange<'txn, KC, DC>>
1401    where
1402        KC: BytesEncode<'a>,
1403        R: RangeBounds<KC::EItem>,
1404    {
1405        assert_eq_env_db_txn!(self, txn);
1406
1407        let start_bound = match range.start_bound() {
1408            Bound::Included(bound) => {
1409                let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1410                Bound::Included(bytes.into_owned())
1411            }
1412            Bound::Excluded(bound) => {
1413                let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1414                Bound::Excluded(bytes.into_owned())
1415            }
1416            Bound::Unbounded => Bound::Unbounded,
1417        };
1418
1419        let end_bound = match range.end_bound() {
1420            Bound::Included(bound) => {
1421                let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1422                Bound::Included(bytes.into_owned())
1423            }
1424            Bound::Excluded(bound) => {
1425                let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1426                Bound::Excluded(bytes.into_owned())
1427            }
1428            Bound::Unbounded => Bound::Unbounded,
1429        };
1430
1431        RoCursor::new(txn, self.dbi).map(|cursor| RoRevRange::new(cursor, start_bound, end_bound))
1432    }
1433
1434    /// Return a mutable reversed lexicographically ordered iterator of a range of
1435    /// key-value pairs in this database.
1436    ///
1437    /// Comparisons are made by using the bytes representation of the key.
1438    ///
1439    /// ```
1440    /// # use std::fs;
1441    /// # use std::path::Path;
1442    /// # use heed::EnvOpenOptions;
1443    /// use heed::Database;
1444    /// use heed::types::*;
1445    /// use heed::byteorder::BigEndian;
1446    ///
1447    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1448    /// # let dir = tempfile::tempdir()?;
1449    /// # let env = unsafe { EnvOpenOptions::new()
1450    /// #     .map_size(10 * 1024 * 1024) // 10MB
1451    /// #     .max_dbs(3000)
1452    /// #     .open(dir.path())?
1453    /// # };
1454    /// type BEI32 = I32<BigEndian>;
1455    ///
1456    /// let mut wtxn = env.write_txn()?;
1457    /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
1458    ///
1459    /// # db.clear(&mut wtxn)?;
1460    /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
1461    /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
1462    /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
1463    /// db.put(&mut wtxn, &521, "i-am-five-hundred-and-twenty-one")?;
1464    ///
1465    /// let range = 27..=42;
1466    /// let mut range = db.rev_range_mut(&mut wtxn, &range)?;
1467    /// assert_eq!(range.next().transpose()?, Some((42, "i-am-forty-two")));
1468    /// let ret = unsafe { range.del_current()? };
1469    /// assert!(ret);
1470    /// assert_eq!(range.next().transpose()?, Some((27, "i-am-twenty-seven")));
1471    /// let ret = unsafe { range.put_current(&27, "i-am-the-new-twenty-seven")? };
1472    /// assert!(ret);
1473    ///
1474    /// assert_eq!(range.next().transpose()?, None);
1475    /// drop(range);
1476    ///
1477    ///
1478    /// let mut iter = db.iter(&wtxn)?;
1479    /// assert_eq!(iter.next().transpose()?, Some((13, "i-am-thirteen")));
1480    /// assert_eq!(iter.next().transpose()?, Some((27, "i-am-the-new-twenty-seven")));
1481    /// assert_eq!(iter.next().transpose()?, Some((521, "i-am-five-hundred-and-twenty-one")));
1482    /// assert_eq!(iter.next().transpose()?, None);
1483    ///
1484    /// drop(iter);
1485    /// wtxn.commit()?;
1486    /// # Ok(()) }
1487    /// ```
1488    pub fn rev_range_mut<'a, 'txn, R>(
1489        &self,
1490        txn: &'txn mut RwTxn,
1491        range: &'a R,
1492    ) -> Result<RwRevRange<'txn, KC, DC>>
1493    where
1494        KC: BytesEncode<'a>,
1495        R: RangeBounds<KC::EItem>,
1496    {
1497        assert_eq_env_db_txn!(self, txn);
1498
1499        let start_bound = match range.start_bound() {
1500            Bound::Included(bound) => {
1501                let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1502                Bound::Included(bytes.into_owned())
1503            }
1504            Bound::Excluded(bound) => {
1505                let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1506                Bound::Excluded(bytes.into_owned())
1507            }
1508            Bound::Unbounded => Bound::Unbounded,
1509        };
1510
1511        let end_bound = match range.end_bound() {
1512            Bound::Included(bound) => {
1513                let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1514                Bound::Included(bytes.into_owned())
1515            }
1516            Bound::Excluded(bound) => {
1517                let bytes = KC::bytes_encode(bound).map_err(Error::Encoding)?;
1518                Bound::Excluded(bytes.into_owned())
1519            }
1520            Bound::Unbounded => Bound::Unbounded,
1521        };
1522
1523        RwCursor::new(txn, self.dbi).map(|cursor| RwRevRange::new(cursor, start_bound, end_bound))
1524    }
1525
1526    /// Return a lexicographically ordered iterator of all key-value pairs
1527    /// in this database that starts with the given prefix.
1528    ///
1529    /// Comparisons are made by using the bytes representation of the key.
1530    ///
1531    /// You can make this iterator `Send`able between threads by
1532    /// using the `read-txn-no-tls` crate feature.
1533    ///
1534    /// ```
1535    /// # use std::fs;
1536    /// # use std::path::Path;
1537    /// # use heed::EnvOpenOptions;
1538    /// use heed::Database;
1539    /// use heed::types::*;
1540    /// use heed::byteorder::BigEndian;
1541    ///
1542    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1543    /// # let dir = tempfile::tempdir()?;
1544    /// # let env = unsafe { EnvOpenOptions::new()
1545    /// #     .map_size(10 * 1024 * 1024) // 10MB
1546    /// #     .max_dbs(3000)
1547    /// #     .open(dir.path())?
1548    /// # };
1549    /// type BEI32 = I32<BigEndian>;
1550    ///
1551    /// let mut wtxn = env.write_txn()?;
1552    /// let db: Database<Str, BEI32> = env.create_database(&mut wtxn, Some("iter-i32"))?;
1553    ///
1554    /// # db.clear(&mut wtxn)?;
1555    /// db.put(&mut wtxn, "i-am-twenty-eight", &28)?;
1556    /// db.put(&mut wtxn, "i-am-twenty-seven", &27)?;
1557    /// db.put(&mut wtxn, "i-am-twenty-nine",  &29)?;
1558    /// db.put(&mut wtxn, "i-am-forty-one",    &41)?;
1559    /// db.put(&mut wtxn, "i-am-forty-two",    &42)?;
1560    ///
1561    /// let mut iter = db.prefix_iter(&mut wtxn, "i-am-twenty")?;
1562    /// assert_eq!(iter.next().transpose()?, Some(("i-am-twenty-eight", 28)));
1563    /// assert_eq!(iter.next().transpose()?, Some(("i-am-twenty-nine", 29)));
1564    /// assert_eq!(iter.next().transpose()?, Some(("i-am-twenty-seven", 27)));
1565    /// assert_eq!(iter.next().transpose()?, None);
1566    ///
1567    /// drop(iter);
1568    /// wtxn.commit()?;
1569    /// # Ok(()) }
1570    /// ```
1571    pub fn prefix_iter<'a, 'txn>(
1572        &self,
1573        txn: &'txn RoTxn,
1574        prefix: &'a KC::EItem,
1575    ) -> Result<RoPrefix<'txn, KC, DC, C>>
1576    where
1577        KC: BytesEncode<'a>,
1578        C: LexicographicComparator,
1579    {
1580        assert_eq_env_db_txn!(self, txn);
1581
1582        let prefix_bytes = KC::bytes_encode(prefix).map_err(Error::Encoding)?;
1583        let prefix_bytes = prefix_bytes.into_owned();
1584        RoCursor::new(txn, self.dbi).map(|cursor| RoPrefix::new(cursor, prefix_bytes))
1585    }
1586
1587    /// Return a mutable lexicographically ordered iterator of all key-value pairs
1588    /// in this database that starts with the given prefix.
1589    ///
1590    /// Comparisons are made by using the bytes representation of the key.
1591    ///
1592    /// ```
1593    /// # use std::fs;
1594    /// # use std::path::Path;
1595    /// # use heed::EnvOpenOptions;
1596    /// use heed::Database;
1597    /// use heed::types::*;
1598    /// use heed::byteorder::BigEndian;
1599    ///
1600    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1601    /// # let dir = tempfile::tempdir()?;
1602    /// # let env = unsafe { EnvOpenOptions::new()
1603    /// #     .map_size(10 * 1024 * 1024) // 10MB
1604    /// #     .max_dbs(3000)
1605    /// #     .open(dir.path())?
1606    /// # };
1607    /// type BEI32 = I32<BigEndian>;
1608    ///
1609    /// let mut wtxn = env.write_txn()?;
1610    /// let db: Database<Str, BEI32> = env.create_database(&mut wtxn, Some("iter-i32"))?;
1611    ///
1612    /// # db.clear(&mut wtxn)?;
1613    /// db.put(&mut wtxn, "i-am-twenty-eight", &28)?;
1614    /// db.put(&mut wtxn, "i-am-twenty-seven", &27)?;
1615    /// db.put(&mut wtxn, "i-am-twenty-nine",  &29)?;
1616    /// db.put(&mut wtxn, "i-am-forty-one",    &41)?;
1617    /// db.put(&mut wtxn, "i-am-forty-two",    &42)?;
1618    ///
1619    /// let mut iter = db.prefix_iter_mut(&mut wtxn, "i-am-twenty")?;
1620    /// assert_eq!(iter.next().transpose()?, Some(("i-am-twenty-eight", 28)));
1621    /// let ret = unsafe { iter.del_current()? };
1622    /// assert!(ret);
1623    ///
1624    /// assert_eq!(iter.next().transpose()?, Some(("i-am-twenty-nine", 29)));
1625    /// assert_eq!(iter.next().transpose()?, Some(("i-am-twenty-seven", 27)));
1626    /// let ret = unsafe { iter.put_current("i-am-twenty-seven", &27000)? };
1627    /// assert!(ret);
1628    ///
1629    /// assert_eq!(iter.next().transpose()?, None);
1630    ///
1631    /// drop(iter);
1632    ///
1633    /// let ret = db.get(&wtxn, "i-am-twenty-eight")?;
1634    /// assert_eq!(ret, None);
1635    ///
1636    /// let ret = db.get(&wtxn, "i-am-twenty-seven")?;
1637    /// assert_eq!(ret, Some(27000));
1638    ///
1639    /// wtxn.commit()?;
1640    /// # Ok(()) }
1641    /// ```
1642    pub fn prefix_iter_mut<'a, 'txn>(
1643        &self,
1644        txn: &'txn mut RwTxn,
1645        prefix: &'a KC::EItem,
1646    ) -> Result<RwPrefix<'txn, KC, DC, C>>
1647    where
1648        KC: BytesEncode<'a>,
1649        C: LexicographicComparator,
1650    {
1651        assert_eq_env_db_txn!(self, txn);
1652
1653        let prefix_bytes = KC::bytes_encode(prefix).map_err(Error::Encoding)?;
1654        let prefix_bytes = prefix_bytes.into_owned();
1655        RwCursor::new(txn, self.dbi).map(|cursor| RwPrefix::new(cursor, prefix_bytes))
1656    }
1657
1658    /// Return a reversed lexicographically ordered iterator of all key-value pairs
1659    /// in this database that starts with the given prefix.
1660    ///
1661    /// Comparisons are made by using the bytes representation of the key.
1662    ///
1663    /// You can make this iterator `Send`able between threads by
1664    /// using the `read-txn-no-tls` crate feature.
1665    ///
1666    /// ```
1667    /// # use std::fs;
1668    /// # use std::path::Path;
1669    /// # use heed::EnvOpenOptions;
1670    /// use heed::Database;
1671    /// use heed::types::*;
1672    /// use heed::byteorder::BigEndian;
1673    ///
1674    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1675    /// # let dir = tempfile::tempdir()?;
1676    /// # let env = unsafe { EnvOpenOptions::new()
1677    /// #     .map_size(10 * 1024 * 1024) // 10MB
1678    /// #     .max_dbs(3000)
1679    /// #     .open(dir.path())?
1680    /// # };
1681    /// type BEI32 = I32<BigEndian>;
1682    ///
1683    /// let mut wtxn = env.write_txn()?;
1684    /// let db: Database<Str, BEI32> = env.create_database(&mut wtxn, Some("iter-i32"))?;
1685    ///
1686    /// # db.clear(&mut wtxn)?;
1687    /// db.put(&mut wtxn, "i-am-twenty-eight", &28)?;
1688    /// db.put(&mut wtxn, "i-am-twenty-seven", &27)?;
1689    /// db.put(&mut wtxn, "i-am-twenty-nine",  &29)?;
1690    /// db.put(&mut wtxn, "i-am-forty-one",    &41)?;
1691    /// db.put(&mut wtxn, "i-am-forty-two",    &42)?;
1692    ///
1693    /// let mut iter = db.rev_prefix_iter(&mut wtxn, "i-am-twenty")?;
1694    /// assert_eq!(iter.next().transpose()?, Some(("i-am-twenty-seven", 27)));
1695    /// assert_eq!(iter.next().transpose()?, Some(("i-am-twenty-nine", 29)));
1696    /// assert_eq!(iter.next().transpose()?, Some(("i-am-twenty-eight", 28)));
1697    /// assert_eq!(iter.next().transpose()?, None);
1698    ///
1699    /// drop(iter);
1700    /// wtxn.commit()?;
1701    /// # Ok(()) }
1702    /// ```
1703    pub fn rev_prefix_iter<'a, 'txn>(
1704        &self,
1705        txn: &'txn RoTxn,
1706        prefix: &'a KC::EItem,
1707    ) -> Result<RoRevPrefix<'txn, KC, DC, C>>
1708    where
1709        KC: BytesEncode<'a>,
1710        C: LexicographicComparator,
1711    {
1712        assert_eq_env_db_txn!(self, txn);
1713
1714        let prefix_bytes = KC::bytes_encode(prefix).map_err(Error::Encoding)?;
1715        let prefix_bytes = prefix_bytes.into_owned();
1716        RoCursor::new(txn, self.dbi).map(|cursor| RoRevPrefix::new(cursor, prefix_bytes))
1717    }
1718
1719    /// Return a mutable reversed lexicographically ordered iterator of all key-value pairs
1720    /// in this database that starts with the given prefix.
1721    ///
1722    /// Comparisons are made by using the bytes representation of the key.
1723    ///
1724    /// ```
1725    /// # use std::fs;
1726    /// # use std::path::Path;
1727    /// # use heed::EnvOpenOptions;
1728    /// use heed::Database;
1729    /// use heed::types::*;
1730    /// use heed::byteorder::BigEndian;
1731    ///
1732    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1733    /// # let dir = tempfile::tempdir()?;
1734    /// # let env = unsafe { EnvOpenOptions::new()
1735    /// #     .map_size(10 * 1024 * 1024) // 10MB
1736    /// #     .max_dbs(3000)
1737    /// #     .open(dir.path())?
1738    /// # };
1739    /// type BEI32 = I32<BigEndian>;
1740    ///
1741    /// let mut wtxn = env.write_txn()?;
1742    /// let db: Database<Str, BEI32> = env.create_database(&mut wtxn, Some("iter-i32"))?;
1743    ///
1744    /// # db.clear(&mut wtxn)?;
1745    /// db.put(&mut wtxn, "i-am-twenty-eight", &28)?;
1746    /// db.put(&mut wtxn, "i-am-twenty-seven", &27)?;
1747    /// db.put(&mut wtxn, "i-am-twenty-nine",  &29)?;
1748    /// db.put(&mut wtxn, "i-am-forty-one",    &41)?;
1749    /// db.put(&mut wtxn, "i-am-forty-two",    &42)?;
1750    ///
1751    /// let mut iter = db.rev_prefix_iter_mut(&mut wtxn, "i-am-twenty")?;
1752    /// assert_eq!(iter.next().transpose()?, Some(("i-am-twenty-seven", 27)));
1753    /// let ret = unsafe { iter.del_current()? };
1754    /// assert!(ret);
1755    ///
1756    /// assert_eq!(iter.next().transpose()?, Some(("i-am-twenty-nine", 29)));
1757    /// assert_eq!(iter.next().transpose()?, Some(("i-am-twenty-eight", 28)));
1758    /// let ret = unsafe { iter.put_current("i-am-twenty-eight", &28000)? };
1759    /// assert!(ret);
1760    ///
1761    /// assert_eq!(iter.next().transpose()?, None);
1762    ///
1763    /// drop(iter);
1764    ///
1765    /// let ret = db.get(&wtxn, "i-am-twenty-seven")?;
1766    /// assert_eq!(ret, None);
1767    ///
1768    /// let ret = db.get(&wtxn, "i-am-twenty-eight")?;
1769    /// assert_eq!(ret, Some(28000));
1770    ///
1771    /// wtxn.commit()?;
1772    /// # Ok(()) }
1773    /// ```
1774    pub fn rev_prefix_iter_mut<'a, 'txn>(
1775        &self,
1776        txn: &'txn mut RwTxn,
1777        prefix: &'a KC::EItem,
1778    ) -> Result<RwRevPrefix<'txn, KC, DC, C>>
1779    where
1780        KC: BytesEncode<'a>,
1781        C: LexicographicComparator,
1782    {
1783        assert_eq_env_db_txn!(self, txn);
1784
1785        let prefix_bytes = KC::bytes_encode(prefix).map_err(Error::Encoding)?;
1786        let prefix_bytes = prefix_bytes.into_owned();
1787        RwCursor::new(txn, self.dbi).map(|cursor| RwRevPrefix::new(cursor, prefix_bytes))
1788    }
1789
1790    /// Insert a key-value pair in this database, replacing any previous value. The entry is
1791    /// written with no specific flag.
1792    ///
1793    /// ```
1794    /// # use std::fs;
1795    /// # use std::path::Path;
1796    /// # use heed::EnvOpenOptions;
1797    /// use heed::Database;
1798    /// use heed::types::*;
1799    /// use heed::byteorder::BigEndian;
1800    ///
1801    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1802    /// # let dir = tempfile::tempdir()?;
1803    /// # let env = unsafe { EnvOpenOptions::new()
1804    /// #     .map_size(10 * 1024 * 1024) // 10MB
1805    /// #     .max_dbs(3000)
1806    /// #     .open(dir.path())?
1807    /// # };
1808    /// type BEI32 = I32<BigEndian>;
1809    ///
1810    /// let mut wtxn = env.write_txn()?;
1811    /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
1812    ///
1813    /// # db.clear(&mut wtxn)?;
1814    /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
1815    /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
1816    /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
1817    /// db.put(&mut wtxn, &521, "i-am-five-hundred-and-twenty-one")?;
1818    ///
1819    /// let ret = db.get(&mut wtxn, &27)?;
1820    /// assert_eq!(ret, Some("i-am-twenty-seven"));
1821    ///
1822    /// wtxn.commit()?;
1823    /// # Ok(()) }
1824    /// ```
1825    pub fn put<'a>(&self, txn: &mut RwTxn, key: &'a KC::EItem, data: &'a DC::EItem) -> Result<()>
1826    where
1827        KC: BytesEncode<'a>,
1828        DC: BytesEncode<'a>,
1829    {
1830        assert_eq_env_db_txn!(self, txn);
1831
1832        let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
1833        let data_bytes: Cow<[u8]> = DC::bytes_encode(data).map_err(Error::Encoding)?;
1834
1835        let mut key_val = unsafe { crate::into_val(&key_bytes) };
1836        let mut data_val = unsafe { crate::into_val(&data_bytes) };
1837        let flags = 0;
1838
1839        unsafe {
1840            mdb_result(ffi::mdb_put(txn.txn.txn, self.dbi, &mut key_val, &mut data_val, flags))?
1841        }
1842
1843        Ok(())
1844    }
1845
1846    /// Insert a key-value pair where the value can directly be written to disk, replacing any
1847    /// previous value.
1848    ///
1849    /// ```
1850    /// # use std::fs;
1851    /// # use std::path::Path;
1852    /// # use heed::EnvOpenOptions;
1853    /// use std::io::Write;
1854    /// use heed::Database;
1855    /// use heed::types::*;
1856    /// use heed::byteorder::BigEndian;
1857    ///
1858    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1859    /// # let dir = tempfile::tempdir()?;
1860    /// # let env = unsafe { EnvOpenOptions::new()
1861    /// #     .map_size(10 * 1024 * 1024) // 10MB
1862    /// #     .max_dbs(3000)
1863    /// #     .open(dir.path())?
1864    /// # };
1865    /// type BEI32 = I32<BigEndian>;
1866    ///
1867    /// let mut wtxn = env.write_txn()?;
1868    /// let db = env.create_database::<BEI32, Str>(&mut wtxn, Some("number-string"))?;
1869    ///
1870    /// # db.clear(&mut wtxn)?;
1871    /// let value = "I am a long long long value";
1872    /// db.put_reserved(&mut wtxn, &42, value.len(), |reserved| {
1873    ///     reserved.write_all(value.as_bytes())
1874    /// })?;
1875    ///
1876    /// let ret = db.get(&mut wtxn, &42)?;
1877    /// assert_eq!(ret, Some(value));
1878    ///
1879    /// wtxn.commit()?;
1880    /// # Ok(()) }
1881    /// ```
1882    pub fn put_reserved<'a, F>(
1883        &self,
1884        txn: &mut RwTxn,
1885        key: &'a KC::EItem,
1886        data_size: usize,
1887        write_func: F,
1888    ) -> Result<()>
1889    where
1890        KC: BytesEncode<'a>,
1891        F: FnOnce(&mut ReservedSpace) -> io::Result<()>,
1892    {
1893        assert_eq_env_db_txn!(self, txn);
1894
1895        let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
1896        let mut key_val = unsafe { crate::into_val(&key_bytes) };
1897        let mut reserved = ffi::reserve_size_val(data_size);
1898        let flags = ffi::MDB_RESERVE;
1899
1900        unsafe {
1901            mdb_result(ffi::mdb_put(txn.txn.txn, self.dbi, &mut key_val, &mut reserved, flags))?
1902        }
1903
1904        let mut reserved = unsafe { ReservedSpace::from_val(reserved) };
1905        write_func(&mut reserved)?;
1906        if reserved.remaining() == 0 {
1907            Ok(())
1908        } else {
1909            Err(io::Error::from(io::ErrorKind::UnexpectedEof).into())
1910        }
1911    }
1912
1913    /// Insert a key-value pair in this database, replacing any previous value. The entry is
1914    /// written with the specified flags.
1915    ///
1916    /// ```
1917    /// # use std::fs;
1918    /// # use std::path::Path;
1919    /// # use heed::EnvOpenOptions;
1920    /// use heed::{Database, PutFlags, DatabaseFlags, Error, MdbError};
1921    /// use heed::types::*;
1922    /// use heed::byteorder::BigEndian;
1923    ///
1924    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1925    /// # let dir = tempfile::tempdir()?;
1926    /// # let env = unsafe { EnvOpenOptions::new()
1927    /// #     .map_size(10 * 1024 * 1024) // 10MB
1928    /// #     .max_dbs(3000)
1929    /// #     .open(dir.path())?
1930    /// # };
1931    /// type BEI32 = I32<BigEndian>;
1932    ///
1933    /// let mut wtxn = env.write_txn()?;
1934    /// let db = env.database_options()
1935    ///     .types::<BEI32, Str>()
1936    ///     .name("dup-i32")
1937    ///     .flags(DatabaseFlags::DUP_SORT)
1938    ///     .create(&mut wtxn)?;
1939    ///
1940    /// # db.clear(&mut wtxn)?;
1941    /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
1942    /// db.put(&mut wtxn, &42, "i-am-so-cool")?;
1943    /// db.put(&mut wtxn, &42, "i-am-the-king")?;
1944    /// db.put(&mut wtxn, &42, "i-am-fun")?;
1945    /// db.put_with_flags(&mut wtxn, PutFlags::APPEND, &54, "i-am-older-than-you")?;
1946    /// db.put_with_flags(&mut wtxn, PutFlags::APPEND_DUP, &54, "ok-but-i-am-better-than-you")?;
1947    /// // You can compose flags by OR'ing them
1948    /// db.put_with_flags(&mut wtxn, PutFlags::APPEND_DUP | PutFlags::NO_OVERWRITE, &55, "welcome")?;
1949    ///
1950    /// // The NO_DUP_DATA flag will return KeyExist if we try to insert the exact same key/value pair.
1951    /// let ret = db.put_with_flags(&mut wtxn, PutFlags::NO_DUP_DATA, &54, "ok-but-i-am-better-than-you");
1952    /// assert!(matches!(ret, Err(Error::Mdb(MdbError::KeyExist))));
1953    ///
1954    /// // The NO_OVERWRITE flag will return KeyExist if we try to insert something with an already existing key.
1955    /// let ret = db.put_with_flags(&mut wtxn, PutFlags::NO_OVERWRITE, &54, "there-can-be-only-one-data");
1956    /// assert!(matches!(ret, Err(Error::Mdb(MdbError::KeyExist))));
1957    ///
1958    /// let mut iter = db.iter(&wtxn)?;
1959    /// assert_eq!(iter.next().transpose()?, Some((42, "i-am-forty-two")));
1960    /// assert_eq!(iter.next().transpose()?, Some((42, "i-am-fun")));
1961    /// assert_eq!(iter.next().transpose()?, Some((42, "i-am-so-cool")));
1962    /// assert_eq!(iter.next().transpose()?, Some((42, "i-am-the-king")));
1963    /// assert_eq!(iter.next().transpose()?, Some((54, "i-am-older-than-you")));
1964    /// assert_eq!(iter.next().transpose()?, Some((54, "ok-but-i-am-better-than-you")));
1965    /// assert_eq!(iter.next().transpose()?, Some((55, "welcome")));
1966    /// assert_eq!(iter.next().transpose()?, None);
1967    ///
1968    /// drop(iter);
1969    /// wtxn.commit()?;
1970    /// # Ok(()) }
1971    /// ```
1972    pub fn put_with_flags<'a>(
1973        &self,
1974        txn: &mut RwTxn,
1975        flags: PutFlags,
1976        key: &'a KC::EItem,
1977        data: &'a DC::EItem,
1978    ) -> Result<()>
1979    where
1980        KC: BytesEncode<'a>,
1981        DC: BytesEncode<'a>,
1982    {
1983        assert_eq_env_db_txn!(self, txn);
1984
1985        let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
1986        let data_bytes: Cow<[u8]> = DC::bytes_encode(data).map_err(Error::Encoding)?;
1987
1988        let mut key_val = unsafe { crate::into_val(&key_bytes) };
1989        let mut data_val = unsafe { crate::into_val(&data_bytes) };
1990        let flags = flags.bits();
1991
1992        unsafe {
1993            mdb_result(ffi::mdb_put(txn.txn.txn, self.dbi, &mut key_val, &mut data_val, flags))?
1994        }
1995
1996        Ok(())
1997    }
1998
1999    /// Attempt to insert a key-value pair in this database, or if a value already exists for the
2000    /// key, returns the previous value.
2001    ///
2002    /// The entry is always written with the [`NO_OVERWRITE`](PutFlags::NO_OVERWRITE) flag.
2003    ///
2004    /// ```
2005    /// # use heed::EnvOpenOptions;
2006    /// use heed::Database;
2007    /// use heed::types::*;
2008    /// use heed::byteorder::BigEndian;
2009    ///
2010    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
2011    /// # let dir = tempfile::tempdir()?;
2012    /// # let env = unsafe { EnvOpenOptions::new()
2013    /// #     .map_size(10 * 1024 * 1024) // 10MB
2014    /// #     .max_dbs(3000)
2015    /// #     .open(dir.path())?
2016    /// # };
2017    /// type BEI32 = I32<BigEndian>;
2018    ///
2019    /// let mut wtxn = env.write_txn()?;
2020    /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
2021    ///
2022    /// # db.clear(&mut wtxn)?;
2023    /// assert_eq!(db.get_or_put(&mut wtxn, &42, "i-am-forty-two")?, None);
2024    /// assert_eq!(db.get_or_put(&mut wtxn, &42, "the meaning of life")?, Some("i-am-forty-two"));
2025    ///
2026    /// let ret = db.get(&mut wtxn, &42)?;
2027    /// assert_eq!(ret, Some("i-am-forty-two"));
2028    ///
2029    /// wtxn.commit()?;
2030    /// # Ok(()) }
2031    /// ```
2032    pub fn get_or_put<'a, 'txn>(
2033        &'txn self,
2034        txn: &mut RwTxn,
2035        key: &'a KC::EItem,
2036        data: &'a DC::EItem,
2037    ) -> Result<Option<DC::DItem>>
2038    where
2039        KC: BytesEncode<'a>,
2040        DC: BytesEncode<'a> + BytesDecode<'a>,
2041    {
2042        self.get_or_put_with_flags(txn, PutFlags::empty(), key, data)
2043    }
2044
2045    /// Attempt to insert a key-value pair in this database, or if a value already exists for the
2046    /// key, returns the previous value.
2047    ///
2048    /// The entry is written with the specified flags, in addition to
2049    /// [`NO_OVERWRITE`](PutFlags::NO_OVERWRITE) which is always used.
2050    ///
2051    /// ```
2052    /// # use heed::EnvOpenOptions;
2053    /// use heed::{Database, PutFlags};
2054    /// use heed::types::*;
2055    /// use heed::byteorder::BigEndian;
2056    ///
2057    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
2058    /// # let dir = tempfile::tempdir()?;
2059    /// # let env = unsafe { EnvOpenOptions::new()
2060    /// #     .map_size(10 * 1024 * 1024) // 10MB
2061    /// #     .max_dbs(3000)
2062    /// #     .open(dir.path())?
2063    /// # };
2064    /// type BEI32 = I32<BigEndian>;
2065    ///
2066    /// let mut wtxn = env.write_txn()?;
2067    /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
2068    ///
2069    /// # db.clear(&mut wtxn)?;
2070    /// assert_eq!(db.get_or_put_with_flags(&mut wtxn, PutFlags::empty(), &42, "i-am-forty-two")?, None);
2071    /// assert_eq!(db.get_or_put_with_flags(&mut wtxn, PutFlags::empty(), &42, "the meaning of life")?, Some("i-am-forty-two"));
2072    ///
2073    /// let ret = db.get(&mut wtxn, &42)?;
2074    /// assert_eq!(ret, Some("i-am-forty-two"));
2075    ///
2076    /// wtxn.commit()?;
2077    /// # Ok(()) }
2078    /// ```
2079    pub fn get_or_put_with_flags<'a, 'txn>(
2080        &'txn self,
2081        txn: &mut RwTxn,
2082        flags: PutFlags,
2083        key: &'a KC::EItem,
2084        data: &'a DC::EItem,
2085    ) -> Result<Option<DC::DItem>>
2086    where
2087        KC: BytesEncode<'a>,
2088        DC: BytesEncode<'a> + BytesDecode<'a>,
2089    {
2090        assert_eq_env_db_txn!(self, txn);
2091
2092        let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
2093        let data_bytes: Cow<[u8]> = DC::bytes_encode(data).map_err(Error::Encoding)?;
2094
2095        let mut key_val = unsafe { crate::into_val(&key_bytes) };
2096        let mut data_val = unsafe { crate::into_val(&data_bytes) };
2097        let flags = (flags | PutFlags::NO_OVERWRITE).bits();
2098
2099        let result = unsafe {
2100            mdb_result(ffi::mdb_put(txn.txn.txn, self.dbi, &mut key_val, &mut data_val, flags))
2101        };
2102
2103        match result {
2104            // the value was successfully inserted
2105            Ok(()) => Ok(None),
2106            // the key already exists: the previous value is stored in the data parameter
2107            Err(MdbError::KeyExist) => {
2108                let bytes = unsafe { crate::from_val(data_val) };
2109                let data = DC::bytes_decode(bytes).map_err(Error::Decoding)?;
2110                Ok(Some(data))
2111            }
2112            Err(error) => Err(error.into()),
2113        }
2114    }
2115
2116    /// Attempt to insert a key-value pair in this database, where the value can be directly
2117    /// written to disk, or if a value already exists for the key, returns the previous value.
2118    ///
2119    /// The entry is always written with the [`NO_OVERWRITE`](PutFlags::NO_OVERWRITE) and
2120    /// [`MDB_RESERVE`](lmdb_master_sys::MDB_RESERVE) flags.
2121    ///
2122    /// ```
2123    /// # use heed::EnvOpenOptions;
2124    /// use std::io::Write;
2125    /// use heed::{Database, PutFlags};
2126    /// use heed::types::*;
2127    /// use heed::byteorder::BigEndian;
2128    ///
2129    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
2130    /// # let dir = tempfile::tempdir()?;
2131    /// # let env = unsafe { EnvOpenOptions::new()
2132    /// #     .map_size(10 * 1024 * 1024) // 10MB
2133    /// #     .max_dbs(3000)
2134    /// #     .open(dir.path())?
2135    /// # };
2136    /// type BEI32 = I32<BigEndian>;
2137    ///
2138    /// let mut wtxn = env.write_txn()?;
2139    /// let db = env.create_database::<BEI32, Str>(&mut wtxn, Some("number-string"))?;
2140    ///
2141    /// # db.clear(&mut wtxn)?;
2142    /// let long = "I am a long long long value";
2143    /// assert_eq!(
2144    ///     db.get_or_put_reserved(&mut wtxn, &42, long.len(), |reserved| {
2145    ///         reserved.write_all(long.as_bytes())
2146    ///     })?,
2147    ///     None
2148    /// );
2149    ///
2150    /// let longer = "I am an even longer long long long value";
2151    /// assert_eq!(
2152    ///     db.get_or_put_reserved(&mut wtxn, &42, longer.len(), |reserved| {
2153    ///         unreachable!()
2154    ///     })?,
2155    ///     Some(long)
2156    /// );
2157    ///
2158    /// let ret = db.get(&mut wtxn, &42)?;
2159    /// assert_eq!(ret, Some(long));
2160    ///
2161    /// wtxn.commit()?;
2162    /// # Ok(()) }
2163    /// ```
2164    pub fn get_or_put_reserved<'a, 'txn, F>(
2165        &'txn self,
2166        txn: &mut RwTxn,
2167        key: &'a KC::EItem,
2168        data_size: usize,
2169        write_func: F,
2170    ) -> Result<Option<DC::DItem>>
2171    where
2172        KC: BytesEncode<'a>,
2173        F: FnOnce(&mut ReservedSpace) -> io::Result<()>,
2174        DC: BytesDecode<'a>,
2175    {
2176        self.get_or_put_reserved_with_flags(txn, PutFlags::empty(), key, data_size, write_func)
2177    }
2178
2179    /// Attempt to insert a key-value pair in this database, where the value can be directly
2180    /// written to disk, or if a value already exists for the key, returns the previous value.
2181    ///
2182    /// The entry is written with the specified flags, in addition to
2183    /// [`NO_OVERWRITE`](PutFlags::NO_OVERWRITE) and [`MDB_RESERVE`](lmdb_master_sys::MDB_RESERVE)
2184    /// which are always used.
2185    ///
2186    /// ```
2187    /// # use heed::EnvOpenOptions;
2188    /// use std::io::Write;
2189    /// use heed::{Database, PutFlags};
2190    /// use heed::types::*;
2191    /// use heed::byteorder::BigEndian;
2192    ///
2193    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
2194    /// # let dir = tempfile::tempdir()?;
2195    /// # let env = unsafe { EnvOpenOptions::new()
2196    /// #     .map_size(10 * 1024 * 1024) // 10MB
2197    /// #     .max_dbs(3000)
2198    /// #     .open(dir.path())?
2199    /// # };
2200    /// type BEI32 = I32<BigEndian>;
2201    ///
2202    /// let mut wtxn = env.write_txn()?;
2203    /// let db = env.create_database::<BEI32, Str>(&mut wtxn, Some("number-string"))?;
2204    ///
2205    /// # db.clear(&mut wtxn)?;
2206    /// let long = "I am a long long long value";
2207    /// assert_eq!(
2208    ///     db.get_or_put_reserved_with_flags(&mut wtxn, PutFlags::empty(), &42, long.len(), |reserved| {
2209    ///         reserved.write_all(long.as_bytes())
2210    ///     })?,
2211    ///     None
2212    /// );
2213    ///
2214    /// let longer = "I am an even longer long long long value";
2215    /// assert_eq!(
2216    ///     db.get_or_put_reserved_with_flags(&mut wtxn, PutFlags::empty(), &42, longer.len(), |reserved| {
2217    ///         unreachable!()
2218    ///     })?,
2219    ///     Some(long)
2220    /// );
2221    ///
2222    /// let ret = db.get(&mut wtxn, &42)?;
2223    /// assert_eq!(ret, Some(long));
2224    ///
2225    /// wtxn.commit()?;
2226    /// # Ok(()) }
2227    /// ```
2228    pub fn get_or_put_reserved_with_flags<'a, 'txn, F>(
2229        &'txn self,
2230        txn: &mut RwTxn,
2231        flags: PutFlags,
2232        key: &'a KC::EItem,
2233        data_size: usize,
2234        write_func: F,
2235    ) -> Result<Option<DC::DItem>>
2236    where
2237        KC: BytesEncode<'a>,
2238        F: FnOnce(&mut ReservedSpace) -> io::Result<()>,
2239        DC: BytesDecode<'a>,
2240    {
2241        assert_eq_env_db_txn!(self, txn);
2242
2243        let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
2244
2245        let mut key_val = unsafe { crate::into_val(&key_bytes) };
2246        let mut reserved = ffi::reserve_size_val(data_size);
2247        let flags = (flags | PutFlags::NO_OVERWRITE).bits() | lmdb_master_sys::MDB_RESERVE;
2248
2249        let result = unsafe {
2250            mdb_result(ffi::mdb_put(txn.txn.txn, self.dbi, &mut key_val, &mut reserved, flags))
2251        };
2252
2253        match result {
2254            // value was inserted: fill the reserved space
2255            Ok(()) => {
2256                let mut reserved = unsafe { ReservedSpace::from_val(reserved) };
2257                write_func(&mut reserved)?;
2258                if reserved.remaining() == 0 {
2259                    Ok(None)
2260                } else {
2261                    Err(io::Error::from(io::ErrorKind::UnexpectedEof).into())
2262                }
2263            }
2264            // the key already exists: the previous value is stored in the data parameter
2265            Err(MdbError::KeyExist) => {
2266                let bytes = unsafe { crate::from_val(reserved) };
2267                let data = DC::bytes_decode(bytes).map_err(Error::Decoding)?;
2268                Ok(Some(data))
2269            }
2270            Err(error) => Err(error.into()),
2271        }
2272    }
2273
2274    /// Deletes an entry or every duplicate data items of a key
2275    /// if the database supports duplicate data items.
2276    ///
2277    /// If the entry does not exist, then `false` is returned.
2278    ///
2279    /// ```
2280    /// # use std::fs;
2281    /// # use std::path::Path;
2282    /// # use heed::EnvOpenOptions;
2283    /// use heed::Database;
2284    /// use heed::types::*;
2285    /// use heed::byteorder::BigEndian;
2286    ///
2287    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
2288    /// # let dir = tempfile::tempdir()?;
2289    /// # let env = unsafe { EnvOpenOptions::new()
2290    /// #     .map_size(10 * 1024 * 1024) // 10MB
2291    /// #     .max_dbs(3000)
2292    /// #     .open(dir.path())?
2293    /// # };
2294    /// type BEI32 = I32<BigEndian>;
2295    ///
2296    /// let mut wtxn = env.write_txn()?;
2297    /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
2298    ///
2299    /// # db.clear(&mut wtxn)?;
2300    /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
2301    /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
2302    /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
2303    /// db.put(&mut wtxn, &521, "i-am-five-hundred-and-twenty-one")?;
2304    ///
2305    /// let ret = db.delete(&mut wtxn, &27)?;
2306    /// assert_eq!(ret, true);
2307    ///
2308    /// let ret = db.get(&mut wtxn, &27)?;
2309    /// assert_eq!(ret, None);
2310    ///
2311    /// let ret = db.delete(&mut wtxn, &467)?;
2312    /// assert_eq!(ret, false);
2313    ///
2314    /// wtxn.commit()?;
2315    /// # Ok(()) }
2316    /// ```
2317    pub fn delete<'a>(&self, txn: &mut RwTxn, key: &'a KC::EItem) -> Result<bool>
2318    where
2319        KC: BytesEncode<'a>,
2320    {
2321        assert_eq_env_db_txn!(self, txn);
2322
2323        let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
2324        let mut key_val = unsafe { crate::into_val(&key_bytes) };
2325
2326        let result = unsafe {
2327            mdb_result(ffi::mdb_del(txn.txn.txn, self.dbi, &mut key_val, ptr::null_mut()))
2328        };
2329
2330        match result {
2331            Ok(()) => Ok(true),
2332            Err(e) if e.not_found() => Ok(false),
2333            Err(e) => Err(e.into()),
2334        }
2335    }
2336
2337    /// Deletes a single key-value pair in this database.
2338    ///
2339    /// If the database doesn't support duplicate data items the data is ignored.
2340    /// If the key does not exist, then `false` is returned.
2341    ///
2342    /// ```
2343    /// # use std::fs;
2344    /// # use std::path::Path;
2345    /// # use heed::{DatabaseFlags, EnvOpenOptions};
2346    /// use heed::types::*;
2347    /// use heed::byteorder::BigEndian;
2348    ///
2349    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
2350    /// # let dir = tempfile::tempdir()?;
2351    /// # let env = unsafe { EnvOpenOptions::new()
2352    /// #     .map_size(10 * 1024 * 1024) // 10MB
2353    /// #     .max_dbs(3000)
2354    /// #     .open(dir.path())?
2355    /// # };
2356    /// type BEI64 = I64<BigEndian>;
2357    ///
2358    /// let mut wtxn = env.write_txn()?;
2359    /// let db = env.database_options()
2360    ///     .types::<BEI64, BEI64>()
2361    ///     .flags(DatabaseFlags::DUP_SORT)
2362    ///     .name("dup-sort")
2363    ///     .create(&mut wtxn)?;
2364    ///
2365    /// # db.clear(&mut wtxn)?;
2366    /// db.put(&mut wtxn, &68, &120)?;
2367    /// db.put(&mut wtxn, &68, &121)?;
2368    /// db.put(&mut wtxn, &68, &122)?;
2369    /// db.put(&mut wtxn, &68, &123)?;
2370    /// db.put(&mut wtxn, &92, &32)?;
2371    /// db.put(&mut wtxn, &35, &120)?;
2372    /// db.put(&mut wtxn, &0, &120)?;
2373    /// db.put(&mut wtxn, &42, &120)?;
2374    ///
2375    /// let mut iter = db.get_duplicates(&wtxn, &68)?.expect("the key exists");
2376    /// assert_eq!(iter.next().transpose()?, Some((68, 120)));
2377    /// assert_eq!(iter.next().transpose()?, Some((68, 121)));
2378    /// assert_eq!(iter.next().transpose()?, Some((68, 122)));
2379    /// assert_eq!(iter.next().transpose()?, Some((68, 123)));
2380    /// assert_eq!(iter.next().transpose()?, None);
2381    /// drop(iter);
2382    ///
2383    /// assert!(db.delete_one_duplicate(&mut wtxn, &68, &121)?, "The entry must exist");
2384    ///
2385    /// let mut iter = db.get_duplicates(&wtxn, &68)?.expect("the key exists");
2386    /// assert_eq!(iter.next().transpose()?, Some((68, 120)));
2387    /// // No more (68, 121) returned here!
2388    /// assert_eq!(iter.next().transpose()?, Some((68, 122)));
2389    /// assert_eq!(iter.next().transpose()?, Some((68, 123)));
2390    /// assert_eq!(iter.next().transpose()?, None);
2391    /// drop(iter);
2392    ///
2393    /// wtxn.commit()?;
2394    /// # Ok(()) }
2395    /// ```
2396    pub fn delete_one_duplicate<'a>(
2397        &self,
2398        txn: &mut RwTxn,
2399        key: &'a KC::EItem,
2400        data: &'a DC::EItem,
2401    ) -> Result<bool>
2402    where
2403        KC: BytesEncode<'a>,
2404        DC: BytesEncode<'a>,
2405    {
2406        assert_eq_env_db_txn!(self, txn);
2407
2408        let key_bytes: Cow<[u8]> = KC::bytes_encode(key).map_err(Error::Encoding)?;
2409        let data_bytes: Cow<[u8]> = DC::bytes_encode(data).map_err(Error::Encoding)?;
2410        let mut key_val = unsafe { crate::into_val(&key_bytes) };
2411        let mut data_val = unsafe { crate::into_val(&data_bytes) };
2412
2413        let result =
2414            unsafe { mdb_result(ffi::mdb_del(txn.txn.txn, self.dbi, &mut key_val, &mut data_val)) };
2415
2416        match result {
2417            Ok(()) => Ok(true),
2418            Err(e) if e.not_found() => Ok(false),
2419            Err(e) => Err(e.into()),
2420        }
2421    }
2422
2423    /// Deletes a range of key-value pairs in this database.
2424    ///
2425    /// Prefer using [`clear`] instead of a call to this method with a full range ([`..`]).
2426    ///
2427    /// Comparisons are made by using the bytes representation of the key.
2428    ///
2429    /// [`clear`]: crate::Database::clear
2430    /// [`..`]: std::ops::RangeFull
2431    ///
2432    /// ```
2433    /// # use std::fs;
2434    /// # use std::path::Path;
2435    /// # use heed::EnvOpenOptions;
2436    /// use heed::Database;
2437    /// use heed::types::*;
2438    /// use heed::byteorder::BigEndian;
2439    ///
2440    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
2441    /// # let dir = tempfile::tempdir()?;
2442    /// # let env = unsafe { EnvOpenOptions::new()
2443    /// #     .map_size(10 * 1024 * 1024) // 10MB
2444    /// #     .max_dbs(3000)
2445    /// #     .open(dir.path())?
2446    /// # };
2447    /// type BEI32 = I32<BigEndian>;
2448    ///
2449    /// let mut wtxn = env.write_txn()?;
2450    /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
2451    ///
2452    /// # db.clear(&mut wtxn)?;
2453    /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
2454    /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
2455    /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
2456    /// db.put(&mut wtxn, &521, "i-am-five-hundred-and-twenty-one")?;
2457    ///
2458    /// let range = 27..=42;
2459    /// let ret = db.delete_range(&mut wtxn, &range)?;
2460    /// assert_eq!(ret, 2);
2461    ///
2462    ///
2463    /// let mut iter = db.iter(&wtxn)?;
2464    /// assert_eq!(iter.next().transpose()?, Some((13, "i-am-thirteen")));
2465    /// assert_eq!(iter.next().transpose()?, Some((521, "i-am-five-hundred-and-twenty-one")));
2466    /// assert_eq!(iter.next().transpose()?, None);
2467    ///
2468    /// drop(iter);
2469    /// wtxn.commit()?;
2470    /// # Ok(()) }
2471    /// ```
2472    pub fn delete_range<'a, 'txn, R>(&self, txn: &'txn mut RwTxn, range: &'a R) -> Result<usize>
2473    where
2474        KC: BytesEncode<'a> + BytesDecode<'txn>,
2475        R: RangeBounds<KC::EItem>,
2476    {
2477        assert_eq_env_db_txn!(self, txn);
2478
2479        let mut count = 0;
2480        let mut iter = self.remap_data_type::<DecodeIgnore>().range_mut(txn, range)?;
2481
2482        while iter.next().is_some() {
2483            // safety: We do not keep any reference from the database while using `del_current`.
2484            //         The user can't keep any reference inside of the database as we ask for a
2485            //         mutable reference to the `txn`.
2486            unsafe { iter.del_current()? };
2487            count += 1;
2488        }
2489
2490        Ok(count)
2491    }
2492
2493    /// Deletes all key/value pairs in this database.
2494    ///
2495    /// Prefer using this method instead of a call to [`delete_range`] with a full range ([`..`]).
2496    ///
2497    /// [`delete_range`]: crate::Database::delete_range
2498    /// [`..`]: std::ops::RangeFull
2499    ///
2500    /// ```
2501    /// # use std::fs;
2502    /// # use std::path::Path;
2503    /// # use heed::EnvOpenOptions;
2504    /// use heed::Database;
2505    /// use heed::types::*;
2506    /// use heed::byteorder::BigEndian;
2507    ///
2508    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
2509    /// # let dir = tempfile::tempdir()?;
2510    /// # let env = unsafe { EnvOpenOptions::new()
2511    /// #     .map_size(10 * 1024 * 1024) // 10MB
2512    /// #     .max_dbs(3000)
2513    /// #     .open(dir.path())?
2514    /// # };
2515    /// type BEI32 = I32<BigEndian>;
2516    ///
2517    /// let mut wtxn = env.write_txn()?;
2518    /// let db: Database<BEI32, Str> = env.create_database(&mut wtxn, Some("iter-i32"))?;
2519    ///
2520    /// # db.clear(&mut wtxn)?;
2521    /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
2522    /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
2523    /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
2524    /// db.put(&mut wtxn, &521, "i-am-five-hundred-and-twenty-one")?;
2525    ///
2526    /// db.clear(&mut wtxn)?;
2527    ///
2528    /// let ret = db.is_empty(&wtxn)?;
2529    /// assert!(ret);
2530    ///
2531    /// wtxn.commit()?;
2532    /// # Ok(()) }
2533    /// ```
2534    pub fn clear(&self, txn: &mut RwTxn) -> Result<()> {
2535        assert_eq_env_db_txn!(self, txn);
2536
2537        unsafe { mdb_result(ffi::mdb_drop(txn.txn.txn, self.dbi, 0)).map_err(Into::into) }
2538    }
2539
2540    /// Change the codec types of this database, specifying the codecs.
2541    ///
2542    /// # Safety
2543    ///
2544    /// It is up to you to ensure that the data read and written using the polymorphic
2545    /// handle correspond to the the typed, uniform one. If an invalid write is made,
2546    /// it can corrupt the database from the eyes of heed.
2547    ///
2548    /// # Example
2549    ///
2550    /// ```
2551    /// # use std::fs;
2552    /// # use std::path::Path;
2553    /// # use heed::EnvOpenOptions;
2554    /// use heed::Database;
2555    /// use heed::types::*;
2556    /// use heed::byteorder::BigEndian;
2557    ///
2558    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
2559    /// # let dir = tempfile::tempdir()?;
2560    /// # let env = unsafe { EnvOpenOptions::new()
2561    /// #     .map_size(10 * 1024 * 1024) // 10MB
2562    /// #     .max_dbs(3000)
2563    /// #     .open(dir.path())?
2564    /// # };
2565    /// type BEI32 = I32<BigEndian>;
2566    ///
2567    /// let mut wtxn = env.write_txn()?;
2568    /// let db: Database<Unit, Unit> = env.create_database(&mut wtxn, Some("iter-i32"))?;
2569    ///
2570    /// # db.clear(&mut wtxn)?;
2571    /// // We remap the types for ease of use.
2572    /// let db = db.remap_types::<BEI32, Str>();
2573    /// db.put(&mut wtxn, &42, "i-am-forty-two")?;
2574    /// db.put(&mut wtxn, &27, "i-am-twenty-seven")?;
2575    /// db.put(&mut wtxn, &13, "i-am-thirteen")?;
2576    /// db.put(&mut wtxn, &521, "i-am-five-hundred-and-twenty-one")?;
2577    ///
2578    /// wtxn.commit()?;
2579    /// # Ok(()) }
2580    /// ```
2581    pub fn remap_types<KC2, DC2>(&self) -> Database<KC2, DC2, C> {
2582        Database::new(self.env_ident, self.dbi)
2583    }
2584
2585    /// Change the key codec type of this database, specifying the new codec.
2586    pub fn remap_key_type<KC2>(&self) -> Database<KC2, DC, C> {
2587        self.remap_types::<KC2, DC>()
2588    }
2589
2590    /// Change the data codec type of this database, specifying the new codec.
2591    pub fn remap_data_type<DC2>(&self) -> Database<KC, DC2, C> {
2592        self.remap_types::<KC, DC2>()
2593    }
2594
2595    /// Wrap the data bytes into a lazy decoder.
2596    pub fn lazily_decode_data(&self) -> Database<KC, LazyDecode<DC>, C> {
2597        self.remap_types::<KC, LazyDecode<DC>>()
2598    }
2599}
2600
2601impl<KC, DC, C> Clone for Database<KC, DC, C> {
2602    fn clone(&self) -> Database<KC, DC, C> {
2603        *self
2604    }
2605}
2606
2607impl<KC, DC, C> Copy for Database<KC, DC, C> {}
2608
2609impl<KC, DC, C> fmt::Debug for Database<KC, DC, C> {
2610    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2611        f.debug_struct("Database")
2612            .field("key_codec", &any::type_name::<KC>())
2613            .field("data_codec", &any::type_name::<DC>())
2614            .field("comparator", &any::type_name::<C>())
2615            .finish()
2616    }
2617}
2618
2619/// Statistics for a database in the environment.
2620#[derive(Debug, Clone, Copy)]
2621pub struct DatabaseStat {
2622    /// Size of a database page.
2623    /// This is currently the same for all databases.
2624    pub page_size: u32,
2625    /// Depth (height) of the B-tree.
2626    pub depth: u32,
2627    /// Number of internal (non-leaf) pages
2628    pub branch_pages: usize,
2629    /// Number of leaf pages.
2630    pub leaf_pages: usize,
2631    /// Number of overflow pages.
2632    pub overflow_pages: usize,
2633    /// Number of data items.
2634    pub entries: usize,
2635}
2636
2637#[cfg(test)]
2638mod tests {
2639    use heed_types::*;
2640
2641    use super::*;
2642
2643    #[test]
2644    fn put_overwrite() -> Result<()> {
2645        let dir = tempfile::tempdir()?;
2646        let env = unsafe { EnvOpenOptions::new().open(dir.path())? };
2647        let mut txn = env.write_txn()?;
2648        let db = env.create_database::<Bytes, Bytes>(&mut txn, None)?;
2649
2650        assert_eq!(db.get(&txn, b"hello").unwrap(), None);
2651
2652        db.put(&mut txn, b"hello", b"hi").unwrap();
2653        assert_eq!(db.get(&txn, b"hello").unwrap(), Some(&b"hi"[..]));
2654
2655        db.put(&mut txn, b"hello", b"bye").unwrap();
2656        assert_eq!(db.get(&txn, b"hello").unwrap(), Some(&b"bye"[..]));
2657
2658        Ok(())
2659    }
2660
2661    #[test]
2662    #[cfg(feature = "longer-keys")]
2663    fn longer_keys() -> Result<()> {
2664        let dir = tempfile::tempdir()?;
2665        let env = unsafe { EnvOpenOptions::new().open(dir.path())? };
2666        let mut txn = env.write_txn()?;
2667        let db = env.create_database::<Bytes, Bytes>(&mut txn, None)?;
2668
2669        // Try storing a key larger than 511 bytes (the default if MDB_MAXKEYSIZE is not set)
2670        let long_key = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut pharetra sit amet aliquam. Sit amet nisl purus in mollis nunc. Eget egestas purus viverra accumsan in nisl nisi scelerisque. Duis ultricies lacus sed turpis tincidunt. Sem nulla pharetra diam sit. Leo vel orci porta non pulvinar. Erat pellentesque adipiscing commodo elit at imperdiet dui. Suspendisse ultrices gravida dictum fusce ut placerat orci nulla. Diam donec adipiscing tristique risus nec feugiat. In fermentum et sollicitudin ac orci. Ut sem nulla pharetra diam sit amet. Aliquam purus sit amet luctus venenatis lectus. Erat pellentesque adipiscing commodo elit at imperdiet dui accumsan. Urna duis convallis convallis tellus id interdum velit laoreet id. Ac feugiat sed lectus vestibulum mattis ullamcorper velit sed. Tincidunt arcu non sodales neque. Habitant morbi tristique senectus et netus et malesuada fames.";
2671
2672        assert_eq!(db.get(&txn, long_key).unwrap(), None);
2673
2674        db.put(&mut txn, long_key, b"hi").unwrap();
2675        assert_eq!(db.get(&txn, long_key).unwrap(), Some(&b"hi"[..]));
2676
2677        db.put(&mut txn, long_key, b"bye").unwrap();
2678        assert_eq!(db.get(&txn, long_key).unwrap(), Some(&b"bye"[..]));
2679
2680        Ok(())
2681    }
2682}