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