use core::iter::FusedIterator;
pub struct Bidi<I>
where I: DoubleEndedIterator
{
inner: I,
next: fn(&mut I) -> Option<<I as Iterator>::Item>,
next_back: fn(&mut I) -> Option<<I as Iterator>::Item>,
nth: fn(&mut I, usize) -> Option<<I as Iterator>::Item>,
nth_back: fn(&mut I, usize) -> Option<<I as Iterator>::Item>,
}
impl<I> Bidi<I>
where I: DoubleEndedIterator
{
pub fn new<II>(iter: II, cond: bool) -> Self
where II: IntoIterator<IntoIter = I> {
let inner = iter.into_iter();
if cond {
Self {
inner,
next: <I as DoubleEndedIterator>::next_back,
next_back: <I as Iterator>::next,
nth: <I as DoubleEndedIterator>::nth_back,
nth_back: <I as Iterator>::nth,
}
}
else {
Self {
inner,
next: <I as Iterator>::next,
next_back: <I as DoubleEndedIterator>::next_back,
nth: <I as Iterator>::nth,
nth_back: <I as DoubleEndedIterator>::nth_back,
}
}
}
}
impl<I> Iterator for Bidi<I>
where I: DoubleEndedIterator
{
type Item = <I as Iterator>::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
(&mut self.next)(&mut self.inner)
}
#[inline]
fn nth(&mut self, n: usize) -> Option<Self::Item> {
(&mut self.nth)(&mut self.inner, n)
}
#[inline]
#[cfg(not(tarpaulin_include))]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
#[inline]
#[cfg(not(tarpaulin_include))]
fn count(self) -> usize {
self.inner.count()
}
#[inline]
#[cfg(not(tarpaulin_include))]
fn last(mut self) -> Option<Self::Item> {
self.next_back()
}
}
impl<I> DoubleEndedIterator for Bidi<I>
where I: DoubleEndedIterator
{
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
(&mut self.next_back)(&mut self.inner)
}
#[inline]
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
(&mut self.nth_back)(&mut self.inner, n)
}
}
impl<I> ExactSizeIterator for Bidi<I>
where I: DoubleEndedIterator + ExactSizeIterator
{
#[inline]
#[cfg(not(tarpaulin_include))]
fn len(&self) -> usize {
self.inner.len()
}
}
impl<I> FusedIterator for Bidi<I> where I: DoubleEndedIterator + FusedIterator
{
}
pub trait BidiIterator
where
Self: Sized + IntoIterator,
<Self as IntoIterator>::IntoIter: DoubleEndedIterator,
{
fn bidi(self, cond: bool) -> Bidi<Self::IntoIter> {
Bidi::new(self, cond)
}
}
impl<I> BidiIterator for I
where
I: Sized + IntoIterator,
<I as IntoIterator>::IntoIter: DoubleEndedIterator,
{
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn forward() {
let mut iter = (0 .. 6).bidi(false);
assert_eq!(iter.next(), Some(0));
assert_eq!(iter.next_back(), Some(5));
assert_eq!(iter.nth(1), Some(2));
assert_eq!(iter.nth_back(1), Some(3));
assert!(iter.next().is_none());
}
#[test]
fn reverse() {
let mut iter = (0 .. 6).bidi(true);
assert_eq!(iter.next(), Some(5));
assert_eq!(iter.next_back(), Some(0));
assert_eq!(iter.nth(1), Some(3));
assert_eq!(iter.nth_back(1), Some(2));
assert!(iter.next().is_none());
}
}