ring/polyfill/slice/
as_chunks.rs

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 AUTHOR DISCLAIMS ALL WARRANTIES
8// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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
15use super::AsChunksMut;
16use core::ops;
17
18#[inline(always)]
19pub 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 = slice.len() / N;
22    let (multiple_of_n, remainder) = slice.split_at(len * N);
23    (AsChunks(multiple_of_n), remainder)
24}
25
26#[derive(Clone, Copy)]
27pub struct AsChunks<'a, T, const N: usize>(&'a [T]);
28
29impl<'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
57impl<T, const N: usize> ops::Index<usize> for AsChunks<'_, T, N>
58where
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 = N * index;
66        let slice = &self.0[start..(start + N)];
67        slice.try_into().unwrap()
68    }
69}
70
71impl<'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
81pub struct AsChunksIter<'a, T, const N: usize>(core::slice::ChunksExact<'a, T>);
82
83impl<'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| 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.
94impl<'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
101impl<'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>`.
109impl<'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}