use std::ops::{Bound, RangeBounds};
use std::{mem, ptr};
use crate::mdb::error::mdb_result;
use crate::mdb::ffi;
use crate::*;
#[derive(Copy, Clone)]
pub struct Database {
pub(crate) env_ident: usize,
pub(crate) dbi: ffi::MDB_dbi,
}
impl Database {
pub(crate) fn new(env_ident: usize, dbi: ffi::MDB_dbi) -> Database {
Database { env_ident, dbi }
}
pub fn get<'txn, A: AsRef<[u8]>>(
&self,
txn: &'txn RoTxn,
key: A,
) -> Result<Option<&'txn [u8]>> {
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
let mut key_val = unsafe { crate::into_val(key.as_ref()) };
let mut data_val = mem::MaybeUninit::uninit();
let result = unsafe {
mdb_result(ffi::mdb_get(
txn.txn,
self.dbi,
&mut key_val,
data_val.as_mut_ptr(),
))
};
match result {
Ok(()) => {
let data = unsafe { crate::from_val(data_val.assume_init()) };
Ok(Some(data))
}
Err(e) if e.not_found() => Ok(None),
Err(e) => Err(e.into()),
}
}
pub fn get_lower_than<'txn, A: AsRef<[u8]>>(
&self,
txn: &'txn RoTxn,
key: A,
) -> Result<Option<(&'txn [u8], &'txn [u8])>> {
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
let mut cursor = RoCursor::new(txn, self.dbi)?;
cursor.move_on_key_greater_than_or_equal_to(key.as_ref())?;
cursor.move_on_prev()
}
pub fn get_lower_than_or_equal_to<'txn, A: AsRef<[u8]>>(
&self,
txn: &'txn RoTxn,
key: A,
) -> Result<Option<(&'txn [u8], &'txn [u8])>> {
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
let key = key.as_ref();
let mut cursor = RoCursor::new(txn, self.dbi)?;
match cursor.move_on_key_greater_than_or_equal_to(key) {
Ok(Some((k, data))) if k == key => Ok(Some((k, data))),
Ok(_) => cursor.move_on_prev(),
Err(e) => Err(e),
}
}
pub fn get_greater_than<'txn, A: AsRef<[u8]>>(
&self,
txn: &'txn RoTxn,
key: A,
) -> Result<Option<(&'txn [u8], &'txn [u8])>> {
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
let key = key.as_ref();
let mut cursor = RoCursor::new(txn, self.dbi)?;
match cursor.move_on_key_greater_than_or_equal_to(key)? {
Some((k, data)) if k > key => Ok(Some((k, data))),
Some((_key, _data)) => cursor.move_on_next(),
None => Ok(None),
}
}
pub fn get_greater_than_or_equal_to<'txn, A: AsRef<[u8]>>(
&self,
txn: &'txn RoTxn,
key: A,
) -> Result<Option<(&'txn [u8], &'txn [u8])>> {
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
let mut cursor = RoCursor::new(txn, self.dbi)?;
cursor.move_on_key_greater_than_or_equal_to(key.as_ref())
}
pub fn first<'txn>(&self, txn: &'txn RoTxn) -> Result<Option<(&'txn [u8], &'txn [u8])>> {
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
let mut cursor = RoCursor::new(txn, self.dbi)?;
cursor.move_on_first()
}
pub fn last<'txn>(&self, txn: &'txn RoTxn) -> Result<Option<(&'txn [u8], &'txn [u8])>> {
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
let mut cursor = RoCursor::new(txn, self.dbi)?;
cursor.move_on_last()
}
pub fn len<'txn>(&self, txn: &'txn RoTxn) -> Result<u64> {
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
let mut stat = mem::MaybeUninit::uninit();
let stat = unsafe {
mdb_result(ffi::mdb_stat(txn.txn, self.dbi, stat.as_mut_ptr()))?;
stat.assume_init()
};
Ok(stat.ms_entries as u64)
}
pub fn is_empty<'txn>(&self, txn: &'txn RoTxn) -> Result<bool> {
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
let mut cursor = RoCursor::new(txn, self.dbi)?;
match cursor.move_on_first()? {
Some(_) => Ok(false),
None => Ok(true),
}
}
pub fn iter<'txn>(&self, txn: &'txn RoTxn) -> Result<RoIter<'txn>> {
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
RoCursor::new(txn, self.dbi).map(|cursor| RoIter::new(cursor))
}
pub fn iter_mut<'txn>(&self, txn: &'txn mut RwTxn) -> Result<RwIter<'txn>> {
assert_eq!(self.env_ident, txn.txn.env.env_mut_ptr() as usize);
RwCursor::new(txn, self.dbi).map(|cursor| RwIter::new(cursor))
}
pub fn rev_iter<'txn>(&self, txn: &'txn RoTxn) -> Result<RoRevIter<'txn>> {
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
RoCursor::new(txn, self.dbi).map(|cursor| RoRevIter::new(cursor))
}
pub fn rev_iter_mut<'txn>(&self, txn: &'txn mut RwTxn) -> Result<RwRevIter<'txn>> {
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
RwCursor::new(txn, self.dbi).map(|cursor| RwRevIter::new(cursor))
}
pub fn range<'txn, R, A>(&self, txn: &'txn RoTxn, range: R) -> Result<RoRange<'txn>>
where
R: RangeBounds<A>,
A: AsRef<[u8]>,
{
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
let start_bound = match range.start_bound() {
Bound::Included(bytes) => Bound::Included(bytes.as_ref().to_vec()),
Bound::Excluded(bytes) => Bound::Excluded(bytes.as_ref().to_vec()),
Bound::Unbounded => Bound::Unbounded,
};
let end_bound = match range.end_bound() {
Bound::Included(bytes) => Bound::Included(bytes.as_ref().to_vec()),
Bound::Excluded(bytes) => Bound::Excluded(bytes.as_ref().to_vec()),
Bound::Unbounded => Bound::Unbounded,
};
RoCursor::new(txn, self.dbi).map(|cursor| RoRange::new(cursor, start_bound, end_bound))
}
pub fn range_mut<'txn, R, A>(&self, txn: &'txn mut RwTxn, range: R) -> Result<RwRange<'txn>>
where
R: RangeBounds<A>,
A: AsRef<[u8]>,
{
assert_eq!(self.env_ident, txn.txn.env.env_mut_ptr() as usize);
let start_bound = match range.start_bound() {
Bound::Included(bytes) => Bound::Included(bytes.as_ref().to_vec()),
Bound::Excluded(bytes) => Bound::Excluded(bytes.as_ref().to_vec()),
Bound::Unbounded => Bound::Unbounded,
};
let end_bound = match range.end_bound() {
Bound::Included(bytes) => Bound::Included(bytes.as_ref().to_vec()),
Bound::Excluded(bytes) => Bound::Excluded(bytes.as_ref().to_vec()),
Bound::Unbounded => Bound::Unbounded,
};
RwCursor::new(txn, self.dbi).map(|cursor| RwRange::new(cursor, start_bound, end_bound))
}
pub fn rev_range<'txn, R, A>(&self, txn: &'txn RoTxn, range: R) -> Result<RoRevRange<'txn>>
where
R: RangeBounds<A>,
A: AsRef<[u8]>,
{
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
let start_bound = match range.start_bound() {
Bound::Included(bytes) => Bound::Included(bytes.as_ref().to_vec()),
Bound::Excluded(bytes) => Bound::Excluded(bytes.as_ref().to_vec()),
Bound::Unbounded => Bound::Unbounded,
};
let end_bound = match range.end_bound() {
Bound::Included(bytes) => Bound::Included(bytes.as_ref().to_vec()),
Bound::Excluded(bytes) => Bound::Excluded(bytes.as_ref().to_vec()),
Bound::Unbounded => Bound::Unbounded,
};
RoCursor::new(txn, self.dbi).map(|cursor| RoRevRange::new(cursor, start_bound, end_bound))
}
pub fn rev_range_mut<'txn, R, A>(
&self,
txn: &'txn mut RwTxn,
range: R,
) -> Result<RwRevRange<'txn>>
where
R: RangeBounds<A>,
A: AsRef<[u8]>,
{
assert_eq!(self.env_ident, txn.txn.env.env_mut_ptr() as usize);
let start_bound = match range.start_bound() {
Bound::Included(bytes) => Bound::Included(bytes.as_ref().to_vec()),
Bound::Excluded(bytes) => Bound::Excluded(bytes.as_ref().to_vec()),
Bound::Unbounded => Bound::Unbounded,
};
let end_bound = match range.end_bound() {
Bound::Included(bytes) => Bound::Included(bytes.as_ref().to_vec()),
Bound::Excluded(bytes) => Bound::Excluded(bytes.as_ref().to_vec()),
Bound::Unbounded => Bound::Unbounded,
};
RwCursor::new(txn, self.dbi).map(|cursor| RwRevRange::new(cursor, start_bound, end_bound))
}
pub fn prefix_iter<'txn, A: AsRef<[u8]>>(
&self,
txn: &'txn RoTxn,
prefix: A,
) -> Result<RoPrefix<'txn>> {
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
RoCursor::new(txn, self.dbi).map(|cursor| RoPrefix::new(cursor, prefix.as_ref().to_vec()))
}
pub fn prefix_iter_mut<'txn, A: AsRef<[u8]>>(
&self,
txn: &'txn mut RwTxn,
prefix: A,
) -> Result<RwPrefix<'txn>> {
assert_eq!(self.env_ident, txn.txn.env.env_mut_ptr() as usize);
RwCursor::new(txn, self.dbi).map(|cursor| RwPrefix::new(cursor, prefix.as_ref().to_vec()))
}
pub fn rev_prefix_iter<'txn, A: AsRef<[u8]>>(
&self,
txn: &'txn RoTxn,
prefix: A,
) -> Result<RoRevPrefix<'txn>> {
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
RoCursor::new(txn, self.dbi)
.map(|cursor| RoRevPrefix::new(cursor, prefix.as_ref().to_vec()))
}
pub fn rev_prefix_iter_mut<'txn, A: AsRef<[u8]>>(
&self,
txn: &'txn mut RwTxn,
prefix: A,
) -> Result<RwRevPrefix<'txn>> {
assert_eq!(self.env_ident, txn.txn.env.env_mut_ptr() as usize);
RwCursor::new(txn, self.dbi)
.map(|cursor| RwRevPrefix::new(cursor, prefix.as_ref().to_vec()))
}
pub fn put<A, B>(&self, txn: &mut RwTxn, key: A, data: B) -> Result<()>
where
A: AsRef<[u8]>,
B: AsRef<[u8]>,
{
assert_eq!(self.env_ident, txn.txn.env.env_mut_ptr() as usize);
let mut key_val = unsafe { crate::into_val(key.as_ref()) };
let mut data_val = unsafe { crate::into_val(data.as_ref()) };
let flags = 0;
unsafe {
mdb_result(ffi::mdb_put(
txn.txn.txn,
self.dbi,
&mut key_val,
&mut data_val,
flags,
))?
}
Ok(())
}
pub fn append<A, B>(&self, txn: &mut RwTxn, key: A, data: B) -> Result<()>
where
A: AsRef<[u8]>,
B: AsRef<[u8]>,
{
assert_eq!(self.env_ident, txn.txn.env.env_mut_ptr() as usize);
let mut key_val = unsafe { crate::into_val(key.as_ref()) };
let mut data_val = unsafe { crate::into_val(data.as_ref()) };
let flags = ffi::MDB_APPEND;
unsafe {
mdb_result(ffi::mdb_put(
txn.txn.txn,
self.dbi,
&mut key_val,
&mut data_val,
flags,
))?
}
Ok(())
}
pub fn delete<A: AsRef<[u8]>>(&self, txn: &mut RwTxn, key: A) -> Result<bool> {
assert_eq!(self.env_ident, txn.txn.env.env_mut_ptr() as usize);
let mut key_val = unsafe { crate::into_val(key.as_ref()) };
let result = unsafe {
mdb_result(ffi::mdb_del(
txn.txn.txn,
self.dbi,
&mut key_val,
ptr::null_mut(),
))
};
match result {
Ok(()) => Ok(true),
Err(e) if e.not_found() => Ok(false),
Err(e) => Err(e.into()),
}
}
pub fn delete_range<'txn, R, A>(&self, txn: &'txn mut RwTxn, range: R) -> Result<usize>
where
R: RangeBounds<A>,
A: AsRef<[u8]>,
{
assert_eq!(self.env_ident, txn.txn.env.env_mut_ptr() as usize);
let mut count = 0;
let mut iter = self.range_mut::<_, A>(txn, range)?;
while iter.next().is_some() {
unsafe { iter.del_current()? };
count += 1;
}
Ok(count)
}
pub fn clear(&self, txn: &mut RwTxn) -> Result<()> {
assert_eq!(self.env_ident, txn.txn.env.env_mut_ptr() as usize);
unsafe { mdb_result(ffi::mdb_drop(txn.txn.txn, self.dbi, 0)).map_err(Into::into) }
}
}