bulks 0.11.3

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

use array_trait::{AsArray, length};

use crate::{Bulk, DoubleEndedBulk, IntoBulk, IntoContained, StaticBulk};

/// A bulk that flattens one level of nesting in a of things
/// that can be turned into bulks.
///
/// This `struct` is created by the [`flatten`](Bulk::flatten) method on [`Bulk`]. See its
/// documentation for more.
#[must_use = "bulks are lazy and do nothing unless consumed"]
#[derive(Clone, Debug)]
pub struct Flatten<I>
where
    I: Bulk<Item: IntoBulk<IntoBulk: StaticBulk>>
{
    bulk: I
}

impl<I> Flatten<I>
where
    I: Bulk<Item: IntoBulk<IntoBulk: StaticBulk>>
{
    pub(crate) const fn new(bulk: I) -> Self
    {
        Self { bulk }
    }

    const fn chunk() -> usize
    {
        <<<I::Item as IntoBulk>::IntoBulk as StaticBulk>::Array<<I::Item as IntoIterator>::Item> as AsArray>::LENGTH
    }
}

const impl<I> IntoIterator for Flatten<I>
where
    I: Bulk<Item: IntoBulk<IntoBulk: StaticBulk>> + [const] IntoIterator<IntoIter: [const] Iterator>,
    core::iter::Flatten<I::IntoIter>: [const] IntoContained<IntoContained: [const] IntoIterator>
{
    type IntoIter = <<core::iter::Flatten<I::IntoIter> as IntoContained>::IntoContained as IntoIterator>::IntoIter;
    type Item = <<core::iter::Flatten<I::IntoIter> as IntoContained>::IntoContained as IntoIterator>::Item;

    fn into_iter(self) -> Self::IntoIter
    {
        let Self { bulk } = self;
        unsafe { bulk.into_iter().flatten().into_contained().into_iter() }
    }
}
const impl<I> Bulk for Flatten<I>
where
    I: [const] Bulk<Item: [const] IntoBulk<IntoBulk: [const] Bulk + StaticBulk> + [const] Destruct>
{
    type MaxLength = length::Mul<I::MaxLength, <<I::Item as IntoBulk>::IntoBulk as StaticBulk>::Array<()>>;
    type MinLength = length::Mul<I::MinLength, <<I::Item as IntoBulk>::IntoBulk as StaticBulk>::Array<()>>;

    fn len(&self) -> usize
    {
        let Self { bulk } = self;
        bulk.len() * Self::chunk()
    }

    fn is_empty(&self) -> bool
    {
        let Self { bulk } = self;
        Self::chunk() == 0 || bulk.is_empty()
    }

    fn first(self) -> Option<Self::Item>
    where
        Self::Item: [const] Destruct,
        Self: Sized
    {
        const fn into_first<T>(x: T) -> Option<T::Item>
        where
            T: [const] IntoBulk<Item: [const] Destruct>
        {
            x.into_bulk().first()
        }

        let Self { bulk } = self;
        bulk.first().and_then(into_first)
    }

    fn for_each<F>(self, f: F)
    where
        Self: Sized,
        F: [const] FnMut(Self::Item) + [const] Destruct
    {
        struct Closure<F>
        {
            f: F
        }
        const impl<F, T> FnOnce<(T,)> for Closure<F>
        where
            T: [const] IntoBulk<IntoBulk: StaticBulk + [const] Bulk>,
            F: [const] FnMut(T::Item) + [const] Destruct
        {
            type Output = ();

            extern "rust-call" fn call_once(self, (x,): (T,)) -> Self::Output
            {
                x.into_bulk().for_each(self.f)
            }
        }
        const impl<F, T> FnMut<(T,)> for Closure<F>
        where
            T: [const] IntoBulk<IntoBulk: StaticBulk + [const] Bulk>,
            F: [const] FnMut(T::Item) + [const] Destruct
        {
            extern "rust-call" fn call_mut(&mut self, (x,): (T,)) -> Self::Output
            {
                x.into_bulk().for_each(&mut self.f)
            }
        }

        let Self { bulk } = self;
        bulk.for_each(Closure { f })
    }

    fn try_for_each<F, R>(self, f: F) -> R
    where
        Self: Sized,
        Self::Item: [const] Destruct,
        F: [const] FnMut(Self::Item) -> R + [const] Destruct,
        R: [const] Try<Output = ()>
    {
        struct Closure<F>
        {
            f: F
        }
        const impl<F, T, R> FnOnce<(T,)> for Closure<F>
        where
            T: [const] IntoBulk<IntoBulk: StaticBulk + [const] Bulk, Item: [const] Destruct>,
            F: [const] FnMut(T::Item) -> R + [const] Destruct,
            R: [const] Try<Output = ()>
        {
            type Output = R;

            extern "rust-call" fn call_once(self, (x,): (T,)) -> Self::Output
            {
                x.into_bulk().try_for_each(self.f)
            }
        }
        const impl<F, T, R> FnMut<(T,)> for Closure<F>
        where
            T: [const] IntoBulk<IntoBulk: StaticBulk + [const] Bulk, Item: [const] Destruct>,
            F: [const] FnMut(T::Item) -> R + [const] Destruct,
            R: [const] Try<Output = ()>
        {
            extern "rust-call" fn call_mut(&mut self, (x,): (T,)) -> Self::Output
            {
                x.into_bulk().try_for_each(&mut self.f)
            }
        }

        let Self { bulk } = self;
        bulk.try_for_each(Closure { f })
    }
}
const impl<I> DoubleEndedBulk for Flatten<I>
where
    I: [const] DoubleEndedBulk<Item: [const] IntoBulk<IntoBulk: [const] DoubleEndedBulk + StaticBulk> + [const] Destruct>,
    Self::IntoIter: DoubleEndedIterator
{
    fn rev_for_each<F>(self, f: F)
    where
        Self: Sized,
        F: [const] FnMut(Self::Item) + [const] Destruct
    {
        struct Closure<F>
        {
            f: F
        }
        const impl<F, T> FnOnce<(T,)> for Closure<F>
        where
            T: [const] IntoBulk<IntoBulk: StaticBulk + [const] DoubleEndedBulk>,
            F: [const] FnMut(T::Item) + [const] Destruct
        {
            type Output = ();

            extern "rust-call" fn call_once(self, (x,): (T,)) -> Self::Output
            {
                x.into_bulk().rev_for_each(self.f)
            }
        }
        const impl<F, T> FnMut<(T,)> for Closure<F>
        where
            T: [const] IntoBulk<IntoBulk: StaticBulk + [const] DoubleEndedBulk>,
            F: [const] FnMut(T::Item) + [const] Destruct
        {
            extern "rust-call" fn call_mut(&mut self, (x,): (T,)) -> Self::Output
            {
                x.into_bulk().rev_for_each(&mut self.f)
            }
        }

        let Self { bulk } = self;
        bulk.rev_for_each(Closure { f })
    }

    fn try_rev_for_each<F, R>(self, f: F) -> R
    where
        Self: Sized,
        Self::Item: [const] Destruct,
        F: [const] FnMut(Self::Item) -> R + [const] Destruct,
        R: [const] Try<Output = ()>
    {
        struct Closure<F>
        {
            f: F
        }
        const impl<F, T, R> FnOnce<(T,)> for Closure<F>
        where
            T: [const] IntoBulk<IntoBulk: StaticBulk + [const] DoubleEndedBulk, Item: [const] Destruct>,
            F: [const] FnMut(T::Item) -> R + [const] Destruct,
            R: [const] Try<Output = ()>
        {
            type Output = R;

            extern "rust-call" fn call_once(self, (x,): (T,)) -> Self::Output
            {
                x.into_bulk().try_rev_for_each(self.f)
            }
        }
        const impl<F, T, R> FnMut<(T,)> for Closure<F>
        where
            T: [const] IntoBulk<IntoBulk: StaticBulk + [const] DoubleEndedBulk, Item: [const] Destruct>,
            F: [const] FnMut(T::Item) -> R + [const] Destruct,
            R: [const] Try<Output = ()>
        {
            extern "rust-call" fn call_mut(&mut self, (x,): (T,)) -> Self::Output
            {
                x.into_bulk().try_rev_for_each(&mut self.f)
            }
        }

        let Self { bulk } = self;
        bulk.try_rev_for_each(Closure { f })
    }
}

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

    #[test]
    fn it_works()
    {
        let a = [[1, -1], [2, -2], [3, -3]];
        let b = a.into_bulk().flatten().collect_array();

        println!("{b:?}")
    }
}