use core::{
iter::FusedIterator,
ops::{Not, RangeBounds},
};
use fluent_result::bool::Then;
#[cfg(doc)]
use crate::*;
use crate::{InvalidSizeHint, SizeHint};
#[derive(Debug, Clone)]
#[readonly::make]
pub struct ExactLen<I: FusedIterator> {
pub iterator: I,
pub len: usize,
}
impl<I: FusedIterator> ExactLen<I> {
#[inline]
pub fn new(iterator: impl IntoIterator<IntoIter = I>, len: usize) -> Self {
Self::try_new(iterator, len).expect("len should be within the wrapped iterator's size hint bounds")
}
#[inline]
pub fn try_new(iterator: impl IntoIterator<IntoIter = I>, len: usize) -> Result<Self, InvalidSizeHint> {
let iterator = iterator.into_iter();
let wrapped: SizeHint = iterator.size_hint().try_into().expect("wrapped iterator size_hint should be valid");
wrapped.contains(&len).not().then_err(InvalidSizeHint)?;
Ok(Self { iterator, len })
}
#[inline]
pub fn into_inner(self) -> I {
self.iterator
}
}
impl<I: FusedIterator> Iterator for ExactLen<I> {
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.len = self.len.saturating_sub(1);
self.iterator.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
SizeHint::exact(self.len).into()
}
}
impl<I: FusedIterator> ExactSizeIterator for ExactLen<I> {
#[inline]
fn len(&self) -> usize {
self.len
}
}
impl<I: DoubleEndedIterator + FusedIterator> DoubleEndedIterator for ExactLen<I> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.len = self.len.saturating_sub(1);
self.iterator.next_back()
}
}
impl<I: FusedIterator> FusedIterator for ExactLen<I> {}