use core::{marker::Destruct, ptr::Pointee};
use array_trait::length::{self, Length, LengthValue};
use crate::{Bulk, DoubleEndedBulk, SplitBulk};
#[derive(Clone, Debug)]
#[must_use = "bulks are lazy and do nothing unless consumed"]
pub struct Rev<I>
where
I: DoubleEndedBulk
{
bulk: I,
}
impl<I> Rev<I>
where
I: DoubleEndedBulk
{
pub(crate) const fn new(bulk: I) -> Self
{
Self {
bulk
}
}
pub const fn into_inner(self) -> I
{
let Self { bulk } = self;
bulk
}
}
impl<I> const Default for Rev<I>
where
I: ~const Bulk + DoubleEndedBulk + ~const Default
{
fn default() -> Self
{
I::default().rev()
}
}
impl<I> IntoIterator for Rev<I>
where
I: DoubleEndedBulk
{
type IntoIter = core::iter::Rev<I::IntoIter>;
type Item = I::Item;
fn into_iter(self) -> Self::IntoIter
{
self.into_inner().into_iter().rev()
}
}
impl<I> const Bulk for Rev<I>
where
I: ~const Bulk + ~const DoubleEndedBulk
{
type MinLength = I::MinLength;
type MaxLength = I::MaxLength;
fn len(&self) -> usize
{
let Self { bulk } = self;
bulk.len()
}
fn is_empty(&self) -> bool
{
let Self { bulk } = self;
bulk.is_empty()
}
fn for_each<F>(self, f: F)
where
Self: Sized,
F: ~const FnMut(Self::Item) + ~const Destruct
{
let Self { bulk } = self;
bulk.rev_for_each(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 core::ops::Try<Output = (), Residual: ~const Destruct>
{
let Self { bulk } = self;
bulk.try_rev_for_each(f)
}
}
impl<I> const DoubleEndedBulk for Rev<I>
where
I: ~const Bulk + ~const DoubleEndedBulk
{
fn rev_for_each<F>(self, f: F)
where
Self: Sized,
F: ~const FnMut(Self::Item) + ~const Destruct
{
let Self { bulk } = self;
bulk.for_each(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 core::ops::Try<Output = (), Residual: ~const Destruct>
{
let Self { bulk } = self;
bulk.try_for_each(f)
}
}
impl<I, N, L, R> const SplitBulk<L> for Rev<I>
where
I: ~const SplitBulk<R, Left: ~const Bulk + DoubleEndedBulk, Right: ~const Bulk + DoubleEndedBulk> + ~const Bulk<Length: Length<Value = N> + Pointee<Metadata = N::Metadata>> + ~const DoubleEndedBulk,
N: LengthValue<SaturatingSub<L> = R>,
L: LengthValue,
R: LengthValue
{
type Left = Rev<I::Right>;
type Right = Rev<I::Left>;
fn split_at(Self { bulk }: Self, m: L) -> (Self::Left, Self::Right)
where
Self: Sized
{
let n = bulk.length();
let (left, right) = bulk.split_at(length::value::saturating_sub(n, m));
(
right.rev(),
left.rev()
)
}
}
#[cfg(test)]
mod test
{
use crate::*;
#[test]
fn it_works()
{
let a = [1, 2, 3, 4, 5, 6];
let b = a.into_bulk()
.rev()
.map(|x| 7 - x)
.collect_array();
assert_eq!(a, b)
}
}