• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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