use core::{
cell::UnsafeCell, iter::{
FusedIterator, Iterator
}
};
pub mod nucleus;
use nucleus::Nucleus;
use crate::maybe::MaybeRc;
pub struct Forkable<I, const S: usize>
where
I: Iterator + FusedIterator,
<I as Iterator>::Item: Clone + Copy
{
iter_index: usize,
iter: MaybeRc<UnsafeCell<Nucleus<I, S>>>
}
impl<I, const S: usize> Iterator for Forkable<I, S>
where
I: Iterator + FusedIterator,
<I as Iterator>::Item: Clone + Copy
{
type Item = <I as Iterator>::Item;
fn next(&mut self) -> Option<Self::Item> {
let Self {
iter_index,
ref iter
} = self;
let iter = unsafe {
iter
.get()
.as_mut()
.unwrap_unchecked()
};
if *iter_index < iter.oldest_index() {
*iter_index = iter_index.saturating_add(1);
return None
}
let target_value = match iter.at(iter_index.saturating_sub(iter.oldest_index())) {
target_value @ Some(_) => target_value,
None => {
iter.next()
}
};
*iter_index = iter_index.saturating_add(1);
target_value
}
}
impl<I, const S: usize> Forkable<I, S>
where
I: Iterator + FusedIterator,
<I as Iterator>::Item: Clone + Copy,
{
#[inline]
pub fn new(target_iterator: I) -> Self {
let iter_index = 0;
let iter = MaybeRc::from(
UnsafeCell::new(
Nucleus::new(target_iterator)
)
);
Self {
iter_index,
iter
}
}
#[inline]
pub fn is_exhausted(&self) -> bool {
let Self {
iter_index,
ref iter
} = self;
let iter = unsafe {
iter
.get()
.as_ref()
.unwrap_unchecked()
};
return *iter_index < iter.oldest_index()
}
#[inline]
pub fn fork(self) -> (Self, Self) {
let iter_index = self.iter_index;
let (i0, i1) = self.iter.make_clone();
(
Self {
iter_index,
iter: i0
},
Self {
iter_index,
iter: i1
}
)
}
}
#[cfg(test)]
mod test {
use super::Forkable;
macro_rules! assert_matches {
($($target_tt:tt)*) => {
assert!(
matches!(
$($target_tt)*
)
)
};
}
#[test]
fn storage_exhaust() {
const INITIAL_VALUE: usize = 0x00;
const STORAGE_SIZE: usize = 0x10;
let f: Forkable<_, STORAGE_SIZE> = Forkable::new((INITIAL_VALUE..).into_iter());
let (mut f0, mut f1) = f.fork();
for target_index in INITIAL_VALUE..STORAGE_SIZE * 2 {
assert_matches!(f0.next(), Some(target_value) if target_value == target_index)
}
for _ in INITIAL_VALUE..STORAGE_SIZE {
assert_matches!(f1.next(), None)
}
}
#[test]
fn iter_race() {
const INITIAL_VALUE: usize = 0x00;
const STORAGE_SIZE: usize = 0x10;
const OVERTAKE_COUNT: usize = STORAGE_SIZE / 2;
let f: Forkable<_, STORAGE_SIZE> = Forkable::new((INITIAL_VALUE..).into_iter());
let (mut f0, mut f1) = f.fork();
for _ in 0..=OVERTAKE_COUNT {
assert!(matches!(f0.next(), Some(_)));
}
for target_index in INITIAL_VALUE..STORAGE_SIZE {
assert_matches!(f1.next(), Some(target_value) if target_value == target_index)
}
}
}