slice_utils/
windows.rs

1use crate::{Slice, SliceBorrowed, SliceOf, SliceOwned};
2
3macro_rules! either {
4    ( [][$($t:tt)*] ) => {$($t)*};
5    ( [$($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            /// A slice/iterator over overlapping windows of a slice; see
12            #[doc = concat!("[`Slice", stringify!($owned), "::windows`].")]
13            #[derive(Clone, Copy)]
14            pub struct [<Windows $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> [<Windows $owned>]<'a, S>
22            where
23                S: [<Slice $owned>] + ?Sized,
24            {
25                /// See
26                #[doc = concat!("[`Slice", stringify!($owned), "::windows`].")]
27                pub fn new(data: &'a S, size: usize) -> Self {
28                    if size == 0 {
29                        panic!("cannot call `windows` with size = 0");
30                    }
31
32                    Self {
33                        data,
34                        size,
35                        i: 0,
36                    }
37                }
38            }
39
40            impl<'a, S> Slice for [<Windows $owned>]<'a, S>
41            where
42                S: [<Slice $owned>] + ?Sized,
43            {
44                type Output = SliceOf<&'a S>;
45
46                fn len(&self) -> usize {
47                    self.data.len() - self.size + 1
48                }
49
50                fn get_with<W: FnMut(&Self::Output) -> R, R>(
51                    &self,
52                    index: usize,
53                    f: &mut W
54                ) -> Option<R> {
55                    Some(f(&self.get_owned(index)?))
56                }
57            }
58
59            impl<'a, S> SliceOwned for [<Windows $owned>]<'a, S>
60            where
61                S: [<Slice $owned>] + ?Sized,
62            {
63                fn get_owned(&self, index: usize) -> Option<Self::Output> {
64                    if index > Slice::len(self) {
65                        None
66                    } else {
67                        self.data.slice(index..index+self.size)
68                    }
69                }
70            }
71
72            impl<'a, S> Iterator for [<Windows $owned>]<'a, S>
73            where
74                S: [<Slice $owned>] + ?Sized,
75            {
76                type Item = SliceOf<&'a S>;
77
78                fn next(&mut self) -> Option<Self::Item> {
79                    if self.i > self.data.len() {
80                        None
81                    } else {
82                        let start = self.i;
83                        self.i += 1;
84                        self.get_owned(start)
85                    }
86                }
87
88                fn size_hint(&self) -> (usize, Option<usize>) {
89                    let len = Slice::len(self);
90                    (len, Some(len))
91                }
92            }
93
94            impl<'a, S> ExactSizeIterator
95                for [<Windows $owned>]<'a, S>
96            where
97                S: [<Slice $owned>] + ?Sized {}
98
99            type [<ArrayWindow $owned>]<$($lt,)? S> = either!([$(&$lt S)?][S]);
100            /// A slice/iterator over overlapping windows of a slice; see
101            #[doc = concat!("[`Slice", stringify!($owned), "::array_windows`].")]
102            #[derive(Clone, Copy)]
103            pub struct [<ArrayWindows $owned>]<$($lt,)? S: $sized, const N: usize> {
104                /// The inner slice.
105                pub data: [<ArrayWindow $owned>]<$($lt,)? S>,
106                i: usize,
107            }
108
109            impl<$($lt,)? S, const N: usize> [<ArrayWindows $owned>]<$($lt,)? S, N>
110            where
111                S: [<Slice $owned>] + $sized,
112            {
113                /// See
114                #[doc = concat!("[`Slice", stringify!($owned), "::array_windows`].")]
115                pub fn new(data: either!([$(&$lt S)?][S])) -> Self {
116                    // TODO: make this a comptime assertion
117                    if N == 0 {
118                        panic!("cannot call `windows` with size = 0");
119                    }
120
121                    Self {
122                        data,
123                        i: 0,
124                    }
125                }
126            }
127
128            impl<$($lt,)? S, const N: usize> Slice for [<ArrayWindows $owned>]<$($lt,)? S, N>
129            where
130                S: [<Slice $owned>] + $sized,
131            {
132                type Output = [$item; N];
133
134                fn len(&self) -> usize {
135                    self.data.len() - N + 1
136                }
137
138                fn get_with<W: FnMut(&Self::Output) -> R, R>(
139                    &self,
140                    index: usize,
141                    f: &mut W
142                ) -> Option<R> {
143                    Some(f(&self.get_owned(index)?))
144                }
145            }
146
147            impl<$($lt,)? S, const N: usize> SliceOwned for [<ArrayWindows $owned>]<$($lt,)? S, N>
148            where
149                S: [<Slice $owned>] + $sized,
150            {
151                fn get_owned(&self, index: usize) -> Option<Self::Output> {
152                    if index > Slice::len(self) {
153                        None
154                    } else {
155                        Some(core::array::from_fn(|i| self.data.$fn(index + i).unwrap()))
156                    }
157                }
158            }
159
160            impl<$($lt,)? S, const N: usize> Iterator for [<ArrayWindows $owned>]<$($lt,)? S, N>
161            where
162                S: [<Slice $owned>] + $sized,
163            {
164                type Item = [$item; N];
165
166                fn next(&mut self) -> Option<Self::Item> {
167                    if self.i + N > self.data.len() {
168                        None
169                    } else {
170                        let start = self.i;
171                        self.i += 1;
172                        self.get_owned(start)
173                    }
174                }
175
176                fn size_hint(&self) -> (usize, Option<usize>) {
177                    let len = self.data.len() - N + 1;
178                    (len, Some(len))
179                }
180            }
181
182            impl<$($lt,)? S, const N: usize> ExactSizeIterator
183                for [<ArrayWindows $owned>]<$($lt,)? S, N>
184            where
185                S: [<Slice $owned>] + $sized {}
186        }
187    };
188}
189
190def_window!(Owned, [], Sized, S::Output, get_owned);
191def_window!(Borrowed, ['a], ?Sized, &'a S::Output, get);