1use std::{cmp::max, marker::PhantomData, num::NonZeroUsize};
2
3use crate::Dataset;
4
5pub trait Window<I> {
7 fn window(&self, current: usize, size: NonZeroUsize) -> Option<Vec<I>>;
13}
14
15impl<I, T: Dataset<I> + ?Sized> Window<I> for T {
16 fn window(&self, current: usize, size: NonZeroUsize) -> Option<Vec<I>> {
17 (current..current + size.get())
18 .map(|x| self.get(x))
19 .collect()
20 }
21}
22
23pub trait Windows<I> {
25 fn windows(&self, size: usize) -> WindowsIterator<'_, I>;
27}
28
29impl<I, T: Dataset<I>> Windows<I> for T {
30 fn windows(&self, size: usize) -> WindowsIterator<'_, I> {
52 let size = NonZeroUsize::new(size).expect("window size must be non-zero");
53 WindowsIterator::new(self, size)
54 }
55}
56
57pub struct WindowsIterator<'a, I> {
59 pub size: NonZeroUsize,
61 current: usize,
62 dataset: &'a dyn Dataset<I>,
63}
64
65impl<'a, I> WindowsIterator<'a, I> {
66 pub fn new(dataset: &'a dyn Dataset<I>, size: NonZeroUsize) -> Self {
74 WindowsIterator {
75 current: 0,
76 dataset,
77 size,
78 }
79 }
80}
81
82impl<I> Iterator for WindowsIterator<'_, I> {
83 type Item = Vec<I>;
84
85 fn next(&mut self) -> Option<Vec<I>> {
86 self.current += 1;
87 self.dataset.window(self.current - 1, self.size)
88 }
89}
90
91impl<I> Clone for WindowsIterator<'_, I> {
92 fn clone(&self) -> Self {
93 WindowsIterator {
94 size: self.size,
95 dataset: self.dataset,
96 current: self.current,
97 }
98 }
99}
100
101pub struct WindowsDataset<D, I> {
103 pub size: NonZeroUsize,
105 dataset: D,
106 input: PhantomData<I>,
107}
108
109impl<D, I> WindowsDataset<D, I>
110where
111 D: Dataset<I>,
112{
113 pub fn new(dataset: D, size: usize) -> Self
121 where
122 D:,
123 {
124 let size = NonZeroUsize::new(size).expect("window size must be non-zero");
125 WindowsDataset::<D, I> {
126 size,
127 dataset,
128 input: PhantomData,
129 }
130 }
131}
132
133impl<D, I> Dataset<Vec<I>> for WindowsDataset<D, I>
134where
135 D: Dataset<I>,
136 I: Send + Sync,
137{
138 fn get(&self, index: usize) -> Option<Vec<I>> {
148 self.dataset.window(index, self.size)
149 }
150
151 fn get_many(&self, indices: &[usize]) -> Option<Vec<Vec<I>>> {
152 let mut windows = Vec::with_capacity(indices.len());
153 let mut read_indices = Vec::new();
154 for &index in indices {
155 read_indices.clear();
156 read_indices.extend(index..index + self.size.get());
157 let window = self.dataset.get_many(&read_indices)?;
158 if window.len() != read_indices.len() {
159 return None;
160 }
161 windows.push(window);
162 }
163 Some(windows)
164 }
165
166 fn len(&self) -> usize {
172 let len = self.dataset.len() as isize - self.size.get() as isize + 1;
173 max(len, 0) as usize
174 }
175}
176
177#[cfg(test)]
178mod tests {
179 use rstest::rstest;
180
181 use crate::{
182 Dataset, InMemDataset,
183 transform::{Windows, WindowsDataset},
184 };
185
186 #[rstest]
187 pub fn windows_should_be_equal_to_vec_windows() {
188 let items = [1, 2, 3, 4, 5].to_vec();
189 let dataset = InMemDataset::new(items.clone());
190 let expected = items
191 .windows(3)
192 .map(|x| x.to_vec())
193 .collect::<Vec<Vec<i32>>>();
194
195 let result = dataset.windows(3).collect::<Vec<Vec<i32>>>();
196
197 assert_eq!(result, expected);
198 }
199
200 #[rstest]
201 pub fn windows_dataset_should_be_equal_to_vec_windows() {
202 let items = [1, 2, 3, 4, 5].to_vec();
203 let dataset = InMemDataset::new(items.clone());
204 let expected = items
205 .windows(3)
206 .map(|x| x.to_vec())
207 .collect::<Vec<Vec<i32>>>();
208
209 let result = WindowsDataset::new(dataset, 3)
210 .iter()
211 .collect::<Vec<Vec<i32>>>();
212
213 assert_eq!(result, expected);
214 }
215
216 #[rstest]
217 pub fn cloned_iterator_should_be_equal() {
218 let items = [1, 2, 3, 4, 5].to_vec();
219 let dataset = InMemDataset::new(items.clone());
220 let original = dataset.windows(4);
221
222 let cloned = original.clone();
223
224 assert!(std::ptr::eq(cloned.dataset, original.dataset));
225 assert_eq!(cloned.size, original.size);
226 assert_eq!(cloned.current, original.current);
227 }
228
229 #[rstest]
230 pub fn cloned_iterator_should_be_unaffected() {
231 let items = [1, 2, 3, 4, 5].to_vec();
232 let dataset = InMemDataset::new(items.clone());
233 let mut original = dataset.windows(4);
234
235 let cloned = original.clone();
236 original.current = 2;
237
238 assert_ne!(cloned.current, original.current);
239 }
240
241 #[rstest]
242 #[should_panic(expected = "window size must be non-zero")]
243 pub fn windows_should_panic() {
244 let items = [1, 2].to_vec();
245 let dataset = InMemDataset::new(items.clone());
246
247 dataset.windows(0);
248 }
249
250 #[rstest]
251 #[should_panic(expected = "window size must be non-zero")]
252 pub fn new_window_dataset_should_panic() {
253 let items = [1, 2].to_vec();
254 let dataset = InMemDataset::new(items.clone());
255
256 WindowsDataset::new(dataset, 0);
257 }
258
259 #[rstest]
260 pub fn window_dataset_len_should_be_equal() {
261 let dataset = InMemDataset::new([1, 2, 3, 4].to_vec());
262
263 let result = WindowsDataset::new(dataset, 2).len();
264
265 assert_eq!(result, 3);
266 }
267
268 #[rstest]
269 pub fn window_iterator_should_be_empty() {
270 let dataset = InMemDataset::new([1, 2].to_vec());
271 let mut peekable = dataset.windows(4).peekable();
272
273 let result = peekable.peek();
274
275 assert_eq!(result, None);
276 }
277
278 #[rstest]
279 pub fn window_dataset_len_should_be_zero() {
280 let dataset = InMemDataset::new([1, 2].to_vec());
281
282 let result = WindowsDataset::new(dataset, 4).len();
283
284 assert_eq!(result, 0);
285 }
286
287 #[rstest]
288 pub fn window_dataset_get_should_be_equal() {
289 let dataset = InMemDataset::new([1, 2, 3, 4].to_vec());
290 let expected = Some([1, 2, 3].to_vec());
291
292 let result = WindowsDataset::new(dataset, 3).get(0);
293
294 assert_eq!(result, expected);
295 }
296
297 #[rstest]
298 pub fn window_dataset_get_should_be_none() {
299 let dataset = InMemDataset::new([1, 2].to_vec());
300
301 let result = WindowsDataset::new(dataset, 4).get(0);
302
303 assert_eq!(result, None);
304 }
305}