1 /// Allows splitting a reference to an array type into fixed-length chunks.
2 pub trait ChunksFixed<'a, Chunks>
3 where
4     Chunks: 'a,
5 {
chunks_fixed(self) -> Chunks6     fn chunks_fixed(self) -> Chunks;
7 }
8 
9 /// Allows iterating over a mutable array in fixed-length chunks.
10 ///
11 /// The design of this is different than that for `ChunksFixed` because it
12 /// isn't clear that we can legally (according to Rust's rules) convert create
13 /// a mutable reference to the chunked type from a mutable reference.
14 ///
15 /// TODO: Get clarification on the rules and refactor this tp be more like
16 /// `ChunksFixed`.
17 pub trait ChunksFixedMut<'a, Chunk>
18 where
19     Chunk: 'a,
20 {
21     type MutIterator: Iterator<Item = &'a mut Chunk>;
22 
chunks_fixed_mut(self) -> Self::MutIterator23     fn chunks_fixed_mut(self) -> Self::MutIterator;
24 }
25 
26 /// `$unchuncked_len` must be divisible by `$chunk_len`.
27 macro_rules! define_chunks_fixed {
28     ( $unchuncked_len:expr, $chunk_len:expr ) => {
29         define_chunks_fixed!($unchuncked_len, $chunk_len, $unchuncked_len / $chunk_len);
30     };
31 
32     ( $unchuncked_len:expr, $chunk_len:expr, $chunked_len:expr ) => {
33         impl<'a, T> ChunksFixed<'a, &'a [[T; $chunk_len]; $chunked_len]>
34             for &'a [T; $unchuncked_len]
35         {
36             #[inline(always)]
37             fn chunks_fixed(self) -> &'a [[T; $chunk_len]; $chunked_len] {
38                 let as_ptr: *const [T; $chunk_len] = self.as_ptr() as *const [T; $chunk_len];
39                 let as_ptr = as_ptr as *const [[T; $chunk_len]; $chunked_len];
40                 unsafe { &*as_ptr }
41             }
42         }
43 
44         impl<'a, T> ChunksFixedMut<'a, [T; $chunk_len]> for &'a mut [T; $unchuncked_len] {
45             type MutIterator = core::iter::Map<
46                 core::slice::ChunksExactMut<'a, T>,
47                 fn(&'a mut [T]) -> &'a mut [T; $chunk_len],
48             >;
49 
50             #[inline(always)]
51             fn chunks_fixed_mut(self) -> Self::MutIterator {
52                 // There will be no remainder because `$unchuncked_len` must be divisible by
53                 // `$chunk_len`. The `unwrap()` will not fail for the same reason.
54                 self.chunks_exact_mut($chunk_len)
55                     .map(|slice| slice.try_into().unwrap())
56             }
57         }
58     };
59 }
60 
61 // Sorted by the first value, then the second value.
62 define_chunks_fixed!(12, 4);
63 define_chunks_fixed!(16, 4);
64 define_chunks_fixed!(16, 8);
65 define_chunks_fixed!(32, 4);
66 define_chunks_fixed!(64, 4);
67 define_chunks_fixed!(64, 32);
68 define_chunks_fixed!(80, 20);
69