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 #[doc = concat!("[`Slice", stringify!($owned), "::chunks`].")]
13 #[derive(Debug, Clone, Copy)]
14 pub struct [<Chunks $owned>]<'a, S: ?Sized> {
15 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 #[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 #[doc = concat!("[`Slice", stringify!($owned), "::array_chunks`].")]
71 #[derive(Debug, Clone, Copy)]
72 pub struct [<ArrayChunks $owned>]<$($lt,)? S: $sized, const N: usize> {
73 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 #[doc = concat!("[`Slice", stringify!($owned), "::array_chunks`].")]
84 pub fn new(data: either!([[$($lt)?] $(&$lt S)?][S])) -> Self {
85 if N == 0 {
87 panic!("cannot call `chunks` with size = 0");
88 }
89
90 Self {
91 data,
92 i: 0,
93 }
94 }
95
96 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);