#![doc = include_str!("../README.md")]
#![warn(
missing_docs,
missing_copy_implementations,
missing_debug_implementations,
missing_docs,
rust_2018_idioms
)]
use std::fmt::{Debug, Formatter};
pub struct DynIter<'iter, V> {
iter: Box<dyn Iterator<Item = V> + 'iter>,
}
impl<V> Debug for DynIter<'_, V> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let size_str = match self.iter.size_hint() {
(min, None) => format!("at least {min}",),
(min, Some(max)) if min == max => format!("{min}",),
(min, Some(max)) => format!("between {min} and {max}"),
};
write!(f, "{{ iter: [Iterator with {size_str} elements]}}")
}
}
impl<'iter, V> DynIter<'iter, V> {
pub fn new<I>(iter: I) -> Self
where
I: Iterator<Item = V> + 'iter,
{
Self {
iter: Box::new(iter),
}
}
}
impl<'iter, V> Iterator for DynIter<'iter, V> {
type Item = V;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
fn count(self) -> usize
where
Self: Sized,
{
self.iter.count()
}
}
pub trait IntoDynIterator: Iterator {
#[inline]
fn into_dyn_iter<'iter>(self) -> DynIter<'iter, Self::Item>
where
Self: Sized + 'iter,
{
DynIter::new(self)
}
}
impl<T: ?Sized> IntoDynIterator for T where T: Iterator {}
#[cfg(test)]
mod tests {
use crate::{DynIter, IntoDynIterator as _};
#[test]
fn it_compiles() {
let iter = (0..5).skip(2).filter(|n| *n != 3);
let mut dyn_iter = DynIter::new(iter);
assert_eq!(dyn_iter.size_hint(), (0, Some(3)));
assert_eq!(dyn_iter.next(), Some(2));
assert_eq!(dyn_iter.size_hint(), (0, Some(2)));
assert_eq!(dyn_iter.next(), Some(4));
assert_eq!(dyn_iter.size_hint(), (0, Some(0)));
assert_eq!(dyn_iter.next(), None);
}
#[test]
fn size_hint_count() {
let iter = (0..5).skip(2).filter(|e| *e != 3).into_dyn_iter();
assert_eq!(iter.size_hint(), (0, Some(3)));
assert_eq!(iter.count(), 2);
}
mod debug {
use super::*;
struct SizeHintIterator {
min: usize,
max: Option<usize>,
}
impl Iterator for SizeHintIterator {
type Item = u8;
fn next(&mut self) -> Option<Self::Item> {
unimplemented!()
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.min, self.max)
}
}
#[test]
fn no_max_size_hint() {
let iter = SizeHintIterator { min: 2, max: None };
let dyn_iter = DynIter::new(iter);
let debug_msg = format!("{dyn_iter:?}");
assert_eq!("{ iter: [Iterator with at least 2 elements]}", debug_msg);
}
#[test]
fn equal_min_max_size_hint() {
let iter = SizeHintIterator {
min: 3,
max: Some(3),
};
let dyn_iter = DynIter::new(iter);
let debug_msg = format!("{dyn_iter:?}");
assert_eq!("{ iter: [Iterator with 3 elements]}", debug_msg);
}
#[test]
fn different_min_max_size_hint() {
let iter = SizeHintIterator {
min: 4,
max: Some(5),
};
let dyn_iter = DynIter::new(iter);
let debug_msg = format!("{dyn_iter:?}");
assert_eq!(
"{ iter: [Iterator with between 4 and 5 elements]}",
debug_msg
);
}
}
}