soa_rs/
chunks_exact.rs

1use crate::{Slice, SliceRef, SoaRaw, Soars};
2use std::marker::PhantomData;
3
4/// An iterator over a [`Slice`] in (non-overlapping) chunks of `chunk_size`
5/// elements.
6///
7/// When the slice len is not evenly divided by the chunk size, the last up to
8/// `chunk_size-1` elements will be omitted but can be retrieved from the
9/// [`remainder`] function from the iterator.
10///
11/// This struct is created by the [`chunks_exact`] method.
12///
13/// [`remainder`]: ChunksExact::remainder
14/// [`chunks_exact`]: Slice::chunks_exact
15pub struct ChunksExact<'a, T>
16where
17    T: 'a + Soars,
18{
19    slice: Slice<T, ()>,
20    remainder: SliceRef<'a, T>,
21    parts_remaining: usize,
22    chunk_size: usize,
23}
24
25impl<'a, T> ChunksExact<'a, T>
26where
27    T: Soars,
28{
29    pub(crate) fn new(slice: &'a Slice<T>, chunk_size: usize) -> Self {
30        let len = slice.len();
31        let rem_len = len % chunk_size;
32        let fst_len = len - rem_len;
33        let remainder = slice.idx(fst_len..);
34        // SAFETY: Lifetime of self is bound to the passed slice
35        let slice = unsafe { slice.as_sized() };
36        Self {
37            slice,
38            remainder,
39            parts_remaining: fst_len / chunk_size,
40            chunk_size,
41        }
42    }
43
44    /// Returns the remainder of the original slice that has not been yielded by
45    /// the iterator.
46    pub fn remainder(&self) -> &Slice<T> {
47        self.remainder.as_ref()
48    }
49}
50
51impl<'a, T> Iterator for ChunksExact<'a, T>
52where
53    T: Soars,
54{
55    type Item = SliceRef<'a, T>;
56
57    fn next(&mut self) -> Option<Self::Item> {
58        if self.parts_remaining == 0 {
59            None
60        } else {
61            let out = SliceRef {
62                slice: self.slice,
63                len: self.chunk_size,
64                marker: PhantomData,
65            };
66            self.parts_remaining -= 1;
67            // SAFETY: We had a remaining part, so we have at least chunk_size items
68            self.slice.raw = unsafe { self.slice.raw().offset(self.chunk_size) };
69            Some(out)
70        }
71    }
72}