use crate::{Cursor, ReadResult, TableObjectOwned, TransactionKind};
use std::{borrow::Cow, marker::PhantomData};
pub struct IterDupFixedOfKey<'tx, 'cur, K: TransactionKind, Value = Vec<u8>> {
cursor: &'cur mut Cursor<'tx, K>,
current_page: Cow<'tx, [u8]>,
page_offset: usize,
value_size: usize,
remaining: usize,
exhausted: bool,
_marker: PhantomData<fn() -> Value>,
}
impl<K, Value> core::fmt::Debug for IterDupFixedOfKey<'_, '_, K, Value>
where
K: TransactionKind,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let remaining_in_page = if self.value_size > 0 {
self.current_page.len().saturating_sub(self.page_offset) / self.value_size
} else {
0
};
f.debug_struct("IterDupFixedOfKey")
.field("exhausted", &self.exhausted)
.field("value_size", &self.value_size)
.field("remaining_in_page", &remaining_in_page)
.field("remaining_for_key", &self.remaining)
.finish()
}
}
impl<'tx: 'cur, 'cur, K, Value> IterDupFixedOfKey<'tx, 'cur, K, Value>
where
K: TransactionKind,
{
pub const fn value_size(&self) -> usize {
self.value_size
}
pub(crate) fn new_end(cursor: &'cur mut Cursor<'tx, K>) -> Self {
IterDupFixedOfKey {
cursor,
current_page: Cow::Borrowed(&[]),
page_offset: 0,
value_size: 0,
remaining: 0,
exhausted: true,
_marker: PhantomData,
}
}
pub(crate) fn new_with(
cursor: &'cur mut Cursor<'tx, K>,
page: Cow<'tx, [u8]>,
value_size: usize,
) -> Self {
let remaining = cursor.dup_count().unwrap_or(1);
IterDupFixedOfKey {
cursor,
current_page: page,
page_offset: 0,
value_size,
remaining,
exhausted: false,
_marker: PhantomData,
}
}
}
impl<'tx: 'cur, 'cur, K, Value> IterDupFixedOfKey<'tx, 'cur, K, Value>
where
K: TransactionKind,
{
fn consume_value(&mut self) -> Option<Cow<'tx, [u8]>> {
if self.value_size == 0 {
return None;
}
let end = self.page_offset.checked_add(self.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> {
if let Some((_key, page)) = self.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() {
self.remaining = self.remaining.saturating_sub(1);
return Ok(Some(value));
}
if !self.fetch_next_page()? {
return Ok(None);
}
let value = self.consume_value().expect("freshly fetched page should have values");
self.remaining = self.remaining.saturating_sub(1);
Ok(Some(value))
}
pub fn owned_next(&mut self) -> ReadResult<Option<Value>>
where
Value: TableObjectOwned,
{
self.borrow_next()?.map(|cow| Value::decode(&cow)).transpose()
}
}
impl<'tx: 'cur, 'cur, K, Value> Iterator for IterDupFixedOfKey<'tx, 'cur, K, Value>
where
K: TransactionKind,
Value: TableObjectOwned,
{
type Item = ReadResult<Value>;
fn next(&mut self) -> Option<Self::Item> {
self.owned_next().transpose()
}
fn size_hint(&self) -> (usize, Option<usize>) {
if self.exhausted || self.value_size == 0 {
return (0, Some(0));
}
(self.remaining, Some(self.remaining))
}
}