use core::{marker::Destruct, ops::Try};
use crate::{ArrayChunks, Bulk, util::ArrayBuffer};
#[must_use = "bulks are lazy and do nothing unless consumed"]
pub struct ArrayChunksWithRemainder<'a, I, const N: usize, const REV: bool>
where
I: Bulk
{
bulk: ArrayChunks<I, N>,
remainder: &'a mut ArrayBuffer<I::Item, N, REV>
}
impl<'a, I, const N: usize, const REV: bool> ArrayChunksWithRemainder<'a, I, N, REV>
where
I: Bulk
{
#[track_caller]
pub(crate) const fn new(bulk: I, remainder: &'a mut ArrayBuffer<I::Item, N, REV>) -> Self
{
Self {
bulk: ArrayChunks::new(bulk),
remainder
}
}
const fn skip_len(&self) -> usize
where
I: [const] Bulk
{
let Self { bulk, remainder: _ } = self;
bulk.skip_len::<REV>()
}
const fn for_each_closure<F>(self, f: F) -> (I, impl [const] FnMut(I::Item) + [const] Destruct + 'a)
where
Self: Sized,
I: [const] Bulk<Item: [const] Destruct>,
F: [const] FnMut(<Self as IntoIterator>::Item) + [const] Destruct + 'a
{
struct Closure<'a, T, F, const N: usize, const REV: bool>
where
F: FnMut([T; N])
{
f: F,
buffer: &'a mut ArrayBuffer<T, N, REV>,
skip: usize
}
const impl<'a, T, F, const N: usize, const REV: bool> FnOnce<(T,)> for Closure<'a, T, F, N, REV>
where
T: [const] Destruct,
F: [const] FnMut([T; N]) + [const] Destruct
{
type Output = ();
extern "rust-call" fn call_once(mut self, args: (T,)) -> Self::Output
{
self.call_mut(args)
}
}
const impl<'a, T, F, const N: usize, const REV: bool> FnMut<(T,)> for Closure<'a, T, F, N, REV>
where
T: [const] Destruct,
F: [const] FnMut([T; N]) + [const] Destruct
{
extern "rust-call" fn call_mut(&mut self, (x,): (T,)) -> Self::Output
{
if self.skip > 0
{
self.skip -= 1
}
else if let Some(array) = self.buffer.push_take_array(x)
{
(self.f)(array)
}
}
}
let skip = self.skip_len();
let Self { bulk, remainder } = self;
(bulk.into_inner(), Closure { f, buffer: remainder, skip })
}
const fn try_for_each_closure<F, R>(self, f: F) -> (I, impl [const] FnMut(I::Item) -> R + [const] Destruct + 'a)
where
Self: Sized,
<Self as IntoIterator>::Item: [const] Destruct,
I: [const] Bulk<Item: [const] Destruct>,
F: [const] FnMut(<Self as IntoIterator>::Item) -> R + [const] Destruct + 'a,
R: [const] Try<Output = ()> + 'a
{
struct Closure<'a, T, F, R, const N: usize, const REV: bool>
where
F: FnMut([T; N]) -> R,
R: Try<Output = ()>
{
f: F,
buffer: &'a mut ArrayBuffer<T, N, REV>,
skip: usize
}
const impl<'a, T, F, R, const N: usize, const REV: bool> FnOnce<(T,)> for Closure<'a, T, F, R, N, REV>
where
T: [const] Destruct,
F: [const] FnMut([T; N]) -> R + [const] Destruct,
R: [const] Try<Output = ()>
{
type Output = R;
extern "rust-call" fn call_once(mut self, args: (T,)) -> Self::Output
{
self.call_mut(args)
}
}
const impl<'a, T, F, R, const N: usize, const REV: bool> FnMut<(T,)> for Closure<'a, T, F, R, N, REV>
where
T: [const] Destruct,
F: [const] FnMut([T; N]) -> R + [const] Destruct,
R: [const] Try<Output = ()>
{
extern "rust-call" fn call_mut(&mut self, (x,): (T,)) -> Self::Output
{
if self.skip > 0
{
self.skip -= 1
}
else if let Some(array) = self.buffer.push_take_array(x)
{
(self.f)(array)?
}
R::from_output(())
}
}
let skip = self.skip_len();
let Self { bulk, remainder } = self;
(bulk.into_inner(), Closure { f, buffer: remainder, skip })
}
}
const impl<'a, I, const N: usize, const REV: bool> IntoIterator for ArrayChunksWithRemainder<'a, I, N, REV>
where
I: Bulk + [const] IntoIterator<IntoIter: [const] Iterator>
{
type IntoIter = iter::ArrayChunksWithRemainder<'a, <I as IntoIterator>::IntoIter, N, REV>;
type Item = <ArrayChunks<I, N> as IntoIterator>::Item;
fn into_iter(self) -> Self::IntoIter
{
let Self { bulk, remainder } = self;
iter::ArrayChunksWithRemainder::new(bulk.into_iter(), remainder)
}
}
const impl<'a, I, const N: usize, const REV: bool> Bulk for ArrayChunksWithRemainder<'a, I, N, REV>
where
I: [const] Bulk<Item: [const] Destruct>
{
type MaxLength = <ArrayChunks<I, N> as Bulk>::MaxLength;
type MinLength = <ArrayChunks<I, N> as Bulk>::MinLength;
#[inline]
fn len(&self) -> usize
{
let Self { bulk, remainder: _ } = self;
bulk.len()
}
fn for_each<F>(self, f: F)
where
Self: Sized,
F: [const] FnMut(Self::Item) + [const] Destruct
{
let (bulk, closure) = self.for_each_closure(f);
bulk.for_each(closure)
}
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 = ()>
{
let (bulk, closure) = self.try_for_each_closure(f);
bulk.try_for_each(closure)
}
}
mod iter
{
use crate::util::ArrayBuffer;
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct ArrayChunksWithRemainder<'a, I, const N: usize, const REV: bool>
where
I: Iterator
{
iter: Option<core::iter::ArrayChunks<I, N>>,
remainder: &'a mut ArrayBuffer<I::Item, N, REV>
}
impl<'a, I, const N: usize, const REV: bool> ArrayChunksWithRemainder<'a, I, N, REV>
where
I: Iterator
{
pub(super) const fn new(iter: core::iter::ArrayChunks<I, N>, remainder: &'a mut ArrayBuffer<I::Item, N, REV>) -> Self
{
Self { iter: Some(iter), remainder }
}
}
const impl<'a, I, const N: usize, const REV: bool> Iterator for ArrayChunksWithRemainder<'a, I, N, REV>
where
I: Iterator,
core::iter::ArrayChunks<I, N>: [const] Iterator<Item = [I::Item; N]>
{
type Item = [I::Item; N];
fn next(&mut self) -> Option<Self::Item>
{
self.iter.as_mut().and_then(Iterator::next)
}
}
impl<'a, I, const N: usize, const REV: bool> ExactSizeIterator for ArrayChunksWithRemainder<'a, I, N, REV>
where
I: ExactSizeIterator
{
fn len(&self) -> usize
{
self.iter.as_ref().map(|iter| iter.len()).unwrap_or(0)
}
fn is_empty(&self) -> bool
{
self.iter.as_ref().is_none_or(|iter| iter.is_empty())
}
}
impl<'a, I, const N: usize, const REV: bool> Drop for ArrayChunksWithRemainder<'a, I, N, REV>
where
I: Iterator
{
fn drop(&mut self)
{
if let Some(mut iter) = self.iter.take().map(|iter| iter.into_remainder())
{
while !self.remainder.is_full()
&& let Some(value) = iter.next()
{
self.remainder.push(value);
}
}
}
}
}