use core::{fmt, marker::Destruct, ptr::Pointee};
use array_trait::length::{self, Length, LengthValue};
use crate::{Bulk, DoubleEndedBulk, SplitBulk};
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)
}
}
#[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])
}
}