Skip to main content

devela/sys/mem/view/slice/namespace/
chunk.rs

1// devela::sys::mem::view::slice::namespace::chunk
2
3use crate::{Slice, is, lets};
4
5/// # `*chunk*` API methods for subslicing.
6#[rustfmt::skip]
7impl<T> Slice<T> {
8    /// Returns the number of complete `N`-sized chunks in `slice` and the trailing remainder.
9    ///
10    /// This is the fixed-step primitive for const-friendly traversal.
11    ///
12    /// # Examples
13    /// ```
14    /// # use devela::Slice;
15    /// let bytes = b"abcdefg";
16    /// let (count, rem) = Slice::chunks_exact::<3>(bytes);
17    /// assert_eq!(count, 2); // "abc", "def"
18    /// assert_eq!(rem, b"g");
19    /// ```
20    pub const fn chunks_exact<const N: usize>(slice: &[T]) -> (usize, &[T]) {
21        lets![full=slice.len()/N, rem_start=full*N];
22        (full, Slice::range_from(slice, rem_start))
23    }
24
25    /// Mutable counterpart to [`chunks_exact`][Self::chunks_exact].
26    ///
27    /// Returns the number of complete `N`-sized chunks and a mutable remainder slice.
28    /// The caller performs any iteration or stepping logic.
29    pub const fn chunks_exact_mut<const N: usize>(slice: &mut [T]) -> (usize, &mut [T]) {
30        lets![full=slice.len()/N, rem_start=full*N];
31        (full, Slice::range_from_mut(slice, rem_start))
32    }
33
34    /// Returns the `idx`-th complete chunk of size `N`, or `None` if incomplete.
35    ///
36    /// This offers direct, index-based access to fixed-width records.
37    /// Bounds are checked; no iteration policy is imposed.
38    ///
39    /// # Examples
40    /// ```
41    /// # use devela::Slice;
42    /// let b = b"abcdefgh";
43    /// assert_eq!(Slice::chunk::<3>(b, 0), Some(&b"abc"[..]));
44    /// assert_eq!(Slice::chunk::<3>(b, 1), Some(&b"def"[..]));
45    /// assert_eq!(Slice::chunk::<3>(b, 2), None); // only "gh" remains, not enough for a full chunk
46    /// ```
47    pub const fn chunk<const N: usize>(slice: &[T], idx: usize) -> Option<&[T]> {
48        lets![start=idx*N, end=start+N];
49        is![end <= slice.len(), Some(Slice::range(slice, start, end)), None]
50    }
51
52    /// Mutable counterpart to [`chunk`][Self::chunk].
53    ///
54    /// Returns the `idx`-th complete chunk of size `N` as a mutable subslice,
55    /// or `None` if the chunk is incomplete.
56    ///
57    /// # Examples
58    /// ```
59    /// # use devela::Slice;
60    /// let mut b = *b"abcdef";
61    /// if let Some(ch) = Slice::chunk_mut::<3>(&mut b, 1) {
62    ///     ch[0] = b'X';
63    /// }
64    /// assert_eq!(&b, b"abcXef");
65    /// ```
66    pub const fn chunk_mut<const N: usize>(slice: &mut [T], idx: usize) -> Option<&mut [T]> {
67        lets![start=idx*N, end=start+N];
68        is![end <= slice.len(), Some(Slice::range_mut(slice, start, end)), None]
69    }
70}
71
72#[test]
73#[cfg(test)]
74fn test_chunks() {
75    let mut buf = [10, 11, 12, 13, 14, 15, 16];
76
77    // chunks_exact
78    let (count, rem) = Slice::chunks_exact::<3>(&buf);
79    assert_eq!(count, 2); // [10,11,12] , [13,14,15]
80    assert_eq!(rem, &[16]);
81
82    // chunks_exact_mut
83    let (count_mut, rem_mut) = Slice::chunks_exact_mut::<3>(&mut buf);
84    assert_eq!(count_mut, 2);
85    assert_eq!(rem_mut, &mut [16]);
86
87    // chunk
88    let c0 = Slice::chunk::<3>(&buf, 0).unwrap();
89    let c1 = Slice::chunk::<3>(&buf, 1).unwrap();
90    assert_eq!(c0, &[10, 11, 12]);
91    assert_eq!(c1, &[13, 14, 15]);
92    assert!(Slice::chunk::<3>(&buf, 2).is_none());
93
94    // chunk_mut
95    is![let Some(c0m) = Slice::chunk_mut::<3>(&mut buf, 0), c0m[0] = 99];
96    assert_eq!(buf[0], 99);
97}