use core::marker::PhantomData;
use crate::{DescendError, Internal, IntoKeys, KeyError, Schema, Transcode};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ExactSize<T> {
iter: T,
count: usize,
}
impl<T: Iterator> Iterator for ExactSize<T> {
type Item = T::Item;
fn next(&mut self) -> Option<Self::Item> {
if let Some(v) = self.iter.next() {
self.count -= 1; Some(v)
} else {
debug_assert!(self.count == 0);
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.count, Some(self.count))
}
}
impl<T: Iterator> ExactSizeIterator for ExactSize<T> {}
impl<T: Iterator> core::iter::FusedIterator for ExactSize<T> {}
#[derive(Clone, Debug, PartialEq)]
pub struct NodeIter<N, const D: usize> {
root_schema: &'static Schema,
root_depth: usize,
parents: [Option<&'static Internal>; D],
indices: [usize; D],
schema: &'static Schema,
depth: usize,
target: PhantomData<N>,
}
impl<N, const D: usize> NodeIter<N, D> {
pub const fn new(root_schema: &'static Schema) -> Self {
Self {
root_schema,
root_depth: 0,
parents: [None; D],
indices: [0; D],
schema: root_schema,
depth: D + 1,
target: PhantomData,
}
}
fn rooted(
root_schema: &'static Schema,
indices: [usize; D],
root_depth: usize,
schema: &'static Schema,
) -> Self {
let mut iter = Self {
root_schema,
root_depth,
parents: [None; D],
indices,
schema,
depth: D + 1,
target: PhantomData,
};
iter.fill_parents(root_depth);
iter
}
pub fn with_root(
schema: &'static Schema,
root: impl IntoKeys,
) -> Result<Self, DescendError<()>> {
let mut indices = [0; D];
let info = schema
.resolve_into(root, indices.as_mut())
.map_err(|err| err.error)?;
Ok(Self::rooted(schema, indices, info.depth, info.schema))
}
pub const fn exact_size(self) -> ExactSize<Self> {
let shape = self.root_schema.shape();
if D < shape.max_depth {
panic!("insufficient depth for exact size iteration");
}
let mut i = 0;
while i < D {
if self.indices[i] != 0 {
panic!("exact size requires a fresh root iterator");
}
i += 1;
}
if self.root_depth != 0 || self.depth != D + 1 {
panic!("exact size requires a fresh root iterator");
}
ExactSize {
iter: self,
count: shape.count.get(),
}
}
pub const fn root_schema(&self) -> &'static Schema {
self.root_schema
}
pub fn indices(&self) -> Option<&[usize]> {
self.indices.get(..self.depth)
}
pub fn schema(&self) -> Option<&'static Schema> {
(self.depth <= D).then_some(self.schema)
}
pub const fn root_depth(&self) -> usize {
self.root_depth
}
fn fill_parents(&mut self, depth: usize) -> &'static Schema {
let mut schema = self.root_schema;
let mut i = 0;
while i < depth {
let Some(internal) = schema.internal() else {
unreachable!("validated iterator path must stay internal until root depth");
};
schema = internal.get_schema(self.indices[i]);
self.parents[i] = Some(internal);
i += 1;
}
schema
}
fn descend_leftmost(&mut self) {
let mut schema = self.schema;
while self.depth < D {
let Some(internal) = schema.internal() else {
break;
};
self.parents[self.depth] = Some(internal);
self.indices[self.depth] = 0;
schema = internal.get_schema(0);
self.depth += 1;
}
self.schema = schema;
}
fn bump(&mut self) -> bool {
let mut depth = self.depth;
while depth > self.root_depth {
let parent = depth - 1;
let Some(internal) = self.parents[parent] else {
unreachable!("iterator parent cache must be populated below the active depth");
};
let next = self.indices[parent] + 1;
if next < internal.len().get() {
self.indices[parent] = next;
self.depth = parent + 1;
self.schema = internal.get_schema(next);
return true;
}
depth = parent;
}
self.depth = self.root_depth;
false
}
}
impl<N: Transcode + Default, const D: usize> Iterator for NodeIter<N, D> {
type Item = Result<N, N::Error>;
fn next(&mut self) -> Option<Self::Item> {
loop {
debug_assert!(self.depth >= self.root_depth);
debug_assert!(self.depth <= D + 1);
if self.depth == self.root_depth {
return None;
}
if self.depth <= D {
if !self.bump() {
return None;
}
} else {
self.depth = self.root_depth;
}
self.descend_leftmost();
debug_assert!(self.depth >= self.root_depth);
debug_assert!(self.depth <= D);
let mut item = N::default();
match item.transcode_from(self.root_schema, &self.indices[..self.depth]) {
Ok(()) => return Some(Ok(item)),
Err(DescendError::Key(KeyError::TooShort)) => {}
Err(DescendError::Inner(e)) => return Some(Err(e)),
Err(DescendError::Key(KeyError::NotFound | KeyError::TooLong)) => unreachable!(),
}
}
}
}
impl<N: Transcode + Default, const D: usize> core::iter::FusedIterator for NodeIter<N, D> {}