use std::marker::PhantomData;
use std::mem;
pub enum UseOrSubdivide<T, I: Iterator<Item = T>> {
Empty,
Use(T),
Subdivide(I),
}
impl<T, I: Iterator<Item = T>> Iterator for UseOrSubdivide<T, I> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
match self {
Self::Empty => {
return None;
}
Self::Use(_) => {
let taken_use_or_subdivide = mem::replace(self, UseOrSubdivide::Empty);
match taken_use_or_subdivide {
Self::Use(data) => {
return Some(data);
}
_ => unreachable!("this code only runs when UseOrSubdivide::Use"),
}
}
Self::Subdivide(iter) => {
return iter.next();
}
}
}
}
pub struct SubdivisionMap<
'i,
T: 'i,
I: Iterator<Item = T> + 'i,
R: Iterator<Item = T> + 'i,
F: Fn(T) -> UseOrSubdivide<T, R>,
> {
_marker: PhantomData<&'i ()>,
iter: I,
buffer: Option<R>,
callback: F,
}
impl<
'i,
T,
I: Iterator<Item = T> + 'i,
R: Iterator<Item = T> + 'i,
F: Fn(T) -> UseOrSubdivide<T, R>,
> SubdivisionMap<'i, T, I, R, F>
{
pub fn new(iter: I, callback: F) -> Self {
Self {
_marker: PhantomData,
iter,
callback,
buffer: None,
}
}
}
impl<
'i,
T,
I: Iterator<Item = T> + 'i,
R: Iterator<Item = T> + 'i,
F: Fn(T) -> UseOrSubdivide<T, R>,
> Iterator for SubdivisionMap<'i, T, I, R, F>
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(buffer_iter) = &mut self.buffer {
if let Some(item) = buffer_iter.next() {
return Some(item);
}
self.buffer = None;
}
if let Some(raw_item) = self.iter.next() {
match (self.callback)(raw_item) {
UseOrSubdivide::Empty => return None,
UseOrSubdivide::Use(item) => return Some(item),
UseOrSubdivide::Subdivide(list) => {
self.buffer = Some(list.into_iter());
}
}
} else {
return None;
}
}
}
}