| 1 | // Copyright 2025 Brian Smith. |
| 2 | // |
| 3 | // Permission to use, copy, modify, and/or distribute this software for any |
| 4 | // purpose with or without fee is hereby granted, provided that the above |
| 5 | // copyright notice and this permission notice appear in all copies. |
| 6 | // |
| 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES |
| 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY |
| 10 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
| 12 | // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
| 13 | // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 14 | |
| 15 | use super::AsChunksMut; |
| 16 | use core::ops; |
| 17 | |
| 18 | #[inline (always)] |
| 19 | pub fn as_chunks<T, const N: usize>(slice: &[T]) -> (AsChunks<T, N>, &[T]) { |
| 20 | assert!(N != 0, "chunk size must be non-zero" ); |
| 21 | let len: usize = slice.len() / N; |
| 22 | let (multiple_of_n: &[T], remainder: &[T]) = slice.split_at(mid:len * N); |
| 23 | (AsChunks(multiple_of_n), remainder) |
| 24 | } |
| 25 | |
| 26 | #[derive (Clone, Copy)] |
| 27 | pub struct AsChunks<'a, T, const N: usize>(&'a [T]); |
| 28 | |
| 29 | impl<'a, T, const N: usize> AsChunks<'a, T, N> { |
| 30 | #[inline (always)] |
| 31 | pub fn from_ref(value: &'a [T; N]) -> Self { |
| 32 | Self(value) |
| 33 | } |
| 34 | |
| 35 | #[inline (always)] |
| 36 | pub fn as_flattened(&self) -> &[T] { |
| 37 | self.0 |
| 38 | } |
| 39 | |
| 40 | #[cfg (any(target_arch = "aarch64" , target_arch = "arm" , target_arch = "x86_64" ))] |
| 41 | #[inline (always)] |
| 42 | pub fn as_ptr(&self) -> *const [T; N] { |
| 43 | self.0.as_ptr().cast() |
| 44 | } |
| 45 | |
| 46 | #[inline (always)] |
| 47 | pub fn is_empty(&self) -> bool { |
| 48 | self.0.is_empty() |
| 49 | } |
| 50 | |
| 51 | #[inline (always)] |
| 52 | pub fn len(&self) -> usize { |
| 53 | self.0.len() / N |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | impl<T, const N: usize> ops::Index<usize> for AsChunks<'_, T, N> |
| 58 | where |
| 59 | [T]: ops::Index<ops::Range<usize>, Output = [T]>, |
| 60 | { |
| 61 | type Output = [T; N]; |
| 62 | |
| 63 | #[inline (always)] |
| 64 | fn index(&self, index: usize) -> &Self::Output { |
| 65 | let start: usize = N * index; |
| 66 | let slice: &[T] = &self.0[start..(start + N)]; |
| 67 | slice.try_into().unwrap() |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | impl<'a, T, const N: usize> IntoIterator for AsChunks<'a, T, N> { |
| 72 | type IntoIter = AsChunksIter<'a, T, N>; |
| 73 | type Item = &'a [T; N]; |
| 74 | |
| 75 | #[inline (always)] |
| 76 | fn into_iter(self) -> Self::IntoIter { |
| 77 | AsChunksIter(self.0.chunks_exact(N)) |
| 78 | } |
| 79 | } |
| 80 | |
| 81 | pub struct AsChunksIter<'a, T, const N: usize>(core::slice::ChunksExact<'a, T>); |
| 82 | |
| 83 | impl<'a, T, const N: usize> Iterator for AsChunksIter<'a, T, N> { |
| 84 | type Item = &'a [T; N]; |
| 85 | |
| 86 | #[inline (always)] |
| 87 | fn next(&mut self) -> Option<Self::Item> { |
| 88 | self.0.next().map(|x: &'a [T]| x.try_into().unwrap()) |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | // `&mut [[T; N]]` is implicitly convertable to `&[[T; N]]` but our types can't |
| 93 | // do that. |
| 94 | impl<'a, T, const N: usize> From<&'a AsChunksMut<'_, T, N>> for AsChunks<'a, T, N> { |
| 95 | #[inline (always)] |
| 96 | fn from(as_mut: &'a AsChunksMut<'_, T, N>) -> Self { |
| 97 | Self(as_mut.as_flattened()) |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | impl<'a, T, const N: usize> From<&'a [T; N]> for AsChunks<'a, T, N> { |
| 102 | #[inline (always)] |
| 103 | fn from(array: &'a [T; N]) -> Self { |
| 104 | Self(array) |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | // TODO: `impl From<AsChunks<'a, T, {2*N}> for AsChunks<'a, T, N>`. |
| 109 | impl<'a, T> From<AsChunks<'a, T, 8>> for AsChunks<'a, T, 4> { |
| 110 | #[inline (always)] |
| 111 | fn from(as_2x: AsChunks<'a, T, 8>) -> Self { |
| 112 | Self(as_2x.0) |
| 113 | } |
| 114 | } |
| 115 | |