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