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}