use alloc::boxed::Box;
use core::iter::Peekable;
use miden_field::Word;
use super::Result;
use crate::{
Set,
merkle::smt::large_forest::{history::HistoryView, root::TreeEntry},
};
pub(super) enum EntriesIterator<'forest> {
WithHistory {
full_tree_iter:
Peekable<Box<dyn Iterator<Item = super::backend::Result<TreeEntry>> + 'forest>>,
history_view: HistoryView<'forest>,
yielded_history_keys: Set<Word>,
state: EntriesIteratorState<'forest>,
},
WithoutHistory {
full_tree_iter: Box<dyn Iterator<Item = super::backend::Result<TreeEntry>> + 'forest>,
faulted: bool,
},
}
impl<'forest> EntriesIterator<'forest> {
pub(super) fn new_with_history(
full_tree_iter: impl Iterator<Item = super::backend::Result<TreeEntry>> + 'forest,
history_view: HistoryView<'forest>,
) -> Self {
let full_tree_iter: Box<dyn Iterator<Item = _>> = Box::new(full_tree_iter);
Self::WithHistory {
full_tree_iter: full_tree_iter.peekable(),
history_view,
yielded_history_keys: Set::new(),
state: EntriesIteratorState::Initial,
}
}
pub(super) fn new_without_history(
full_tree_iter: impl Iterator<Item = super::backend::Result<TreeEntry>> + 'forest,
) -> Self {
let full_tree_iter = Box::new(full_tree_iter);
Self::WithoutHistory { full_tree_iter, faulted: false }
}
#[inline(always)] fn next_with_history(&mut self) -> Option<Result<TreeEntry>> {
let EntriesIterator::WithHistory {
full_tree_iter,
history_view,
yielded_history_keys,
state,
} = self
else {
panic!("EntriesIterator::next_with_history called without history")
};
loop {
match state {
EntriesIteratorState::Faulted => return None,
EntriesIteratorState::Initial => {
if full_tree_iter.peek().is_none() {
let iterator = Box::new(
history_view
.changed_keys()
.map(|(key, value)| TreeEntry { key, value }),
);
*state = EntriesIteratorState::ReadingHistory { iterator };
} else {
*state = EntriesIteratorState::ReadingFullTree;
}
continue;
},
EntriesIteratorState::ReadingFullTree => {
if full_tree_iter.peek().is_none() {
let iterator = Box::new(
history_view
.changed_keys()
.map(|(key, value)| TreeEntry { key, value }),
);
*state = EntriesIteratorState::ReadingHistory { iterator };
continue;
}
let Some(entry) = full_tree_iter.next() else {
unreachable!("The iterator is known to have another item available");
};
let entry = match entry {
Ok(entry) => entry,
Err(e) => {
*state = EntriesIteratorState::Faulted;
return Some(Err(e.into()));
},
};
let value = if let Some(v) = history_view.value(&entry.key) {
yielded_history_keys.insert(entry.key);
if v.is_empty() {
continue;
}
TreeEntry { key: entry.key, value: v }
} else {
entry
};
return Some(Ok(value));
},
EntriesIteratorState::ReadingHistory { iterator } => {
for entry in iterator.by_ref() {
if !yielded_history_keys.contains(&entry.key) && !entry.value.is_empty() {
return Some(Ok(entry));
}
}
return None;
},
}
}
}
#[inline(always)] fn next_without_history(&mut self) -> Option<Result<TreeEntry>> {
let EntriesIterator::WithoutHistory { full_tree_iter, faulted } = self else {
panic!("EntriesIterator::next_without_history called with history")
};
if *faulted {
return None;
}
let result = full_tree_iter.next().map(|e| e.map_err(Into::into));
if matches!(&result, Some(Err(_))) {
*faulted = true;
}
result
}
}
impl Iterator for EntriesIterator<'_> {
type Item = Result<TreeEntry>;
fn next(&mut self) -> Option<Self::Item> {
match self {
EntriesIterator::WithHistory { .. } => self.next_with_history(),
EntriesIterator::WithoutHistory { .. } => self.next_without_history(),
}
}
}
pub(super) enum EntriesIteratorState<'forest> {
Initial,
ReadingFullTree,
ReadingHistory {
iterator: Box<dyn Iterator<Item = TreeEntry> + 'forest>,
},
Faulted,
}