use crate::{
Cursor, MdbxError, ReadResult, TableObject, TableObjectOwned, TransactionKind,
error::mdbx_result, tx::TxPtrAccess,
};
use std::{borrow::Cow, marker::PhantomData, ptr};
pub type IterKeyVals<'tx, 'cur, K, A, Key = Cow<'tx, [u8]>, Value = Cow<'tx, [u8]>> =
Iter<'tx, 'cur, K, A, Key, Value, { ffi::MDBX_NEXT }>;
pub type IterDupKeys<'tx, 'cur, K, A, Key = Cow<'tx, [u8]>, Value = Cow<'tx, [u8]>> =
Iter<'tx, 'cur, K, A, Key, Value, { ffi::MDBX_NEXT_NODUP }>;
pub type IterDupVals<'tx, 'cur, K, A, Key = Cow<'tx, [u8]>, Value = Cow<'tx, [u8]>> =
Iter<'tx, 'cur, K, A, Key, Value, { ffi::MDBX_NEXT_DUP }>;
pub struct Iter<
'tx,
'cur,
K: TransactionKind,
A: TxPtrAccess,
Key = Cow<'tx, [u8]>,
Value = Cow<'tx, [u8]>,
const OP: u32 = { ffi::MDBX_NEXT },
> {
cursor: Cow<'cur, Cursor<'tx, K, A>>,
pending: Option<(Key, Value)>,
exhausted: bool,
_marker: PhantomData<fn() -> (Key, Value)>,
}
impl<K, A, Key, Value, const OP: u32> core::fmt::Debug for Iter<'_, '_, K, A, Key, Value, OP>
where
K: TransactionKind,
A: TxPtrAccess,
Key: core::fmt::Debug,
Value: core::fmt::Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Iter").finish()
}
}
impl<'tx: 'cur, 'cur, K, A, Key, Value, const OP: u32> Iter<'tx, 'cur, K, A, Key, Value, OP>
where
K: TransactionKind,
A: TxPtrAccess,
{
pub(crate) fn new(cursor: Cow<'cur, Cursor<'tx, K, A>>) -> Self {
Iter { cursor, pending: None, exhausted: false, _marker: PhantomData }
}
pub(crate) fn from_ref(cursor: &'cur mut Cursor<'tx, K, A>) -> Self {
Self::new(Cow::Borrowed(cursor))
}
pub(crate) fn new_end(cursor: Cow<'cur, Cursor<'tx, K, A>>) -> Self {
Iter { cursor, pending: None, exhausted: true, _marker: PhantomData }
}
pub(crate) fn end_from_ref(cursor: &'cur mut Cursor<'tx, K, A>) -> Self {
Self::new_end(Cow::Borrowed(cursor))
}
pub(crate) fn new_with(cursor: Cow<'cur, Cursor<'tx, K, A>>, first: (Key, Value)) -> Self {
Iter { cursor, pending: Some(first), exhausted: false, _marker: PhantomData }
}
pub(crate) fn from_ref_with(cursor: &'cur mut Cursor<'tx, K, A>, first: (Key, Value)) -> Self {
Self::new_with(Cow::Borrowed(cursor), first)
}
pub(crate) fn from_owned_with(cursor: Cursor<'tx, K, A>, first: (Key, Value)) -> Self
where
A: Sized,
{
Self::new_with(Cow::Owned(cursor), first)
}
}
impl<K, A, Key, Value, const OP: u32> Iter<'_, '_, K, A, Key, Value, OP>
where
K: TransactionKind,
A: TxPtrAccess,
Key: TableObjectOwned,
Value: TableObjectOwned,
{
pub fn owned_next(&mut self) -> ReadResult<Option<(Key, Value)>> {
if self.exhausted {
return Ok(None);
}
if let Some(v) = self.pending.take() {
return Ok(Some(v));
}
self.execute_op()
}
}
impl<'tx: 'cur, 'cur, K, A, Key, Value, const OP: u32> Iter<'tx, 'cur, K, A, Key, Value, OP>
where
K: TransactionKind,
A: TxPtrAccess,
Key: TableObject<'tx>,
Value: TableObject<'tx>,
{
fn execute_op(&self) -> ReadResult<Option<(Key, Value)>> {
let mut key = ffi::MDBX_val { iov_len: 0, iov_base: ptr::null_mut() };
let mut data = ffi::MDBX_val { iov_len: 0, iov_base: ptr::null_mut() };
self.cursor.access().with_txn_ptr(|txn| {
let res =
unsafe { ffi::mdbx_cursor_get(self.cursor.cursor(), &mut key, &mut data, OP) };
match res {
ffi::MDBX_SUCCESS => {
unsafe {
let key = TableObject::decode_val::<K>(txn, key)?;
let data = TableObject::decode_val::<K>(txn, data)?;
Ok(Some((key, data)))
}
}
ffi::MDBX_NOTFOUND | ffi::MDBX_ENODATA | ffi::MDBX_RESULT_TRUE => Ok(None),
other => Err(MdbxError::from_err_code(other).into()),
}
})?
}
pub fn borrow_next(&mut self) -> ReadResult<Option<(Key, Value)>> {
if self.exhausted {
return Ok(None);
}
if let Some(v) = self.pending.take() {
return Ok(Some(v));
}
self.execute_op()
}
}
impl<K, A, Key, Value, const OP: u32> Iterator for Iter<'_, '_, K, A, Key, Value, OP>
where
K: TransactionKind,
A: TxPtrAccess,
Key: TableObjectOwned,
Value: TableObjectOwned,
{
type Item = ReadResult<(Key, Value)>;
fn next(&mut self) -> Option<Self::Item> {
self.owned_next().transpose()
}
}
pub struct IterDup<
'tx,
'cur,
K: TransactionKind,
A: TxPtrAccess,
Key = Cow<'tx, [u8]>,
Value = Cow<'tx, [u8]>,
> {
inner: IterDupKeys<'tx, 'cur, K, A, Key, Value>,
}
impl<'tx, 'cur, K, A, Key, Value> core::fmt::Debug for IterDup<'tx, 'cur, K, A, Key, Value>
where
K: TransactionKind,
A: TxPtrAccess,
Key: core::fmt::Debug,
Value: core::fmt::Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("IterDup").finish()
}
}
impl<'tx, 'cur, K, A, Key, Value> IterDup<'tx, 'cur, K, A, Key, Value>
where
K: TransactionKind,
A: TxPtrAccess,
{
pub(crate) fn new(cursor: Cow<'cur, Cursor<'tx, K, A>>) -> Self {
IterDup { inner: IterDupKeys::new(cursor) }
}
pub(crate) fn from_ref(cursor: &'cur mut Cursor<'tx, K, A>) -> Self {
Self::new(Cow::Borrowed(cursor))
}
pub fn from_owned(cursor: Cursor<'tx, K, A>) -> Self
where
A: Sized,
{
Self::new(Cow::Owned(cursor))
}
pub(crate) fn new_with(cursor: Cow<'cur, Cursor<'tx, K, A>>, first: (Key, Value)) -> Self {
IterDup { inner: Iter::new_with(cursor, first) }
}
pub fn from_ref_with(cursor: &'cur mut Cursor<'tx, K, A>, first: (Key, Value)) -> Self {
Self::new_with(Cow::Borrowed(cursor), first)
}
pub fn new_end(cursor: Cow<'cur, Cursor<'tx, K, A>>) -> Self {
IterDup { inner: Iter::new_end(cursor) }
}
pub fn end_from_ref(cursor: &'cur mut Cursor<'tx, K, A>) -> Self {
Self::new_end(Cow::Borrowed(cursor))
}
pub fn end_from_owned(cursor: Cursor<'tx, K, A>) -> Self
where
A: Sized,
{
Self::new_end(Cow::Owned(cursor))
}
}
impl<'tx: 'cur, 'cur, K, A, Key, Value> IterDup<'tx, 'cur, K, A, Key, Value>
where
K: TransactionKind,
A: TxPtrAccess + 'tx,
Key: TableObject<'tx>,
Value: TableObject<'tx>,
{
pub fn borrow_next(&mut self) -> ReadResult<Option<IterDupVals<'tx, 'cur, K, A, Key, Value>>> {
let cursor_ptr = self.inner.cursor.as_ref().cursor();
let access: *const A = self.inner.cursor.access();
let access = unsafe { access.as_ref().unwrap() };
match self.inner.borrow_next()? {
Some((key, value)) => {
let db = self.inner.cursor.as_ref().db();
let dup_cursor = access.with_txn_ptr(move |_| unsafe {
let new_cursor = ffi::mdbx_cursor_create(ptr::null_mut());
let res = ffi::mdbx_cursor_copy(cursor_ptr, new_cursor);
mdbx_result(res)?;
Ok::<_, MdbxError>(Cursor::new_raw(access, new_cursor, db))
})??;
Ok(Some(IterDupVals::from_owned_with(dup_cursor, (key, value))))
}
None => Ok(None),
}
}
}
impl<'tx: 'cur, 'cur, K, A, Key, Value> IterDup<'tx, 'cur, K, A, Key, Value>
where
K: TransactionKind,
A: TxPtrAccess + 'tx,
Key: TableObjectOwned,
Value: TableObjectOwned,
{
pub fn owned_next(&mut self) -> ReadResult<Option<IterDupVals<'tx, 'cur, K, A, Key, Value>>> {
self.borrow_next()
}
}
impl<'tx: 'cur, 'cur, K, A, Key, Value> Iterator for IterDup<'tx, 'cur, K, A, Key, Value>
where
K: TransactionKind,
A: TxPtrAccess + 'tx,
Key: TableObjectOwned,
Value: TableObjectOwned,
{
type Item = ReadResult<IterDupVals<'tx, 'cur, K, A, Key, Value>>;
fn next(&mut self) -> Option<Self::Item> {
self.owned_next().transpose()
}
}
pub type RoIterSync<'tx, 'cur, Key = Cow<'tx, [u8]>, Value = Cow<'tx, [u8]>> =
IterKeyVals<'tx, 'cur, crate::RO, crate::tx::PtrSyncInner<crate::RO>, Key, Value>;
pub type RwIterSync<'tx, 'cur, Key = Cow<'tx, [u8]>, Value = Cow<'tx, [u8]>> =
IterKeyVals<'tx, 'cur, crate::RW, crate::tx::PtrSyncInner<crate::RW>, Key, Value>;
pub type RoIterUnsync<'tx, 'cur, Key = Cow<'tx, [u8]>, Value = Cow<'tx, [u8]>> =
IterKeyVals<'tx, 'cur, crate::RO, crate::tx::RoGuard, Key, Value>;
pub type RwIterUnsync<'tx, 'cur, Key = Cow<'tx, [u8]>, Value = Cow<'tx, [u8]>> =
IterKeyVals<'tx, 'cur, crate::RW, crate::tx::RwUnsync, Key, Value>;