bulks 0.11.3

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

use array_trait::length::LengthValue;

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

/// Creates a bulk that yields nothing.
///
/// Similar to [`core::iter::empty`].
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// use bulks::*;
///
/// let mut nope = bulks::empty::<i32>();
///
/// let nothing: [_; _] = nope.collect();
///
/// assert_eq!(nothing, []);
/// ```
pub const fn empty<T>() -> Empty<T>
{
    Empty(PhantomData)
}

/// A bulk that yields nothing.
///
/// This `struct` is created by the [`empty()`] function. See its documentation for more.
#[must_use = "bulks are lazy and do nothing unless consumed"]
pub struct Empty<T>(PhantomData<T>);

const impl<T> Clone for Empty<T>
{
    fn clone(&self) -> Self
    {
        Self(PhantomData)
    }
}

impl<T> fmt::Debug for Empty<T>
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
    {
        f.debug_struct("Empty").finish()
    }
}

const impl<T> IntoIterator for Empty<T>
{
    type IntoIter = core::iter::Empty<T>;
    type Item = T;

    fn into_iter(self) -> Self::IntoIter
    {
        core::iter::empty()
    }
}
const impl<T> IntoBulk for core::iter::Empty<T>
{
    type IntoBulk = Empty<T>;

    fn into_bulk(self) -> Self::IntoBulk
    {
        empty()
    }
}
const impl<T> Bulk for Empty<T>
{
    type MaxLength = [(); 0];
    type MinLength = [(); 0];

    fn len(&self) -> usize
    {
        0
    }

    fn is_empty(&self) -> bool
    {
        true
    }

    fn first(self) -> Option<Self::Item>
    where
        Self::Item: [const] Destruct,
        Self: Sized
    {
        None
    }

    fn last(self) -> Option<Self::Item>
    where
        Self::Item: [const] Destruct,
        Self: Sized
    {
        None
    }

    fn nth<L>(self, _n: L) -> Option<Self::Item>
    where
        Self: Sized,
        Self::Item: [const] Destruct,
        L: LengthValue
    {
        None
    }

    fn for_each<F>(self, f: F)
    where
        Self: Sized,
        F: [const] FnMut(Self::Item) + [const] Destruct
    {
        let _ = f;
    }

    fn try_for_each<F, R>(self, f: F) -> R
    where
        Self: Sized,
        F: [const] FnMut(Self::Item) -> R + [const] Destruct,
        R: [const] core::ops::Try<Output = ()>
    {
        let _ = f;
        R::from_output(())
    }
}
const impl<T> DoubleEndedBulk for Empty<T>
{
    fn rev_for_each<F>(self, f: F)
    where
        Self: Sized,
        F: [const] FnMut(Self::Item) + [const] Destruct
    {
        let _ = f;
    }

    fn try_rev_for_each<F, R>(self, f: F) -> R
    where
        Self: Sized,
        F: [const] FnMut(Self::Item) -> R + [const] Destruct,
        R: [const] core::ops::Try<Output = ()>
    {
        let _ = f;
        R::from_output(())
    }
}
const impl<T, L> SplitBulk<L> for Empty<T>
where
    L: LengthValue
{
    type Left = Self;
    type Right = Self;

    fn split_at(bulk: Self, _n: L) -> (Self::Left, Self::Right)
    where
        Self: Sized
    {
        (bulk.clone(), bulk)
    }
}

pub const trait EmptyBulk: [const] DoubleEndedBulk + StaticBulk<Array<()> = [(); 0]> {}
const impl<T> EmptyBulk for T where T: [const] DoubleEndedBulk + StaticBulk<Array<()> = [(); 0]> {}

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

    #[test]
    fn it_works()
    {
        let a = const { crate::empty::<u8>().collect_array() };
        assert_eq!(a, [])
    }
}