use std::borrow::Cow;
use std::ops::{Bound, RangeBounds};
use std::{mem, ptr};
use crate::*;
use crate::mdb::error::mdb_result;
use crate::mdb::ffi;
use crate::types::DecodeIgnore;
#[derive(Copy, Clone)]
pub struct PolyDatabase {
pub(crate) env_ident: usize,
pub(crate) dbi: ffi::MDB_dbi,
}
impl PolyDatabase {
pub(crate) fn new(env_ident: usize, dbi: ffi::MDB_dbi) -> PolyDatabase {
PolyDatabase { env_ident, dbi }
}
#[cfg(all(feature = "mdbx", not(feature = "lmdb")))]
pub fn sequence<T>(&self, txn: &RoTxn<T>) -> Result<u64> {
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
let mut value = mem::MaybeUninit::uninit();
let result = unsafe {
mdb_result(ffi::mdbx_dbi_sequence(
txn.txn,
self.dbi,
value.as_mut_ptr(),
0, ))
};
match result {
Ok(()) => unsafe { Ok(value.assume_init()) },
Err(e) => Err(e.into()),
}
}
#[cfg(all(feature = "mdbx", not(feature = "lmdb")))]
pub fn increase_sequence<T>(&self, txn: &mut RwTxn<T>, increment: u64) -> Result<Option<u64>> {
assert_eq!(self.env_ident, txn.txn.env.env_mut_ptr() as usize);
use crate::mdb::error::Error;
let mut value = mem::MaybeUninit::uninit();
let result = unsafe {
mdb_result(ffi::mdbx_dbi_sequence(
txn.txn.txn,
self.dbi,
value.as_mut_ptr(),
increment,
))
};
match result {
Ok(()) => unsafe { Ok(Some(value.assume_init())) },
Err(Error::Other(c)) if c == i32::max_value() => Ok(None), Err(e) => Err(e.into()),
}
}
pub fn get<'a, 'txn, T, KC, DC>(
&self,
txn: &'txn RoTxn<T>,
key: &'a KC::EItem,
) -> Result<Option<DC::DItem>>
where
KC: BytesEncode<'a>,
DC: BytesDecode<'txn>,
{
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
let key_bytes: Cow<[u8]> = KC::bytes_encode(&key).ok_or(Error::Encoding)?;
let mut key_val = unsafe { crate::into_val(&key_bytes) };
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()) };
let data = DC::bytes_decode(data).ok_or(Error::Decoding)?;
Ok(Some(data))
}
Err(e) if e.not_found() => Ok(None),
Err(e) => Err(e.into()),
}
}
pub fn get_lower_than<'a, 'txn, T, KC, DC>(
&self,
txn: &'txn RoTxn<T>,
key: &'a KC::EItem,
) -> Result<Option<(KC::DItem, DC::DItem)>>
where
KC: BytesEncode<'a> + BytesDecode<'txn>,
DC: BytesDecode<'txn>,
{
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
let mut cursor = RoCursor::new(txn, self.dbi)?;
let key_bytes: Cow<[u8]> = KC::bytes_encode(&key).ok_or(Error::Encoding)?;
cursor.move_on_key_greater_than_or_equal_to(&key_bytes)?;
match cursor.move_on_prev() {
Ok(Some((key, data))) => match (KC::bytes_decode(key), DC::bytes_decode(data)) {
(Some(key), Some(data)) => Ok(Some((key, data))),
(_, _) => Err(Error::Decoding),
},
Ok(None) => Ok(None),
Err(e) => Err(e),
}
}
pub fn get_lower_than_or_equal_to<'a, 'txn, T, KC, DC>(
&self,
txn: &'txn RoTxn<T>,
key: &'a KC::EItem,
) -> Result<Option<(KC::DItem, DC::DItem)>>
where
KC: BytesEncode<'a> + BytesDecode<'txn>,
DC: BytesDecode<'txn>,
{
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
let mut cursor = RoCursor::new(txn, self.dbi)?;
let key_bytes: Cow<[u8]> = KC::bytes_encode(&key).ok_or(Error::Encoding)?;
let result = match cursor.move_on_key_greater_than_or_equal_to(&key_bytes) {
Ok(Some((key, data))) if key == &key_bytes[..] => Ok(Some((key, data))),
Ok(_) => cursor.move_on_prev(),
Err(e) => Err(e),
};
match result {
Ok(Some((key, data))) => match (KC::bytes_decode(key), DC::bytes_decode(data)) {
(Some(key), Some(data)) => Ok(Some((key, data))),
(_, _) => Err(Error::Decoding),
},
Ok(None) => Ok(None),
Err(e) => Err(e),
}
}
pub fn get_greater_than<'a, 'txn, T, KC, DC>(
&self,
txn: &'txn RoTxn<T>,
key: &'a KC::EItem,
) -> Result<Option<(KC::DItem, DC::DItem)>>
where
KC: BytesEncode<'a> + BytesDecode<'txn>,
DC: BytesDecode<'txn>,
{
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
let mut cursor = RoCursor::new(txn, self.dbi)?;
let key_bytes: Cow<[u8]> = KC::bytes_encode(&key).ok_or(Error::Encoding)?;
let entry = match cursor.move_on_key_greater_than_or_equal_to(&key_bytes)? {
Some((key, data)) if key > &key_bytes[..] => Some((key, data)),
Some((_key, _data)) => cursor.move_on_next()?,
None => None,
};
match entry {
Some((key, data)) => match (KC::bytes_decode(key), DC::bytes_decode(data)) {
(Some(key), Some(data)) => Ok(Some((key, data))),
(_, _) => Err(Error::Decoding),
},
None => Ok(None),
}
}
pub fn get_greater_than_or_equal_to<'a, 'txn, T, KC, DC>(
&self,
txn: &'txn RoTxn<T>,
key: &'a KC::EItem,
) -> Result<Option<(KC::DItem, DC::DItem)>>
where
KC: BytesEncode<'a> + BytesDecode<'txn>,
DC: BytesDecode<'txn>,
{
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
let mut cursor = RoCursor::new(txn, self.dbi)?;
let key_bytes: Cow<[u8]> = KC::bytes_encode(&key).ok_or(Error::Encoding)?;
match cursor.move_on_key_greater_than_or_equal_to(&key_bytes) {
Ok(Some((key, data))) => match (KC::bytes_decode(key), DC::bytes_decode(data)) {
(Some(key), Some(data)) => Ok(Some((key, data))),
(_, _) => Err(Error::Decoding),
},
Ok(None) => Ok(None),
Err(e) => Err(e),
}
}
pub fn first<'txn, T, KC, DC>(&self, txn: &'txn RoTxn<T>) -> Result<Option<(KC::DItem, DC::DItem)>>
where
KC: BytesDecode<'txn>,
DC: BytesDecode<'txn>,
{
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() {
Ok(Some((key, data))) => match (KC::bytes_decode(key), DC::bytes_decode(data)) {
(Some(key), Some(data)) => Ok(Some((key, data))),
(_, _) => Err(Error::Decoding),
},
Ok(None) => Ok(None),
Err(e) => Err(e),
}
}
pub fn last<'txn, T, KC, DC>(&self, txn: &'txn RoTxn<T>) -> Result<Option<(KC::DItem, DC::DItem)>>
where
KC: BytesDecode<'txn>,
DC: BytesDecode<'txn>,
{
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
let mut cursor = RoCursor::new(txn, self.dbi)?;
match cursor.move_on_last() {
Ok(Some((key, data))) => match (KC::bytes_decode(key), DC::bytes_decode(data)) {
(Some(key), Some(data)) => Ok(Some((key, data))),
(_, _) => Err(Error::Decoding),
},
Ok(None) => Ok(None),
Err(e) => Err(e),
}
}
pub fn len<'txn, T>(&self, txn: &'txn RoTxn<T>) -> Result<usize> {
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
let mut cursor = RoCursor::new(txn, self.dbi)?;
let mut count = 0;
match cursor.move_on_first()? {
Some(_) => count += 1,
None => return Ok(0),
}
while let Some(_) = cursor.move_on_next()? {
count += 1;
}
Ok(count)
}
pub fn is_empty<'txn, T>(&self, txn: &'txn RoTxn<T>) -> 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, T, KC, DC>(&self, txn: &'txn RoTxn<T>) -> Result<RoIter<'txn, KC, DC>> {
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, T, KC, DC>(&self, txn: &'txn mut RwTxn<T>) -> Result<RwIter<'txn, KC, DC>> {
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, T, KC, DC>(&self, txn: &'txn RoTxn<T>) -> Result<RoRevIter<'txn, KC, DC>> {
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, T, KC, DC>(&self, txn: &'txn mut RwTxn<T>) -> Result<RwRevIter<'txn, KC, DC>> {
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<'a, 'txn, T, KC, DC, R>(
&self,
txn: &'txn RoTxn<T>,
range: &'a R,
) -> Result<RoRange<'txn, KC, DC>>
where
KC: BytesEncode<'a>,
R: RangeBounds<KC::EItem>,
{
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
let start_bound = match range.start_bound() {
Bound::Included(bound) => {
let bytes = KC::bytes_encode(bound).ok_or(Error::Encoding)?;
Bound::Included(bytes.into_owned())
}
Bound::Excluded(bound) => {
let bytes = KC::bytes_encode(bound).ok_or(Error::Encoding)?;
Bound::Excluded(bytes.into_owned())
}
Bound::Unbounded => Bound::Unbounded,
};
let end_bound = match range.end_bound() {
Bound::Included(bound) => {
let bytes = KC::bytes_encode(bound).ok_or(Error::Encoding)?;
Bound::Included(bytes.into_owned())
}
Bound::Excluded(bound) => {
let bytes = KC::bytes_encode(bound).ok_or(Error::Encoding)?;
Bound::Excluded(bytes.into_owned())
}
Bound::Unbounded => Bound::Unbounded,
};
RoCursor::new(txn, self.dbi).map(|cursor| RoRange::new(cursor, start_bound, end_bound))
}
pub fn range_mut<'a, 'txn, T, KC, DC, R>(
&self,
txn: &'txn mut RwTxn<T>,
range: &'a R,
) -> Result<RwRange<'txn, KC, DC>>
where
KC: BytesEncode<'a>,
R: RangeBounds<KC::EItem>,
{
assert_eq!(self.env_ident, txn.txn.env.env_mut_ptr() as usize);
let start_bound = match range.start_bound() {
Bound::Included(bound) => {
let bytes = KC::bytes_encode(bound).ok_or(Error::Encoding)?;
Bound::Included(bytes.into_owned())
}
Bound::Excluded(bound) => {
let bytes = KC::bytes_encode(bound).ok_or(Error::Encoding)?;
Bound::Excluded(bytes.into_owned())
}
Bound::Unbounded => Bound::Unbounded,
};
let end_bound = match range.end_bound() {
Bound::Included(bound) => {
let bytes = KC::bytes_encode(bound).ok_or(Error::Encoding)?;
Bound::Included(bytes.into_owned())
}
Bound::Excluded(bound) => {
let bytes = KC::bytes_encode(bound).ok_or(Error::Encoding)?;
Bound::Excluded(bytes.into_owned())
}
Bound::Unbounded => Bound::Unbounded,
};
RwCursor::new(txn, self.dbi).map(|cursor| RwRange::new(cursor, start_bound, end_bound))
}
pub fn rev_range<'a, 'txn, T, KC, DC, R>(
&self,
txn: &'txn RoTxn<T>,
range: &'a R,
) -> Result<RoRevRange<'txn, KC, DC>>
where
KC: BytesEncode<'a>,
R: RangeBounds<KC::EItem>,
{
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
let start_bound = match range.start_bound() {
Bound::Included(bound) => {
let bytes = KC::bytes_encode(bound).ok_or(Error::Encoding)?;
Bound::Included(bytes.into_owned())
}
Bound::Excluded(bound) => {
let bytes = KC::bytes_encode(bound).ok_or(Error::Encoding)?;
Bound::Excluded(bytes.into_owned())
}
Bound::Unbounded => Bound::Unbounded,
};
let end_bound = match range.end_bound() {
Bound::Included(bound) => {
let bytes = KC::bytes_encode(bound).ok_or(Error::Encoding)?;
Bound::Included(bytes.into_owned())
}
Bound::Excluded(bound) => {
let bytes = KC::bytes_encode(bound).ok_or(Error::Encoding)?;
Bound::Excluded(bytes.into_owned())
}
Bound::Unbounded => Bound::Unbounded,
};
RoCursor::new(txn, self.dbi).map(|cursor| RoRevRange::new(cursor, start_bound, end_bound))
}
pub fn rev_range_mut<'a, 'txn, T, KC, DC, R>(
&self,
txn: &'txn mut RwTxn<T>,
range: &'a R,
) -> Result<RwRevRange<'txn, KC, DC>>
where
KC: BytesEncode<'a>,
R: RangeBounds<KC::EItem>,
{
assert_eq!(self.env_ident, txn.txn.env.env_mut_ptr() as usize);
let start_bound = match range.start_bound() {
Bound::Included(bound) => {
let bytes = KC::bytes_encode(bound).ok_or(Error::Encoding)?;
Bound::Included(bytes.into_owned())
}
Bound::Excluded(bound) => {
let bytes = KC::bytes_encode(bound).ok_or(Error::Encoding)?;
Bound::Excluded(bytes.into_owned())
}
Bound::Unbounded => Bound::Unbounded,
};
let end_bound = match range.end_bound() {
Bound::Included(bound) => {
let bytes = KC::bytes_encode(bound).ok_or(Error::Encoding)?;
Bound::Included(bytes.into_owned())
}
Bound::Excluded(bound) => {
let bytes = KC::bytes_encode(bound).ok_or(Error::Encoding)?;
Bound::Excluded(bytes.into_owned())
}
Bound::Unbounded => Bound::Unbounded,
};
RwCursor::new(txn, self.dbi).map(|cursor| RwRevRange::new(cursor, start_bound, end_bound))
}
pub fn prefix_iter<'a, 'txn, T, KC, DC>(
&self,
txn: &'txn RoTxn<T>,
prefix: &'a KC::EItem,
) -> Result<RoPrefix<'txn, KC, DC>>
where
KC: BytesEncode<'a>,
{
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
let prefix_bytes = KC::bytes_encode(prefix).ok_or(Error::Encoding)?;
let prefix_bytes = prefix_bytes.into_owned();
RoCursor::new(txn, self.dbi).map(|cursor| RoPrefix::new(cursor, prefix_bytes))
}
pub fn prefix_iter_mut<'a, 'txn, T, KC, DC>(
&self,
txn: &'txn mut RwTxn<T>,
prefix: &'a KC::EItem,
) -> Result<RwPrefix<'txn, KC, DC>>
where
KC: BytesEncode<'a>,
{
assert_eq!(self.env_ident, txn.txn.env.env_mut_ptr() as usize);
let prefix_bytes = KC::bytes_encode(prefix).ok_or(Error::Encoding)?;
let prefix_bytes = prefix_bytes.into_owned();
RwCursor::new(txn, self.dbi).map(|cursor| RwPrefix::new(cursor, prefix_bytes))
}
pub fn rev_prefix_iter<'a, 'txn, T, KC, DC>(
&self,
txn: &'txn RoTxn<T>,
prefix: &'a KC::EItem,
) -> Result<RoRevPrefix<'txn, KC, DC>>
where
KC: BytesEncode<'a>,
{
assert_eq!(self.env_ident, txn.env.env_mut_ptr() as usize);
let prefix_bytes = KC::bytes_encode(prefix).ok_or(Error::Encoding)?;
let prefix_bytes = prefix_bytes.into_owned();
RoCursor::new(txn, self.dbi).map(|cursor| RoRevPrefix::new(cursor, prefix_bytes))
}
pub fn rev_prefix_iter_mut<'a, 'txn, T, KC, DC>(
&self,
txn: &'txn mut RwTxn<T>,
prefix: &'a KC::EItem,
) -> Result<RwRevPrefix<'txn, KC, DC>>
where
KC: BytesEncode<'a>,
{
assert_eq!(self.env_ident, txn.txn.env.env_mut_ptr() as usize);
let prefix_bytes = KC::bytes_encode(prefix).ok_or(Error::Encoding)?;
let prefix_bytes = prefix_bytes.into_owned();
RwCursor::new(txn, self.dbi).map(|cursor| RwRevPrefix::new(cursor, prefix_bytes))
}
pub fn put<'a, T, KC, DC>(
&self,
txn: &mut RwTxn<T>,
key: &'a KC::EItem,
data: &'a DC::EItem,
) -> Result<()>
where
KC: BytesEncode<'a>,
DC: BytesEncode<'a>,
{
assert_eq!(self.env_ident, txn.txn.env.env_mut_ptr() as usize);
let key_bytes: Cow<[u8]> = KC::bytes_encode(&key).ok_or(Error::Encoding)?;
let data_bytes: Cow<[u8]> = DC::bytes_encode(&data).ok_or(Error::Encoding)?;
let mut key_val = unsafe { crate::into_val(&key_bytes) };
let mut data_val = unsafe { crate::into_val(&data_bytes) };
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, T, KC, DC>(
&self,
txn: &mut RwTxn<T>,
key: &'a KC::EItem,
data: &'a DC::EItem,
) -> Result<()>
where
KC: BytesEncode<'a>,
DC: BytesEncode<'a>,
{
assert_eq!(self.env_ident, txn.txn.env.env_mut_ptr() as usize);
let key_bytes: Cow<[u8]> = KC::bytes_encode(&key).ok_or(Error::Encoding)?;
let data_bytes: Cow<[u8]> = DC::bytes_encode(&data).ok_or(Error::Encoding)?;
let mut key_val = unsafe { crate::into_val(&key_bytes) };
let mut data_val = unsafe { crate::into_val(&data_bytes) };
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, T, KC>(&self, txn: &mut RwTxn<T>, key: &'a KC::EItem) -> Result<bool>
where
KC: BytesEncode<'a>,
{
assert_eq!(self.env_ident, txn.txn.env.env_mut_ptr() as usize);
let key_bytes: Cow<[u8]> = KC::bytes_encode(&key).ok_or(Error::Encoding)?;
let mut key_val = unsafe { crate::into_val(&key_bytes) };
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<'a, 'txn, T, KC, R>(&self, txn: &'txn mut RwTxn<T>, range: &'a R) -> Result<usize>
where
KC: BytesEncode<'a> + BytesDecode<'txn>,
R: RangeBounds<KC::EItem>,
{
assert_eq!(self.env_ident, txn.txn.env.env_mut_ptr() as usize);
let mut count = 0;
let mut iter = self.range_mut::<T, KC, DecodeIgnore, _>(txn, range)?;
while let Some(_) = iter.next() {
iter.del_current()?;
count += 1;
}
Ok(count)
}
pub fn clear<T>(&self, txn: &mut RwTxn<T>) -> 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) }
}
pub fn as_uniform<KC, DC>(&self) -> Database<KC, DC> {
Database::new(self.env_ident, self.dbi)
}
}