Skip to main content

lender/sources/
windows_mut.rs

1use core::{fmt, num::NonZero};
2
3use crate::{DoubleEndedLender, ExactSizeLender, FusedLender, Lend, Lender, Lending};
4
5/// Creates a new lender that returns mutable contiguous overlapping windows of
6/// fixed size over a slice.
7///
8/// This is the mutable, lending variant of
9/// [`windows`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.windows).
10/// The const generic equivalent is [`array_windows_mut`].
11///
12/// Note that the [`WindowsMutExt`] trait provides a convenient entry point for
13/// this function as a method on slices and arrays.
14///
15/// # Panics
16///
17/// Panics if `size` is zero.
18///
19/// # Examples
20/// ```rust
21/// # use lender::prelude::*;
22/// let mut s = [0, 1, 2, 3];
23/// let mut lender = lender::windows_mut(&mut s, 2);
24/// assert_eq!(lender.next(), Some(&mut [0, 1][..]));
25///
26/// // Using the extension trait
27/// let mut lender = s.windows_mut(2);
28/// assert_eq!(lender.next(), Some(&mut [0, 1][..]));
29/// ```
30#[inline]
31pub fn windows_mut<T>(slice: &mut [T], size: usize) -> WindowsMut<'_, T> {
32    let size = NonZero::new(size).expect("window size must be non-zero");
33    WindowsMut {
34        slice,
35        size,
36        position: WindowPosition::Init,
37    }
38}
39
40/// A lender over mutable overlapping windows of a slice.
41///
42/// This `struct` is created by the [`windows_mut()`] function.
43#[must_use = "lenders are lazy and do nothing unless consumed"]
44pub struct WindowsMut<'a, T> {
45    slice: &'a mut [T],
46    size: NonZero<usize>,
47    position: WindowPosition,
48}
49
50impl<T: fmt::Debug> fmt::Debug for WindowsMut<'_, T> {
51    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52        f.debug_struct("WindowsMut")
53            .field("slice", &self.slice)
54            .field("size", &self.size)
55            .finish_non_exhaustive()
56    }
57}
58
59/// Tracks which position was most recently returned.
60#[derive(Clone, Copy)]
61enum WindowPosition {
62    Init,
63    Front,
64    Back,
65}
66
67impl WindowPosition {
68    /// Drop the end of the slice that we most recently returned.
69    #[inline]
70    fn update_slice<T>(self, slice: &mut &mut [T]) {
71        match self {
72            WindowPosition::Init => {}
73            WindowPosition::Front => {
74                // slice.split_off_first_mut();
75                if let [_, tail @ ..] = core::mem::take(slice) {
76                    *slice = tail;
77                }
78            }
79            WindowPosition::Back => {
80                // slice.split_off_last_mut();
81                if let [init @ .., _] = core::mem::take(slice) {
82                    *slice = init;
83                }
84            }
85        }
86    }
87}
88
89impl<'any, T> Lending<'any> for WindowsMut<'_, T> {
90    type Lend = &'any mut [T];
91}
92
93impl<T> Lender for WindowsMut<'_, T> {
94    crate::check_covariance!();
95    #[inline]
96    fn next(&mut self) -> Option<Lend<'_, Self>> {
97        self.position.update_slice(&mut self.slice);
98        self.position = WindowPosition::Front;
99        self.slice.get_mut(..self.size.get())
100    }
101
102    #[inline(always)]
103    fn size_hint(&self) -> (usize, Option<usize>) {
104        let len = self.len();
105        (len, Some(len))
106    }
107}
108
109impl<T> DoubleEndedLender for WindowsMut<'_, T> {
110    #[inline]
111    fn next_back(&mut self) -> Option<Lend<'_, Self>> {
112        self.position.update_slice(&mut self.slice);
113        self.position = WindowPosition::Back;
114        let index = self.slice.len().checked_sub(self.size.get())?;
115        self.slice.get_mut(index..)
116    }
117}
118
119impl<T> ExactSizeLender for WindowsMut<'_, T> {
120    #[inline]
121    fn len(&self) -> usize {
122        let base = self.slice.len().saturating_sub(self.size.get() - 1);
123        // If position is Front or Back, a window was returned but the slice
124        // hasn't been updated yet (update happens on the next call).
125        // We need to subtract 1 to reflect the consumed window.
126        match self.position {
127            WindowPosition::Init => base,
128            WindowPosition::Front | WindowPosition::Back => base.saturating_sub(1),
129        }
130    }
131}
132
133impl<T> FusedLender for WindowsMut<'_, T> {}
134
135/// Creates a new lender that returns mutable overlapping array
136/// windows of fixed size over a slice.
137///
138/// This is the mutable, lending variant of
139/// [`array_windows`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.array_windows).
140/// The non-const generic equivalent is [`windows_mut`].
141///
142/// Note that the [`WindowsMutExt`] trait provides a convenient
143/// entry point for this function as a method on slices and
144/// arrays.
145///
146/// See
147/// [`array_windows`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.array_windows).
148/// for more information.
149///
150///
151/// # Panics
152///
153/// Panics if `WINDOW_SIZE` is zero.
154///
155/// # Examples
156/// ```rust
157/// # use lender::prelude::*;
158/// let mut s = [0, 1, 2, 3];
159/// let mut lender = lender::array_windows_mut::<_, 2>(&mut s);
160/// assert_eq!(lender.next(), Some(&mut [0, 1]));
161///
162/// // Using the extension trait
163/// let mut lender = s.array_windows_mut::<2>();
164/// assert_eq!(lender.next(), Some(&mut [0, 1]));
165/// ```
166#[inline]
167pub fn array_windows_mut<T, const WINDOW_SIZE: usize>(
168    slice: &mut [T],
169) -> ArrayWindowsMut<'_, T, WINDOW_SIZE> {
170    assert!(WINDOW_SIZE != 0, "window size must be non-zero");
171    ArrayWindowsMut {
172        slice,
173        position: WindowPosition::Init,
174    }
175}
176
177/// A lender over mutable overlapping windows of a slice
178/// as fixed-size arrays.
179///
180/// This `struct` is created by the [`array_windows_mut()`]
181/// function.
182#[must_use = "lenders are lazy and do nothing unless consumed"]
183pub struct ArrayWindowsMut<'a, T, const WINDOW_SIZE: usize> {
184    slice: &'a mut [T],
185    position: WindowPosition,
186}
187
188impl<T: fmt::Debug, const WINDOW_SIZE: usize> fmt::Debug for ArrayWindowsMut<'_, T, WINDOW_SIZE> {
189    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
190        f.debug_struct("ArrayWindowsMut")
191            .field("slice", &self.slice)
192            .finish_non_exhaustive()
193    }
194}
195
196impl<'any, T, const WINDOW_SIZE: usize> Lending<'any> for ArrayWindowsMut<'_, T, WINDOW_SIZE> {
197    type Lend = &'any mut [T; WINDOW_SIZE];
198}
199
200impl<T, const WINDOW_SIZE: usize> Lender for ArrayWindowsMut<'_, T, WINDOW_SIZE> {
201    crate::check_covariance!();
202    #[inline]
203    fn next(&mut self) -> Option<Lend<'_, Self>> {
204        self.position.update_slice(&mut self.slice);
205        self.position = WindowPosition::Front;
206        self.slice.first_chunk_mut()
207    }
208
209    #[inline(always)]
210    fn size_hint(&self) -> (usize, Option<usize>) {
211        let len = self.len();
212        (len, Some(len))
213    }
214}
215
216impl<T, const WINDOW_SIZE: usize> DoubleEndedLender for ArrayWindowsMut<'_, T, WINDOW_SIZE> {
217    #[inline]
218    fn next_back(&mut self) -> Option<Lend<'_, Self>> {
219        self.position.update_slice(&mut self.slice);
220        self.position = WindowPosition::Back;
221        self.slice.last_chunk_mut()
222    }
223}
224
225impl<T, const WINDOW_SIZE: usize> ExactSizeLender for ArrayWindowsMut<'_, T, WINDOW_SIZE> {
226    #[inline]
227    fn len(&self) -> usize {
228        let base = self.slice.len().saturating_sub(WINDOW_SIZE - 1);
229        // If position is Front or Back, a window was returned but the slice
230        // hasn't been updated yet (update happens on the next call).
231        // We need to subtract 1 to reflect the consumed window.
232        match self.position {
233            WindowPosition::Init => base,
234            WindowPosition::Front | WindowPosition::Back => base.saturating_sub(1),
235        }
236    }
237}
238
239impl<T, const WINDOW_SIZE: usize> FusedLender for ArrayWindowsMut<'_, T, WINDOW_SIZE> {}
240
241/// Extension trait adding to slices and arrays the methods
242/// [`windows_mut`](WindowsMutExt::windows_mut) and
243/// [`array_windows_mut`](WindowsMutExt::array_windows_mut).
244pub trait WindowsMutExt<T> {
245    /// Returns a lender over mutable contiguous overlapping windows of `size` elements.
246    ///
247    /// See [`windows_mut`] for more details.
248    ///
249    /// # Panics
250    ///
251    /// Panics if `size` is zero.
252    fn windows_mut(&mut self, size: usize) -> WindowsMut<'_, T>;
253    /// Returns a lender over mutable overlapping array
254    /// windows of `WINDOW_SIZE` elements.
255    ///
256    /// See [`array_windows_mut`] for more details.
257    ///
258    /// # Panics
259    ///
260    /// Panics if `WINDOW_SIZE` is zero.
261    fn array_windows_mut<const WINDOW_SIZE: usize>(
262        &mut self,
263    ) -> ArrayWindowsMut<'_, T, WINDOW_SIZE>;
264}
265
266impl<T> WindowsMutExt<T> for [T] {
267    /// This method is a convenient entry point for [`windows_mut`].
268    ///
269    /// # Panics
270    ///
271    /// Panics if `size` is zero.
272    #[inline(always)]
273    fn windows_mut(&mut self, size: usize) -> WindowsMut<'_, T> {
274        windows_mut(self, size)
275    }
276    /// This method is a convenient entry point for [`array_windows_mut`].
277    ///
278    /// # Panics
279    ///
280    /// Panics if `WINDOW_SIZE` is zero.
281    #[inline(always)]
282    fn array_windows_mut<const WINDOW_SIZE: usize>(
283        &mut self,
284    ) -> ArrayWindowsMut<'_, T, WINDOW_SIZE> {
285        array_windows_mut(self)
286    }
287}
288
289impl<T, const N: usize> WindowsMutExt<T> for [T; N] {
290    /// This method is a convenient entry point for [`windows_mut`].
291    ///
292    /// # Panics
293    ///
294    /// Panics if `size` is zero.
295    #[inline(always)]
296    fn windows_mut(&mut self, size: usize) -> WindowsMut<'_, T> {
297        windows_mut(self, size)
298    }
299    /// This method is a convenient entry point for [`array_windows_mut`].
300    ///
301    /// # Panics
302    ///
303    /// Panics if `WINDOW_SIZE` is zero.
304    #[inline(always)]
305    fn array_windows_mut<const WINDOW_SIZE: usize>(
306        &mut self,
307    ) -> ArrayWindowsMut<'_, T, WINDOW_SIZE> {
308        array_windows_mut(self)
309    }
310}
311
312#[test]
313fn test_array_windows_mut() {
314    let mut s = [0, 1, 2, 3];
315    let mut lender = array_windows_mut::<_, 2>(&mut s);
316    assert_eq!(lender.next(), Some(&mut [0, 1]));
317    assert_eq!(lender.next(), Some(&mut [1, 2]));
318    assert_eq!(lender.next(), Some(&mut [2, 3]));
319    assert_eq!(lender.next(), None);
320}
321
322#[test]
323fn test_array_windows_mut_rev() {
324    let mut s = [0, 1, 2, 3];
325    let mut lender = array_windows_mut::<_, 2>(&mut s).rev();
326    assert_eq!(lender.next(), Some(&mut [2, 3]));
327    assert_eq!(lender.next(), Some(&mut [1, 2]));
328    assert_eq!(lender.next(), Some(&mut [0, 1]));
329    assert_eq!(lender.next(), None);
330}
331
332#[test]
333fn test_array_windows_mut_mixed() {
334    let mut s = [0, 1, 2, 3, 4];
335    let mut lender = array_windows_mut::<_, 2>(&mut s);
336    assert_eq!(lender.next_back(), Some(&mut [3, 4]));
337    assert_eq!(lender.next(), Some(&mut [0, 1]));
338    assert_eq!(lender.next_back(), Some(&mut [2, 3]));
339    assert_eq!(lender.next(), Some(&mut [1, 2]));
340    assert_eq!(lender.next_back(), None);
341    assert_eq!(lender.next(), None);
342}
343
344#[test]
345fn test_windows_mut() {
346    let mut s = [0, 1, 2, 3];
347    let mut lender = windows_mut(&mut s, 2);
348    assert_eq!(lender.next(), Some(&mut [0, 1][..]));
349    assert_eq!(lender.next(), Some(&mut [1, 2][..]));
350    assert_eq!(lender.next(), Some(&mut [2, 3][..]));
351    assert_eq!(lender.next(), None);
352}
353
354#[test]
355fn test_windows_mut_rev() {
356    let mut s = [0, 1, 2, 3];
357    let mut lender = windows_mut(&mut s, 2).rev();
358    assert_eq!(lender.next(), Some(&mut [2, 3][..]));
359    assert_eq!(lender.next(), Some(&mut [1, 2][..]));
360    assert_eq!(lender.next(), Some(&mut [0, 1][..]));
361    assert_eq!(lender.next(), None);
362}
363
364#[test]
365fn test_windows_mut_back() {
366    let mut s = [0, 1, 2, 3, 4];
367    let mut lender = windows_mut(&mut s, 2);
368    assert_eq!(lender.next_back(), Some(&mut [3, 4][..]));
369    assert_eq!(lender.next(), Some(&mut [0, 1][..]));
370    assert_eq!(lender.next_back(), Some(&mut [2, 3][..]));
371    assert_eq!(lender.next(), Some(&mut [1, 2][..]));
372    assert_eq!(lender.next_back(), None);
373    assert_eq!(lender.next(), None);
374}
375
376#[test]
377fn test_windows_mut_exact_size() {
378    use crate::ExactSizeLender;
379
380    let mut s = [0, 1, 2, 3, 4];
381    let mut lender = windows_mut(&mut s, 2);
382    assert_eq!(lender.len(), 4);
383    lender.next();
384    assert_eq!(lender.len(), 3);
385    lender.next();
386    assert_eq!(lender.len(), 2);
387    lender.next();
388    assert_eq!(lender.len(), 1);
389    lender.next();
390    assert_eq!(lender.len(), 0);
391    lender.next(); // returns None
392    assert_eq!(lender.len(), 0);
393
394    // Edge cases
395    let mut empty: [i32; 0] = [];
396    assert_eq!(windows_mut(&mut empty, 2).len(), 0);
397
398    let mut single = [1];
399    assert_eq!(windows_mut(&mut single, 2).len(), 0);
400    assert_eq!(windows_mut(&mut single, 1).len(), 1);
401}
402
403#[test]
404#[should_panic(expected = "window size must be non-zero")]
405fn test_windows_mut_zero_size_panics() {
406    let mut arr = [1, 2, 3];
407    let _ = windows_mut(&mut arr, 0);
408}
409
410#[test]
411fn test_array_windows_mut_exact_size() {
412    use crate::ExactSizeLender;
413
414    let mut s = [0, 1, 2, 3, 4];
415    let mut lender = array_windows_mut::<_, 2>(&mut s);
416    assert_eq!(lender.len(), 4);
417    lender.next();
418    assert_eq!(lender.len(), 3);
419    lender.next();
420    assert_eq!(lender.len(), 2);
421
422    // Edge cases
423    let mut single = [1];
424    assert_eq!(array_windows_mut::<_, 2>(&mut single).len(), 0);
425    assert_eq!(array_windows_mut::<_, 1>(&mut single).len(), 1);
426}
427
428#[test]
429fn test_windows_mut_exact_size_mixed() {
430    use crate::ExactSizeLender;
431
432    let mut s = [0, 1, 2, 3, 4];
433    let mut lender = windows_mut(&mut s, 2);
434    assert_eq!(lender.len(), 4);
435    lender.next_back();
436    assert_eq!(lender.len(), 3);
437    lender.next();
438    assert_eq!(lender.len(), 2);
439    lender.next_back();
440    assert_eq!(lender.len(), 1);
441    lender.next();
442    assert_eq!(lender.len(), 0);
443}