use crate::{
Cursor, MdbxError, ReadResult, TableObject, TableObjectOwned, TransactionKind, tx::TxPtrAccess,
};
use std::{marker::PhantomData, ptr};
pub struct Iter<
'tx,
'cur,
K: TransactionKind,
Key = std::borrow::Cow<'tx, [u8]>,
Value = std::borrow::Cow<'tx, [u8]>,
const OP: u32 = { ffi::MDBX_NEXT },
> {
pub(crate) cursor: &'cur mut Cursor<'tx, K>,
pending: Option<(Key, Value)>,
exhausted: bool,
_marker: PhantomData<fn() -> (Key, Value)>,
}
impl<K, Key, Value, const OP: u32> core::fmt::Debug for Iter<'_, '_, K, Key, Value, OP>
where
K: TransactionKind,
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, Key, Value, const OP: u32> Iter<'tx, 'cur, K, Key, Value, OP>
where
K: TransactionKind,
{
pub(crate) fn new(cursor: &'cur mut Cursor<'tx, K>) -> Self {
Iter { cursor, pending: None, exhausted: false, _marker: PhantomData }
}
pub(crate) fn new_end(cursor: &'cur mut Cursor<'tx, K>) -> Self {
Iter { cursor, pending: None, exhausted: true, _marker: PhantomData }
}
pub(crate) fn new_with(cursor: &'cur mut Cursor<'tx, K>, first: (Key, Value)) -> Self {
Iter { cursor, pending: Some(first), exhausted: false, _marker: PhantomData }
}
}
impl<K, Key, Value, const OP: u32> Iter<'_, '_, K, Key, Value, OP>
where
K: TransactionKind,
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, Key, Value, const OP: u32> Iter<'tx, 'cur, K, Key, Value, OP>
where
K: TransactionKind,
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, Key, Value, const OP: u32> Iterator for Iter<'_, '_, K, Key, Value, OP>
where
K: TransactionKind,
Key: TableObjectOwned,
Value: TableObjectOwned,
{
type Item = ReadResult<(Key, Value)>;
fn next(&mut self) -> Option<Self::Item> {
self.owned_next().transpose()
}
}