use super::file::JournalFile;
use super::mmap::MemoryMap;
use super::object::*;
use crate::error::{JournalError, Result};
use crate::file::value_guard::ValueGuard;
use std::num::NonZeroU64;
pub struct FieldIterator<'a, M: MemoryMap> {
pub(super) journal: &'a JournalFile<M>,
pub(super) field_hash_table: Option<FieldHashTable<&'a [u8]>>,
pub(super) current_bucket_index: usize,
pub(super) next_field_offset: Option<NonZeroU64>,
}
impl<M: MemoryMap> FieldIterator<'_, M> {
pub(super) fn advance_to_next_nonempty_bucket(&mut self) {
let Some(hash_table) = &self.field_hash_table else {
return;
};
let items = &hash_table.items;
while self.current_bucket_index < items.len() {
let bucket = items[self.current_bucket_index];
if bucket.head_hash_offset.is_some() {
self.next_field_offset = bucket.head_hash_offset;
return;
}
self.current_bucket_index += 1;
}
self.next_field_offset = None;
}
}
impl<'a, M: MemoryMap> Iterator for FieldIterator<'a, M> {
type Item = Result<ValueGuard<'a, FieldObject<&'a [u8]>>>;
fn next(&mut self) -> Option<Self::Item> {
let offset = self.next_field_offset?;
match self.journal.field_ref(offset) {
Ok(field_guard) => {
self.next_field_offset = field_guard.header.next_hash_offset;
if self.next_field_offset.is_none() {
self.current_bucket_index += 1;
self.advance_to_next_nonempty_bucket();
}
Some(Ok(field_guard))
}
Err(e) => {
self.next_field_offset = None;
Some(Err(e))
}
}
}
}
pub struct FieldDataIterator<'a, M: MemoryMap> {
pub(super) journal: &'a JournalFile<M>,
pub(super) current_data_offset: Option<NonZeroU64>,
}
impl<'a, M: MemoryMap> Iterator for FieldDataIterator<'a, M> {
type Item = Result<ValueGuard<'a, DataObject<&'a [u8]>>>;
fn next(&mut self) -> Option<Self::Item> {
let data_offset = self.current_data_offset?;
match self.journal.data_ref(data_offset) {
Ok(data_guard) => {
self.current_data_offset = data_guard.header.next_field_offset;
Some(Ok(data_guard))
}
Err(e) => {
self.current_data_offset = None;
Some(Err(e))
}
}
}
}
pub struct FieldDataOffsetIterator<'a, M: MemoryMap> {
pub(super) journal: &'a JournalFile<M>,
pub(super) current_data_offset: Option<NonZeroU64>,
}
impl<'a, M: MemoryMap> Iterator for FieldDataOffsetIterator<'a, M> {
type Item = Result<(NonZeroU64, ValueGuard<'a, DataObject<&'a [u8]>>)>;
fn next(&mut self) -> Option<Self::Item> {
let data_offset = self.current_data_offset?;
match self.journal.data_ref(data_offset) {
Ok(data_guard) => {
self.current_data_offset = data_guard.header.next_field_offset;
Some(Ok((data_offset, data_guard)))
}
Err(e) => {
self.current_data_offset = None;
Some(Err(e))
}
}
}
}
pub struct EntryDataIterator<'a, M: MemoryMap> {
pub(super) journal: &'a JournalFile<M>,
pub(super) entry_offset: Option<NonZeroU64>,
pub(super) current_index: usize,
pub(super) total_items: usize,
}
impl<'a, M: MemoryMap> Iterator for EntryDataIterator<'a, M> {
type Item = Result<ValueGuard<'a, DataObject<&'a [u8]>>>;
fn next(&mut self) -> Option<Self::Item> {
let entry_offset = self.entry_offset?;
if self.current_index >= self.total_items {
return None;
}
match self.journal.entry_ref(entry_offset) {
Ok(entry_guard) => {
let idx = self.current_index;
self.current_index += 1;
let data_offset = match &entry_guard.items {
EntryItemsType::Regular(items) => {
if idx >= items.len() {
return None;
}
items[idx].object_offset
}
EntryItemsType::Compact(items) => {
if idx >= items.len() {
return None;
}
items[idx].object_offset as u64
}
};
let data_offset = match NonZeroU64::new(data_offset) {
Some(offset) => offset,
None => {
self.current_index = self.total_items;
return Some(Err(JournalError::InvalidOffset));
}
};
drop(entry_guard);
match self.journal.data_ref(data_offset) {
Ok(data_guard) => Some(Ok(data_guard)),
Err(e) => {
self.current_index = self.total_items;
Some(Err(e))
}
}
}
Err(e) => {
self.current_index = self.total_items;
Some(Err(e))
}
}
}
}