Skip to main content

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