use crate::{Cursor, ReadResult, TransactionKind};
use std::{borrow::Cow, marker::PhantomData};
pub struct IterDupFixedOfKey<'tx, 'cur, K: TransactionKind, const VALUE_SIZE: usize = 0> {
cursor: Cow<'cur, Cursor<'tx, K>>,
current_page: Cow<'tx, [u8]>,
page_offset: usize,
exhausted: bool,
_marker: PhantomData<fn() -> ()>,
}
impl<K, const VALUE_SIZE: usize> core::fmt::Debug for IterDupFixedOfKey<'_, '_, K, VALUE_SIZE>
where
K: TransactionKind,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let remaining = self.current_page.len().saturating_sub(self.page_offset) / VALUE_SIZE;
f.debug_struct("IterDupFixedOfKey")
.field("exhausted", &self.exhausted)
.field("remaining_in_page", &remaining)
.finish()
}
}
impl<'tx: 'cur, 'cur, K, const VALUE_SIZE: usize> IterDupFixedOfKey<'tx, 'cur, K, VALUE_SIZE>
where
K: TransactionKind,
{
pub(crate) fn new_end(cursor: Cow<'cur, Cursor<'tx, K>>) -> Self {
IterDupFixedOfKey {
cursor,
current_page: Cow::Borrowed(&[]),
page_offset: 0,
exhausted: true,
_marker: PhantomData,
}
}
pub(crate) fn end_from_ref(cursor: &'cur mut Cursor<'tx, K>) -> Self {
Self::new_end(Cow::Borrowed(cursor))
}
pub(crate) fn new_with(cursor: Cow<'cur, Cursor<'tx, K>>, page: Cow<'tx, [u8]>) -> Self {
IterDupFixedOfKey {
cursor,
current_page: page,
page_offset: 0,
exhausted: false,
_marker: PhantomData,
}
}
pub(crate) fn from_ref_with(cursor: &'cur mut Cursor<'tx, K>, page: Cow<'tx, [u8]>) -> Self {
Self::new_with(Cow::Borrowed(cursor), page)
}
}
impl<'tx: 'cur, 'cur, K, const VALUE_SIZE: usize> IterDupFixedOfKey<'tx, 'cur, K, VALUE_SIZE>
where
K: TransactionKind,
{
fn consume_value(&mut self) -> Option<Cow<'tx, [u8]>> {
let end = self.page_offset.checked_add(VALUE_SIZE)?;
if end > self.current_page.len() {
return None;
}
let start = self.page_offset;
self.page_offset = end;
match &self.current_page {
Cow::Borrowed(slice) => Some(Cow::Borrowed(&slice[start..end])),
Cow::Owned(vec) => Some(Cow::Owned(vec[start..end].to_vec())),
}
}
fn fetch_next_page(&mut self) -> ReadResult<bool> {
let cursor = self.cursor.to_mut();
if let Some((_key, page)) = cursor.next_multiple::<(), Cow<'tx, [u8]>>()? {
self.current_page = page;
self.page_offset = 0;
return Ok(true);
}
self.exhausted = true;
Ok(false)
}
pub fn borrow_next(&mut self) -> ReadResult<Option<Cow<'tx, [u8]>>> {
if self.exhausted {
return Ok(None);
}
if let Some(value) = self.consume_value() {
return Ok(Some(value));
}
if !self.fetch_next_page()? {
return Ok(None);
}
let value = self.consume_value().expect("freshly fetched page should have values");
Ok(Some(value))
}
pub fn owned_next(&mut self) -> ReadResult<Option<[u8; VALUE_SIZE]>> {
self.borrow_next().map(|opt| {
opt.map(|value| {
let mut arr = [0u8; VALUE_SIZE];
arr.copy_from_slice(&value);
arr
})
})
}
}
impl<'tx: 'cur, 'cur, K, const VALUE_SIZE: usize> Iterator
for IterDupFixedOfKey<'tx, 'cur, K, VALUE_SIZE>
where
K: TransactionKind,
{
type Item = ReadResult<[u8; VALUE_SIZE]>;
fn next(&mut self) -> Option<Self::Item> {
self.owned_next().transpose()
}
}