use crate::{
Cursor, MdbxError, ReadResult, TableObject, TableObjectOwned, TransactionKind, tx::TxPtrAccess,
};
use std::{marker::PhantomData, ptr};
pub struct IterDupOfKey<'tx, 'cur, K: TransactionKind, Value = std::borrow::Cow<'tx, [u8]>> {
cursor: &'cur mut Cursor<'tx, K>,
pending: Option<Value>,
exhausted: bool,
_marker: PhantomData<fn() -> Value>,
}
impl<K, Value> core::fmt::Debug for IterDupOfKey<'_, '_, K, Value>
where
K: TransactionKind,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("IterDupOfKey").field("exhausted", &self.exhausted).finish()
}
}
impl<'tx: 'cur, 'cur, K, Value> IterDupOfKey<'tx, 'cur, K, Value>
where
K: TransactionKind,
{
pub(crate) fn new_end(cursor: &'cur mut Cursor<'tx, K>) -> Self {
IterDupOfKey { cursor, pending: None, exhausted: true, _marker: PhantomData }
}
pub(crate) fn new_with(cursor: &'cur mut Cursor<'tx, K>, first: Value) -> Self {
IterDupOfKey { cursor, pending: Some(first), exhausted: false, _marker: PhantomData }
}
}
impl<'tx: 'cur, 'cur, K, Value> IterDupOfKey<'tx, 'cur, K, Value>
where
K: TransactionKind,
Value: TableObject<'tx>,
{
fn execute_next_dup(&self) -> ReadResult<Option<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, ffi::MDBX_NEXT_DUP)
};
match res {
ffi::MDBX_SUCCESS => {
unsafe {
let value = TableObject::decode_val::<K>(txn, data)?;
Ok(Some(value))
}
}
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<Value>> {
if self.exhausted {
return Ok(None);
}
if let Some(v) = self.pending.take() {
return Ok(Some(v));
}
let result = self.execute_next_dup()?;
if result.is_none() {
self.exhausted = true;
}
Ok(result)
}
}
impl<K, Value> IterDupOfKey<'_, '_, K, Value>
where
K: TransactionKind,
Value: TableObjectOwned,
{
pub fn owned_next(&mut self) -> ReadResult<Option<Value>> {
if self.exhausted {
return Ok(None);
}
if let Some(v) = self.pending.take() {
return Ok(Some(v));
}
let result = self.execute_next_dup()?;
if result.is_none() {
self.exhausted = true;
}
Ok(result)
}
}
impl<K, Value> Iterator for IterDupOfKey<'_, '_, K, Value>
where
K: TransactionKind,
Value: TableObjectOwned,
{
type Item = ReadResult<Value>;
fn next(&mut self) -> Option<Self::Item> {
self.owned_next().transpose()
}
}