#![warn(missing_docs)]
#![allow(clippy::missing_panics_doc, clippy::module_name_repetitions)]
mod chunked_vec;
use std::{
fmt::{self, Debug},
iter,
ops::{Index, IndexMut},
option,
sync::{Arc, Mutex},
};
use crate::chunked_vec::ChunkedVec;
pub struct LazyList<T, I> {
cached: ChunkedVec<T>,
remaining: Mutex<Option<I>>,
}
pub type LazyListBoxed<'a, T> = LazyList<T, Box<dyn Iterator<Item = T> + Send + 'a>>;
pub type LazyListOwned<T> = LazyListBoxed<'static, T>;
pub struct Iter<'a, T, I> {
list: &'a LazyList<T, I>,
inner: chunked_vec::Iter<'a, T>,
}
pub struct IterMut<'a, T, I> {
list: &'a LazyList<T, I>,
inner: chunked_vec::IterMut<'a, T>,
}
pub struct IntoIter<T, I: Iterator>(
iter::Chain<chunked_vec::IntoIter<T>, iter::Flatten<option::IntoIter<I>>>,
);
impl<T, I> LazyList<T, I> {
pub const fn new(iterator: I) -> LazyList<T, I> {
LazyList {
cached: ChunkedVec::new(),
remaining: Mutex::new(Some(iterator)),
}
}
pub fn num_cached(&self) -> usize {
self.cached.len()
}
}
impl<'a, T: Send + Sync + 'a> LazyListBoxed<'a, T> {
pub fn recursive<F: FnMut(&LazyListBoxed<'a, T>, usize) -> Option<T> + Send + 'a>(
mut f: F,
) -> Arc<LazyListBoxed<'a, T>> {
Arc::new_cyclic(|weak| {
let weak = weak.clone();
LazyList::new((0..).map_while(move |i| f(&weak.upgrade().unwrap(), i))).boxed()
})
}
}
impl<'a, T, I: Iterator<Item = T> + Send + 'a> LazyList<T, I> {
pub fn boxed(self) -> LazyListBoxed<'a, T> {
LazyList {
cached: self.cached,
remaining: Mutex::new(
self.remaining
.into_inner()
.unwrap()
.map(|iter| Box::new(iter) as Box<dyn Iterator<Item = T> + Send + 'a>),
),
}
}
}
impl<T, I: Iterator<Item = T>> Index<usize> for LazyList<T, I> {
type Output = T;
fn index(&self, index: usize) -> &T {
self.get(index).expect("index out of bounds")
}
}
impl<T, I: Iterator<Item = T>> IndexMut<usize> for LazyList<T, I> {
fn index_mut(&mut self, index: usize) -> &mut T {
self.get_mut(index).expect("index out of bounds")
}
}
impl<T, I: Iterator<Item = T>> LazyList<T, I> {
fn ensure_cached(&self, index: usize) {
if self.cached.len() > index {
return;
}
let mut guard = self.remaining.lock().unwrap();
let iter_option: &mut Option<I> = &mut guard;
while self.cached.len() <= index {
let element_option: Option<T> = iter_option.as_mut().and_then(Iterator::next);
if let Some(element) = element_option {
self.cached.push(element);
} else {
*iter_option = None;
break;
}
}
}
pub fn get(&self, index: usize) -> Option<&T> {
self.ensure_cached(index);
if index < self.cached.len() {
unsafe { Some(self.cached.index(index)) }
} else {
None
}
}
pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
self.ensure_cached(index);
if index < self.cached.len() {
unsafe { Some(self.cached.index_mut(index)) }
} else {
None
}
}
pub fn iter(&self) -> Iter<T, I> {
Iter {
list: self,
inner: unsafe { self.cached.iter() },
}
}
pub fn iter_mut(&mut self) -> IterMut<T, I> {
IterMut {
list: self,
inner: unsafe { self.cached.iter_mut() },
}
}
}
impl<T, I: Iterator<Item = T>> IntoIterator for LazyList<T, I> {
type Item = T;
type IntoIter = IntoIter<T, I>;
fn into_iter(self) -> IntoIter<T, I> {
IntoIter(
self.cached
.into_iter()
.chain(self.remaining.into_inner().unwrap().into_iter().flatten()),
)
}
}
impl<'a, T, I: Iterator<Item = T>> IntoIterator for &'a LazyList<T, I> {
type Item = &'a T;
type IntoIter = Iter<'a, T, I>;
fn into_iter(self) -> Iter<'a, T, I> {
self.iter()
}
}
impl<'a, T, I: Iterator<Item = T>> IntoIterator for &'a mut LazyList<T, I> {
type Item = &'a mut T;
type IntoIter = IterMut<'a, T, I>;
fn into_iter(self) -> IterMut<'a, T, I> {
self.iter_mut()
}
}
impl<'a, T, I: Iterator<Item = T>> Iterator for Iter<'a, T, I> {
type Item = &'a T;
fn next(&mut self) -> Option<&'a T> {
self.list.ensure_cached(self.inner.next_index());
self.inner.next()
}
}
impl<'a, T, I: Iterator<Item = T>> Iterator for IterMut<'a, T, I> {
type Item = &'a mut T;
fn next<'b>(&'b mut self) -> Option<&'a mut T> {
self.list.ensure_cached(self.inner.next_index());
self.inner.next()
}
}
impl<T, I: Iterator<Item = T>> Iterator for IntoIter<T, I> {
type Item = T;
fn next(&mut self) -> Option<T> {
self.0.next()
}
}
impl<T: Debug, I> Debug for LazyList<T, I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
struct DebugEllipsis;
impl Debug for DebugEllipsis {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("...")
}
}
let mut debug_list = f.debug_list();
debug_list.entries((0..self.cached.len()).map(|i| unsafe {
self.cached.index(i)
}));
let has_remaining = self.remaining.lock().unwrap().is_some();
if has_remaining {
debug_list.entry(&DebugEllipsis);
}
debug_list.finish()
}
}
pub trait IteratorLazyExt: Iterator + Sized {
fn collect_lazy<T>(self) -> LazyList<T, Self>;
}
impl<I: Iterator + Sized> IteratorLazyExt for I {
fn collect_lazy<T>(self) -> LazyList<T, Self> {
LazyList::new(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::{iter, sync::atomic::AtomicUsize};
#[test]
fn test_indexing_infinite() {
let mut list = LazyList::new(0..);
for i in 0..100 {
assert_eq!(list[i], i);
}
for i in 0..100 {
assert_eq!(list[i], i);
}
for i in 0..200 {
list[i] = 10 * i;
}
for i in 0..200 {
assert_eq!(list[i], 10 * i);
}
}
#[test]
fn test_indexing_finite() {
let mut list = LazyList::new(0..200);
for i in 0..100 {
assert_eq!(list[i], i);
}
for i in 0..100 {
assert_eq!(list[i], i);
}
for i in 0..200 {
list[i] = 10 * i;
}
for i in 0..200 {
assert_eq!(list[i], 10 * i);
}
for i in 200..300 {
assert_eq!(list.get(i), None);
}
}
#[test]
fn test_boxed() {
let list: LazyListBoxed<'_, _> = LazyList::new(0..100).boxed();
for i in 0..100 {
assert_eq!(list[i], i);
}
for i in 100..200 {
assert_eq!(list.get(i), None);
}
}
#[test]
fn test_iter_infinite() {
let list = LazyList::new(0..);
let mut iter = list.iter();
for i in 0..100 {
assert_eq!(iter.next(), Some(&(i)));
}
let mut iter2 = list.iter();
for i in 0..200 {
assert_eq!(iter2.next(), Some(&(i)));
}
for i in 0..200 {
assert_eq!(iter.next(), Some(&(i + 100)));
}
}
#[test]
fn test_iter_finite() {
let list = LazyList::new(0..300);
let mut iter = list.iter();
for i in 0..100 {
assert_eq!(iter.next(), Some(&(i)));
}
let mut iter2 = list.iter();
for i in 0..200 {
assert_eq!(iter2.next(), Some(&(i)));
}
for i in 0..200 {
assert_eq!(iter.next(), Some(&(i + 100)));
}
assert_eq!(iter.next(), None);
for _ in 0..100 {
let _ = iter.next();
}
}
#[test]
fn test_iter_mut() {
let mut list = LazyList::new(0..);
let mut iter = list.iter_mut();
for i in 0..100 {
let element_ref = iter.next().unwrap();
assert_eq!(element_ref, &i);
*element_ref += 1000;
}
let mut iter2 = list.iter_mut();
for i in 0..100 {
assert_eq!(iter2.next(), Some(&mut (i + 1000)));
}
for i in 0..100 {
assert_eq!(iter2.next(), Some(&mut (i + 100)));
}
}
#[test]
fn test_into_iter_infinite() {
struct DropCounter<'a>(&'a AtomicUsize, usize);
impl Drop for DropCounter<'_> {
fn drop(&mut self) {
self.0.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
}
}
let drop_counter = AtomicUsize::new(0);
let drop_counter_ref = &drop_counter;
let mut x = 0;
let list = LazyList::new(iter::repeat_with(move || {
let result = x;
x += 1;
DropCounter(drop_counter_ref, result)
}));
let mut iter = list.iter();
for _ in 0..200 {
iter.next();
}
assert_eq!(drop_counter.load(std::sync::atomic::Ordering::Relaxed), 0);
let mut into_iter = list.into_iter();
for i in 0..100 {
assert_eq!(into_iter.next().map(|x| x.1), Some(i));
}
assert_eq!(drop_counter.load(std::sync::atomic::Ordering::Relaxed), 100);
println!("dropping");
drop(into_iter);
assert_eq!(drop_counter.load(std::sync::atomic::Ordering::Relaxed), 200);
}
#[test]
fn test_debug() {
let list = LazyList::new(0..);
assert_eq!(format!("{:?}", list), "[...]");
list[9];
assert_eq!(format!("{:?}", list), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...]");
let list2 = LazyList::new(0..10);
assert_eq!(format!("{:?}", list2), "[...]");
list2[9];
assert_eq!(
format!("{:?}", list2),
"[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...]"
);
list2.get(10);
assert_eq!(format!("{:?}", list2), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
}
#[test]
fn test_recursive() {
let evens =
LazyList::recursive(|evens_ref, i| Some(if i == 0 { 0 } else { evens_ref[i - 1] + 2 }));
assert_eq!(
evens.iter().copied().take(10).collect::<Vec<_>>(),
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
);
}
}