bulks 0.7.2

Amazing bulks! They are like iterators, but in bulk, and therefore support collection into arrays.
use core::{fmt, marker::Destruct, ptr::Pointee};

use array_trait::length::{self, Length, LengthValue};

use crate::{Bulk, DoubleEndedBulk, SplitBulk};

/// Creates a new bulk that repeats elements of type `A` a given number of times
/// applying the provided closure, the repeater, `F: FnMut() -> A`.
///
/// The `repeat_n_with()` function calls the repeater a set amount of times.
///
/// If the element type of the iterator you need implements [`Clone`], and
/// it is OK to keep the source element in memory, you should instead use
/// the [`repeat_n()`](crate::repeat_n) function.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// use bulks::*;
///
/// // let's assume we have some value of a type that is not `Clone`
/// // or which we don't want to have in memory just yet because it is expensive:
/// #[derive(PartialEq, Debug)]
/// struct Expensive;
///
/// // a particular value forever:
/// let mut things: [_; _] = bulks::repeat_n_with(|| Expensive, [(); 4]).collect();
///
/// assert_eq!(things, [Expensive, Expensive, Expensive, Expensive])
/// ```
pub const fn repeat_n_with<G, L>(repeater: G, n: L) -> RepeatNWith<G, L::Length<()>>
where
    G: FnMut<()>,
    L: LengthValue
{
    RepeatNWith {
        repeater,
        n: length::value::into_metadata(n)
    }
}

/// A bulk that repeats elements of type `A` an exact number of times by
/// applying the provided closure `F: FnMut() -> A`.
///
/// This `struct` is created by the [`repeat_n_with()`] function.
/// See its documentation for more.
#[must_use = "bulks are lazy and do nothing unless consumed"]
#[derive(Clone)]
pub struct RepeatNWith<G, N = [()]>
where
    G: FnMut<()>,
    N: Length<Elem = ()> + ?Sized
{
    repeater: G,
    n: <N as Pointee>::Metadata
}

impl<A, G, N> fmt::Debug for RepeatNWith<G, N>
where
    G: FnMut() -> A,
    N: Length<Elem = ()> + ?Sized
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
    {
        f.debug_struct("RepeatNWith").field("count", &self.len()).finish()
    }
}

impl<A, G, N> IntoIterator for RepeatNWith<G, N>
where
    G: FnMut() -> A,
    N: Length<Elem = ()> + ?Sized
{
    type Item = A;
    type IntoIter = core::iter::Take<core::iter::RepeatWith<G>>;

    fn into_iter(self) -> Self::IntoIter
    {
        let Self { repeater, n } = self;
        core::iter::repeat_with(repeater).take(length::value::len_metadata::<N::Value>(n))
    }
}
impl<A, G, N> const Bulk for RepeatNWith<G, N>
where
    G: ~const FnMut() -> A + ~const Destruct,
    N: Length<Elem = ()> + ?Sized
{
    type MinLength = N;
    type MaxLength = N;

    fn len(&self) -> usize
    {
        let Self { repeater: _, n } = self;
        length::value::len_metadata::<N::Value>(*n)
    }

    fn for_each<F>(self, mut f: F)
    where
        Self: Sized,
        F: ~const FnMut(Self::Item) + ~const Destruct
    {
        let Self { mut repeater, n } = self;
        let n = length::value::len_metadata::<N::Value>(n);
        let mut i = 0;
        while i < n
        {
            f(repeater());
            i += 1
        }
    }
    fn try_for_each<F, R>(self, mut f: F) -> R
    where
        Self: Sized,
        F: ~const FnMut(Self::Item) -> R + ~const Destruct,
        R: ~const core::ops::Try<Output = (), Residual: ~const Destruct>
    {
        let Self { mut repeater, n } = self;
        let n = length::value::len_metadata::<N::Value>(n);
        let mut i = 0;
        while i < n
        {
            f(repeater())?;
            i += 1
        }
        R::from_output(())
    }
}
impl<A, G, N> const DoubleEndedBulk for RepeatNWith<G, N>
where
    G: ~const FnMut() -> A + ~const Destruct,
    N: Length<Elem = ()> + ?Sized,
    Self::IntoIter: DoubleEndedIterator
{
    fn rev_for_each<F>(self, f: F)
    where
        Self: Sized,
        F: ~const FnMut(Self::Item) + ~const Destruct
    {
        self.for_each(f)
    }
    fn try_rev_for_each<F, R>(self, f: F) -> R
    where
        Self: Sized,
        A: ~const Destruct,
        F: ~const FnMut(Self::Item) -> R + ~const Destruct,
        R: ~const core::ops::Try<Output = (), Residual: ~const Destruct>
    {
        self.try_for_each(f)
    }
}
impl<A, G, N, M, L, R, NN> const SplitBulk<M> for RepeatNWith<G, N>
where
    N: Length<Elem = (), Value = NN>,
    NN: LengthValue<Min<M> = L, SaturatingSub<M> = R, Metadata = N::Metadata>,
    G: ~const FnMut() -> A + ~const Clone + ~const Destruct,
    M: LengthValue,
    L: LengthValue,
    R: LengthValue
{
    type Left = RepeatNWith<G, L::Length<()>>;
    type Right = RepeatNWith<G, R::Length<()>>;

    fn split_at(Self { repeater, n }: Self, m: M) -> (Self::Left, Self::Right)
    where
        Self: Sized
    {
        let n = NN::from_metadata(n);
        (
            repeat_n_with(repeater.clone(), length::value::min(n, m)),
            repeat_n_with(repeater, length::value::saturating_sub(n, m))
        )
    }
}

#[cfg(test)]
mod test
{
    use crate::Bulk;

    #[test]
    fn it_works()
    {
        let mut i = 0;
        let a = crate::repeat_n_with(|| {i += 1; i}, [(); _])
            .collect_array();
        assert_eq!(a, [1, 2, 3, 4])
    }
}