use core::marker::PhantomData;
use crate::{DescendError, IntoKeys, KeyError, Keys, Schema, Short, Track, 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> {
schema: &'static Schema,
state: [usize; D],
root: usize,
depth: usize,
_n: PhantomData<N>,
}
impl<N, const D: usize> NodeIter<N, D> {
pub const fn with(schema: &'static Schema, state: [usize; D], root: usize) -> Self {
assert!(root <= D);
Self {
schema,
state,
root,
depth: D + 1,
_n: PhantomData,
}
}
pub const fn new(schema: &'static Schema) -> Self {
Self::with(schema, [0; D], 0)
}
pub fn with_root(
schema: &'static Schema,
root: impl IntoKeys,
) -> Result<Self, DescendError<()>> {
let mut state = [0; D];
let mut root = root.into_keys().track();
let mut tr = Short::new(state.as_mut());
tr.transcode(schema, &mut root)?;
Ok(Self::with(schema, state, root.depth()))
}
pub const fn exact_size(schema: &'static Schema) -> ExactSize<Self> {
let shape = schema.shape();
if D < shape.max_depth {
panic!("insufficient depth for exact size iteration");
}
ExactSize {
iter: Self::new(schema),
count: shape.count.get(),
}
}
pub const fn schema(&self) -> &'static Schema {
self.schema
}
pub fn state(&self) -> Option<&[usize]> {
self.state.get(..self.depth)
}
pub const fn root(&self) -> usize {
self.root
}
}
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);
debug_assert!(self.depth <= D + 1);
if self.depth == self.root {
return None;
}
if self.depth <= D {
self.state[self.depth - 1] += 1;
}
let mut item = Track::new(N::default());
let ret = item.transcode(self.schema, &self.state[..]);
let (item, depth) = item.into_inner();
match ret {
Err(DescendError::Key(KeyError::NotFound)) => {
self.state[depth] = 0;
self.depth = depth.max(self.root);
}
Err(DescendError::Key(KeyError::TooLong)) | Ok(()) => {
self.depth = depth;
return Some(Ok(item));
}
Err(DescendError::Key(KeyError::TooShort)) => {
self.depth = depth;
}
Err(DescendError::Inner(e)) => {
return Some(Err(e));
}
}
}
}
}
impl<N: Transcode + Default, const D: usize> core::iter::FusedIterator for NodeIter<N, D> {}