asynciter 0.1.0

Asynchronous iterator.
Documentation
use std::{future::Future, fmt::Debug};

use super::peekable::Peekable;
use crate::AsyncIterator;

#[must_use = "iterators are lazy and do nothing unless consumed"]
#[derive(Debug, Clone)]
pub struct Intersperse<I: AsyncIterator>
where
    I::Item: Clone,
{
    separator: I::Item,
    iter: Peekable<I>,
    needs_sep: bool,
}

impl<I: AsyncIterator> Intersperse<I>
where
    I::Item: Clone,
{
    pub fn new(iter: I, separator: I::Item) -> Self {
        Self {
            iter: iter.peekable(),
            separator,
            needs_sep: false,
        }
    }
}

impl<I> AsyncIterator for Intersperse<I>
where
    I: AsyncIterator,
    I::Item: Clone,
{
    type Item = I::Item;

    #[inline]
    async fn next(&mut self) -> Option<I::Item> {
        if self.needs_sep && self.iter.peek().await.is_some() {
            self.needs_sep = false;
            Some(self.separator.clone())
        } else {
            self.needs_sep = true;
            self.iter.next().await
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        intersperse_size_hint(&self.iter, self.needs_sep)
    }
}

#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct IntersperseWith<I, G>
where
    I: AsyncIterator,
{
    separator: G,
    iter: Peekable<I>,
    needs_sep: bool,
}

impl<I: AsyncIterator + Debug, G> Debug for IntersperseWith<I, G>
where
    I::Item: Debug
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("IntersperseWith")
            .field("needs_sep", &self.needs_sep)
            .field("iter", &self.iter)
            .finish()
    }
}

impl<I: AsyncIterator + Clone, G: Clone> std::clone::Clone for IntersperseWith<I, G>
where
    I::Item: Clone,
{
    fn clone(&self) -> Self {
        Self {
            separator: self.separator.clone(),
            iter: self.iter.clone(),
            needs_sep: self.needs_sep,
        }
    }

    fn clone_from(&mut self, source: &Self) {
        self.separator = source.separator.clone();
        self.iter = source.iter.clone();
        self.needs_sep = source.needs_sep;
    }
}

impl<I, G> IntersperseWith<I, G>
where
    I: AsyncIterator,
    G: FnMut() -> I::Item,
{
    pub fn new(iter: I, separator: G) -> Self {
        Self {
            iter: iter.peekable(),
            separator,
            needs_sep: false,
        }
    }
}

impl<I, G> AsyncIterator for IntersperseWith<I, G>
where
    I: AsyncIterator,
    G: FnMut() -> I::Item,
{
    type Item = I::Item;

    #[inline]
    async fn next(&mut self) -> Option<I::Item> {
        if self.needs_sep && self.iter.peek().await.is_some() {
            self.needs_sep = false;
            Some((self.separator)())
        } else {
            self.needs_sep = true;
            self.iter.next().await
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        intersperse_size_hint(&self.iter, self.needs_sep)
    }
}

#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct AsyncIntersperseWith<I, G>
where
    I: AsyncIterator,
{
    separator: G,
    iter: Peekable<I>,
    needs_sep: bool,
}

impl<I: AsyncIterator + Debug, G> Debug for AsyncIntersperseWith<I, G>
where
    I::Item: Debug
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("IntersperseWith")
            .field("needs_sep", &self.needs_sep)
            .field("iter", &self.iter)
            .finish()
    }
}

impl<I: AsyncIterator + Clone, G: Clone> std::clone::Clone for AsyncIntersperseWith<I, G>
where
    I::Item: Clone,
{
    fn clone(&self) -> Self {
        Self {
            separator: self.separator.clone(),
            iter: self.iter.clone(),
            needs_sep: self.needs_sep,
        }
    }

    fn clone_from(&mut self, source: &Self) {
        self.separator = source.separator.clone();
        self.iter = source.iter.clone();
        self.needs_sep = source.needs_sep;
    }
}

impl<I, G, F> AsyncIntersperseWith<I, G>
where
    I: AsyncIterator,
    G: FnMut() -> F,
    F: Future<Output = I::Item>,
{
    pub fn new(iter: I, separator: G) -> Self {
        Self {
            iter: iter.peekable(),
            separator,
            needs_sep: false,
        }
    }
}

impl<I, G, F> AsyncIterator for AsyncIntersperseWith<I, G>
where
    I: AsyncIterator,
    G: FnMut() -> F,
    F: Future<Output = I::Item>,
{
    type Item = I::Item;

    #[inline]
    async fn next(&mut self) -> Option<I::Item> {
        if self.needs_sep && self.iter.peek().await.is_some() {
            self.needs_sep = false;
            Some((self.separator)().await)
        } else {
            self.needs_sep = true;
            self.iter.next().await
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        intersperse_size_hint(&self.iter, self.needs_sep)
    }
}

#[inline]
fn intersperse_size_hint<I>(iter: &I, needs_sep: bool) -> (usize, Option<usize>)
where
    I: AsyncIterator,
{
    let (lo, hi) = iter.size_hint();
    let next_is_elem = !needs_sep;
    (
        lo.saturating_sub(next_is_elem as usize).saturating_add(lo),
        hi.and_then(|hi| hi.saturating_sub(next_is_elem as usize).checked_add(hi)),
    )
}