slice_utils/
chunks.rs

1use crate::{Slice, SliceBorrowed, SliceOf, SliceOwned};
2
3macro_rules! either {
4    ( [[] $($_:tt)*][$($t:tt)*] ) => {$($t)*};
5    ( [[$($_:tt)*] $($t:tt)*][$($__:tt)*] ) => {$($t)*};
6}
7
8macro_rules! def_window {
9    ( $owned:ident, [$($lt:lifetime)?], $sized:ty, $item:ty, $fn:ident ) => {
10        paste::paste! {
11            /// An iterator over overlapping chunks of a slice; see
12            #[doc = concat!("[`Slice", stringify!($owned), "::chunks`].")]
13            #[derive(Debug, Clone, Copy)]
14            pub struct [<Chunks $owned>]<'a, S: ?Sized> {
15                /// The slice underlying the iterator.
16                pub data: &'a S,
17                size: usize,
18                i: usize,
19            }
20
21            impl<'a, S> [<Chunks $owned>]<'a, S>
22            where
23                S: [<Slice $owned>] + ?Sized,
24            {
25                /// Create a new iterator; see
26                #[doc = concat!("[`Slice", stringify!($owned), "::chunks`].")]
27                pub fn new(data: &'a S, size: usize) -> Self {
28                    if size == 0 {
29                        panic!("cannot call `chunks` with size = 0");
30                    }
31
32                    Self {
33                        data,
34                        size,
35                        i: 0,
36                    }
37                }
38            }
39
40            impl<'a, S> Iterator for [<Chunks $owned>]<'a, S>
41            where
42                S: [<Slice $owned>] + ?Sized,
43            {
44                type Item = SliceOf<&'a S>;
45
46                fn next(&mut self) -> Option<Self::Item> {
47                    if self.i == self.data.len() {
48                        None
49                    } else {
50                        let start = self.i;
51                        self.i = self.data.len().min(self.i + self.size);
52
53                        self.data.slice(start..self.i)
54                    }
55                }
56
57                fn size_hint(&self) -> (usize, Option<usize>) {
58                    let len = self.data.len() / self.size;
59                    (len, Some(len))
60                }
61            }
62
63            impl<'a, S> ExactSizeIterator
64                for [<Chunks $owned>]<'a, S>
65            where
66                S: [<Slice $owned>] + ?Sized {}
67
68            type [<ArrayWindow $owned>]<$($lt,)? S> = either!([[$($lt)?] $(&$lt S)?][S]);
69            /// An iterator over overlapping chunks of a slice; see
70            #[doc = concat!("[`Slice", stringify!($owned), "::array_chunks`].")]
71            #[derive(Debug, Clone, Copy)]
72            pub struct [<ArrayChunks $owned>]<$($lt,)? S: $sized, const N: usize> {
73                /// The slice underlying the iterator.
74                pub data: [<ArrayWindow $owned>]<$($lt,)? S>,
75                i: usize,
76            }
77
78            impl<$($lt,)? S, const N: usize> [<ArrayChunks $owned>]<$($lt,)? S, N>
79            where
80                S: [<Slice $owned>] + $sized,
81            {
82                /// Create a new iterator; see
83                #[doc = concat!("[`Slice", stringify!($owned), "::array_chunks`].")]
84                pub fn new(data: either!([[$($lt)?] $(&$lt S)?][S])) -> Self {
85                    // TODO: make this a comptime assertion
86                    if N == 0 {
87                        panic!("cannot call `chunks` with size = 0");
88                    }
89
90                    Self {
91                        data,
92                        i: 0,
93                    }
94                }
95
96                /// Returns the leftover from the end of the slice, if any.
97                pub fn remainder(&self) -> SliceOf<&S> {
98                    let len = self.data.len();
99                    let start = len - (len % N);
100                    (either!([[$($lt)?] self.data][&self.data])).slice(start..).unwrap()
101                }
102            }
103
104            impl<$($lt,)? S, const N: usize> Iterator for [<ArrayChunks $owned>]<$($lt,)? S, N>
105            where
106                S: [<Slice $owned>] + $sized,
107            {
108                type Item = [$item; N];
109
110                fn next(&mut self) -> Option<Self::Item> {
111                    if self.i + N > self.data.len() {
112                        None
113                    } else {
114                        let start = self.i;
115                        self.i += N;
116
117                        Some(core::array::from_fn(|i| self.data.$fn(start + i).unwrap()))
118                    }
119                }
120
121                fn size_hint(&self) -> (usize, Option<usize>) {
122                    let len = self.data.len() / N;
123                    (len, Some(len))
124                }
125            }
126
127            impl<$($lt,)? S, const N: usize> ExactSizeIterator
128                for [<ArrayChunks $owned>]<$($lt,)? S, N>
129            where
130                S: [<Slice $owned>] + $sized {}
131        }
132    };
133}
134
135def_window!(Owned, [], Sized, S::Output, get_owned);
136def_window!(Borrowed, ['a], ?Sized, &'a S::Output, get);