Skip to main content

heed/
database.rs

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