#![no_std]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![doc = include_str!("../README.md")]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
)]
#![warn(
clippy::cast_lossless,
clippy::cast_possible_truncation,
clippy::cast_possible_wrap,
clippy::cast_precision_loss,
clippy::cast_sign_loss,
clippy::checked_conversions,
clippy::implicit_saturating_sub,
clippy::arithmetic_side_effects,
clippy::panic,
clippy::panic_in_result_fn,
clippy::unwrap_used,
missing_docs,
rust_2018_idioms,
unused_lifetimes,
unused_qualifications
)]
mod sizes;
pub use typenum;
pub use typenum::consts;
use core::{
array::TryFromSliceError,
borrow::{Borrow, BorrowMut},
cmp::Ordering,
fmt::{self, Debug},
hash::{Hash, Hasher},
mem::{ManuallyDrop, MaybeUninit},
ops::{Add, Deref, DerefMut, Index, IndexMut, Range, Sub},
ptr,
slice::{self, Iter, IterMut},
};
use typenum::{Diff, Sum, Unsigned};
#[cfg(feature = "zeroize")]
use zeroize::{Zeroize, ZeroizeOnDrop};
pub type ArrayN<T, const N: usize> = Array<T, <[T; N] as AssociatedArraySize>::Size>;
#[repr(transparent)]
pub struct Array<T, U: ArraySize>(pub U::ArrayType<T>);
type SplitResult<T, U, N> = (Array<T, N>, Array<T, Diff<U, N>>);
type SplitRefResult<'a, T, U, N> = (&'a Array<T, N>, &'a Array<T, Diff<U, N>>);
type SplitRefMutResult<'a, T, U, N> = (&'a mut Array<T, N>, &'a mut Array<T, Diff<U, N>>);
impl<T, U> Array<T, U>
where
U: ArraySize,
{
pub fn from_fn<F>(cb: F) -> Self
where
F: FnMut(usize) -> T,
{
Self(FromFn::from_fn(cb))
}
#[inline]
pub fn iter(&self) -> Iter<'_, T> {
self.as_ref().iter()
}
#[inline]
pub fn iter_mut(&mut self) -> IterMut<'_, T> {
self.as_mut().iter_mut()
}
#[inline]
pub fn as_slice(&self) -> &[T] {
self.0.as_ref()
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [T] {
self.0.as_mut()
}
#[inline]
pub fn ref_from_slice(slice: &[T]) -> &Self {
slice.try_into().expect("slice length mismatch")
}
#[inline]
pub fn ref_from_mut_slice(slice: &mut [T]) -> &mut Self {
slice.try_into().expect("slice length mismatch")
}
#[inline]
pub fn clone_from_slice(slice: &[T]) -> Self
where
Self: Clone,
{
slice.try_into().expect("slice length mismatch")
}
#[inline]
pub fn concat<N>(self, other: Array<T, N>) -> Array<T, Sum<U, N>>
where
N: ArraySize,
U: Add<N>,
Sum<U, N>: ArraySize,
{
let mut result = MaybeUninit::uninit();
let result_ptr = result.as_mut_ptr() as *mut Self;
unsafe {
ptr::write(result_ptr, self);
ptr::write(result_ptr.add(1) as *mut _, other);
result.assume_init()
}
}
#[inline]
pub fn split<N>(self) -> SplitResult<T, U, N>
where
U: Sub<N>,
N: ArraySize,
Diff<U, N>: ArraySize,
{
unsafe {
let array = ManuallyDrop::new(self);
let head = ptr::read(array.as_ptr() as *const _);
let tail = ptr::read(array.as_ptr().add(N::USIZE) as *const _);
(head, tail)
}
}
#[inline]
pub fn split_ref<N>(&self) -> SplitRefResult<'_, T, U, N>
where
U: Sub<N>,
N: ArraySize,
Diff<U, N>: ArraySize,
{
unsafe {
let array_ptr = self.as_ptr();
let head = &*(array_ptr as *const _);
let tail = &*(array_ptr.add(N::USIZE) as *const _);
(head, tail)
}
}
#[inline]
pub fn split_ref_mut<N>(&mut self) -> SplitRefMutResult<'_, T, U, N>
where
U: Sub<N>,
N: ArraySize,
Diff<U, N>: ArraySize,
{
unsafe {
let array_ptr = self.as_mut_ptr();
let head = &mut *(array_ptr as *mut _);
let tail = &mut *(array_ptr.add(N::USIZE) as *mut _);
(head, tail)
}
}
}
impl<T, U> AsRef<[T]> for Array<T, U>
where
U: ArraySize,
{
#[inline]
fn as_ref(&self) -> &[T] {
self.0.as_ref()
}
}
impl<T, U> AsMut<[T]> for Array<T, U>
where
U: ArraySize,
{
#[inline]
fn as_mut(&mut self) -> &mut [T] {
self.0.as_mut()
}
}
impl<T, U> Borrow<[T]> for Array<T, U>
where
U: ArraySize,
{
#[inline]
fn borrow(&self) -> &[T] {
self.0.as_ref()
}
}
impl<T, U, const N: usize> Borrow<[T; N]> for Array<T, U>
where
Self: ArrayOps<T, N>,
U: ArraySize,
{
#[inline]
fn borrow(&self) -> &[T; N] {
self.as_core_array()
}
}
impl<T, U> BorrowMut<[T]> for Array<T, U>
where
U: ArraySize,
{
#[inline]
fn borrow_mut(&mut self) -> &mut [T] {
self.0.as_mut()
}
}
impl<T, U, const N: usize> BorrowMut<[T; N]> for Array<T, U>
where
Self: ArrayOps<T, N>,
U: ArraySize,
{
#[inline]
fn borrow_mut(&mut self) -> &mut [T; N] {
self.as_mut_core_array()
}
}
impl<T, U> Clone for Array<T, U>
where
T: Clone,
U: ArraySize,
{
fn clone(&self) -> Self {
Self::from_fn(|n| self.0.as_ref()[n].clone())
}
}
impl<T, U> Copy for Array<T, U>
where
T: Copy,
U: ArraySize,
U::ArrayType<T>: Copy,
{
}
impl<T, U> Debug for Array<T, U>
where
T: Debug,
U: ArraySize,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Array").field(&self.0.as_ref()).finish()
}
}
impl<T, U> Default for Array<T, U>
where
T: Default,
U: ArraySize,
{
fn default() -> Self {
Self::from_fn(|_| Default::default())
}
}
impl<T, U> Deref for Array<T, U>
where
U: ArraySize,
{
type Target = [T];
#[inline]
fn deref(&self) -> &[T] {
self.0.as_ref()
}
}
impl<T, U> DerefMut for Array<T, U>
where
U: ArraySize,
{
#[inline]
fn deref_mut(&mut self) -> &mut [T] {
self.0.as_mut()
}
}
impl<T, U> Eq for Array<T, U>
where
T: Eq,
U: ArraySize,
{
}
impl<T, U, const N: usize> From<[T; N]> for Array<T, U>
where
Self: ArrayOps<T, N>,
U: ArraySize,
{
#[inline]
fn from(arr: [T; N]) -> Array<T, U> {
Self::from_core_array(arr)
}
}
impl<T, U, const N: usize> From<Array<T, U>> for [T; N]
where
Array<T, U>: ArrayOps<T, N>,
U: ArraySize<ArrayType<T> = [T; N]>,
{
#[inline]
fn from(arr: Array<T, U>) -> [T; N] {
arr.0
}
}
impl<'a, T, U, const N: usize> From<&'a [T; N]> for &'a Array<T, U>
where
Array<T, U>: ArrayOps<T, N>,
U: ArraySize,
{
#[inline]
fn from(array_ref: &'a [T; N]) -> &'a Array<T, U> {
<Array<T, U>>::ref_from_core_array(array_ref)
}
}
impl<'a, T, U, const N: usize> From<&'a Array<T, U>> for &'a [T; N]
where
Array<T, U>: ArrayOps<T, N>,
U: ArraySize,
{
#[inline]
fn from(array_ref: &'a Array<T, U>) -> &'a [T; N] {
array_ref.as_core_array()
}
}
impl<'a, T, U, const N: usize> From<&'a mut [T; N]> for &'a mut Array<T, U>
where
Array<T, U>: ArrayOps<T, N>,
U: ArraySize,
{
#[inline]
fn from(array_ref: &'a mut [T; N]) -> &'a mut Array<T, U> {
<Array<T, U>>::ref_from_mut_core_array(array_ref)
}
}
impl<'a, T, U, const N: usize> From<&'a mut Array<T, U>> for &'a mut [T; N]
where
Array<T, U>: ArrayOps<T, N>,
U: ArraySize,
{
#[inline]
fn from(array_ref: &'a mut Array<T, U>) -> &'a mut [T; N] {
array_ref.as_mut_core_array()
}
}
impl<T, U> Hash for Array<T, U>
where
T: Hash,
U: ArraySize,
{
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.as_ref().hash(state);
}
}
impl<T, I, U> Index<I> for Array<T, U>
where
[T]: Index<I>,
U: ArraySize,
{
type Output = <[T] as Index<I>>::Output;
#[inline]
fn index(&self, index: I) -> &Self::Output {
Index::index(self.as_slice(), index)
}
}
impl<T, I, U> IndexMut<I> for Array<T, U>
where
[T]: IndexMut<I>,
U: ArraySize,
{
#[inline]
fn index_mut(&mut self, index: I) -> &mut Self::Output {
IndexMut::index_mut(self.as_mut_slice(), index)
}
}
impl<T, U> IntoIterator for Array<T, U>
where
U: ArraySize,
{
type Item = T;
type IntoIter = <U::ArrayType<T> as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'a, T, U> IntoIterator for &'a Array<T, U>
where
U: ArraySize,
{
type Item = &'a T;
type IntoIter = Iter<'a, T>;
fn into_iter(self) -> Iter<'a, T> {
self.iter()
}
}
impl<'a, T, U> IntoIterator for &'a mut Array<T, U>
where
U: ArraySize,
{
type Item = &'a mut T;
type IntoIter = IterMut<'a, T>;
#[inline]
fn into_iter(self) -> IterMut<'a, T> {
self.iter_mut()
}
}
impl<T, U> PartialEq for Array<T, U>
where
T: PartialEq,
U: ArraySize,
{
fn eq(&self, other: &Self) -> bool {
self.0.as_ref().eq(other.0.as_ref())
}
}
impl<T, U, const N: usize> PartialEq<[T; N]> for Array<T, U>
where
T: PartialEq,
U: ArraySize<ArrayType<T> = [T; N]>,
{
fn eq(&self, other: &[T; N]) -> bool {
self.0.eq(other)
}
}
impl<T, U, const N: usize> PartialEq<Array<T, U>> for [T; N]
where
T: PartialEq,
U: ArraySize<ArrayType<T> = [T; N]>,
{
fn eq(&self, other: &Array<T, U>) -> bool {
self.eq(&other.0)
}
}
impl<T, U> PartialOrd for Array<T, U>
where
T: PartialOrd,
U: ArraySize,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.0.as_ref().partial_cmp(other.0.as_ref())
}
}
impl<T, U> Ord for Array<T, U>
where
T: Ord,
U: ArraySize,
{
fn cmp(&self, other: &Self) -> Ordering {
self.0.as_ref().cmp(other.0.as_ref())
}
}
impl<'a, T, U> TryFrom<&'a [T]> for Array<T, U>
where
Self: Clone,
U: ArraySize,
{
type Error = TryFromSliceError;
#[inline]
fn try_from(slice: &'a [T]) -> Result<Array<T, U>, TryFromSliceError> {
<&'a Self>::try_from(slice).map(Clone::clone)
}
}
impl<'a, T, U> TryFrom<&'a [T]> for &'a Array<T, U>
where
U: ArraySize,
{
type Error = TryFromSliceError;
#[inline]
fn try_from(slice: &'a [T]) -> Result<Self, TryFromSliceError> {
check_slice_length::<T, U>(slice)?;
Ok(unsafe { &*(slice.as_ptr() as *const Array<T, U>) })
}
}
impl<'a, T, U> TryFrom<&'a mut [T]> for &'a mut Array<T, U>
where
U: ArraySize,
{
type Error = TryFromSliceError;
#[inline]
fn try_from(slice: &'a mut [T]) -> Result<Self, TryFromSliceError> {
check_slice_length::<T, U>(slice)?;
Ok(unsafe { &mut *(slice.as_ptr() as *mut Array<T, U>) })
}
}
#[cfg(feature = "zeroize")]
impl<T, U> Zeroize for Array<T, U>
where
T: Zeroize,
U: ArraySize,
{
fn zeroize(&mut self) {
self.0.as_mut().iter_mut().zeroize()
}
}
#[cfg(feature = "zeroize")]
impl<T, U> ZeroizeOnDrop for Array<T, U>
where
T: ZeroizeOnDrop,
U: ArraySize,
{
}
#[cfg_attr(debug_assertions, allow(clippy::panic_in_result_fn))]
fn check_slice_length<T, U: ArraySize>(slice: &[T]) -> Result<(), TryFromSliceError> {
debug_assert_eq!(Array::<(), U>::default().len(), U::USIZE);
if slice.len() != U::USIZE {
<&[T; 1]>::try_from([].as_slice())?;
#[cfg(debug_assertions)]
unreachable!();
}
Ok(())
}
pub trait ArrayOps<T, const N: usize>:
Borrow<[T; N]>
+ BorrowMut<[T; N]>
+ From<[T; N]>
+ FromFn<T>
+ Into<[T; N]>
+ IntoIterator<Item = T>
+ Sized
+ SliceOps<T>
{
const SIZE: usize;
fn as_core_array(&self) -> &[T; N];
fn as_mut_core_array(&mut self) -> &mut [T; N];
fn from_core_array(arr: [T; N]) -> Self;
fn ref_from_core_array(arr: &[T; N]) -> &Self;
fn ref_from_mut_core_array(arr: &mut [T; N]) -> &mut Self;
fn map_to_core_array<F, U>(self, f: F) -> [U; N]
where
F: FnMut(T) -> U;
}
impl<T, const N: usize> ArrayOps<T, N> for [T; N] {
const SIZE: usize = N;
#[inline]
fn as_core_array(&self) -> &[T; N] {
self
}
#[inline]
fn as_mut_core_array(&mut self) -> &mut [T; N] {
self
}
#[inline]
fn from_core_array(arr: [T; N]) -> Self {
arr
}
#[inline]
fn ref_from_core_array(array_ref: &[T; N]) -> &Self {
array_ref
}
#[inline]
fn ref_from_mut_core_array(array_ref: &mut [T; N]) -> &mut Self {
array_ref
}
#[inline]
fn map_to_core_array<F, U>(self, f: F) -> [U; N]
where
F: FnMut(T) -> U,
{
self.map(f)
}
}
pub trait SliceOps<T>:
AsRef<[T]>
+ AsMut<[T]>
+ Borrow<[T]>
+ BorrowMut<[T]>
+ Index<usize>
+ Index<Range<usize>>
+ IndexMut<usize>
+ IndexMut<Range<usize>>
{
fn as_array_chunks<N: ArraySize>(&self) -> (&[Array<T, N>], &[T]) {
slice_as_chunks(self.as_ref())
}
fn as_array_chunks_mut<N: ArraySize>(&mut self) -> (&mut [Array<T, N>], &mut [T]) {
slice_as_chunks_mut(self.as_mut())
}
}
impl<T> SliceOps<T> for [T] {}
impl<T, const N: usize> SliceOps<T> for [T; N] {}
impl<T, U: ArraySize> SliceOps<T> for Array<T, U> {}
pub unsafe trait ArraySize: Unsigned {
type ArrayType<T>: AssociatedArraySize<Size = Self>
+ From<Array<T, Self>>
+ FromFn<T>
+ Into<Array<T, Self>>
+ IntoIterator<Item = T>
+ SliceOps<T>;
}
pub trait AssociatedArraySize: Sized {
type Size: ArraySize;
}
impl<T, U> AssociatedArraySize for Array<T, U>
where
U: ArraySize,
{
type Size = U;
}
pub trait FromFn<T>: Sized {
fn from_fn<F>(cb: F) -> Self
where
F: FnMut(usize) -> T;
}
impl<T, U> FromFn<T> for Array<T, U>
where
U: ArraySize,
{
fn from_fn<F>(cb: F) -> Self
where
F: FnMut(usize) -> T,
{
Array::from_fn(cb)
}
}
impl<T, const N: usize> FromFn<T> for [T; N] {
fn from_fn<F>(cb: F) -> Self
where
F: FnMut(usize) -> T,
{
core::array::from_fn(cb)
}
}
#[allow(clippy::arithmetic_side_effects)]
pub fn slice_as_chunks<T, N: ArraySize>(buf: &[T]) -> (&[Array<T, N>], &[T]) {
assert_ne!(N::USIZE, 0, "chunk size must be non-zero");
let chunks_len = buf.len() / N::USIZE;
let tail_pos = N::USIZE * chunks_len;
let tail_len = buf.len() - tail_pos;
unsafe {
let ptr = buf.as_ptr();
let chunks = slice::from_raw_parts(ptr as *const Array<T, N>, chunks_len);
let tail = slice::from_raw_parts(ptr.add(tail_pos), tail_len);
(chunks, tail)
}
}
#[allow(clippy::arithmetic_side_effects)]
pub fn slice_as_chunks_mut<T, N: ArraySize>(buf: &mut [T]) -> (&mut [Array<T, N>], &mut [T]) {
assert_ne!(N::USIZE, 0, "chunk size must be non-zero");
let chunks_len = buf.len() / N::USIZE;
let tail_pos = N::USIZE * chunks_len;
let tail_len = buf.len() - tail_pos;
unsafe {
let ptr = buf.as_mut_ptr();
let chunks = slice::from_raw_parts_mut(ptr as *mut Array<T, N>, chunks_len);
let tail = slice::from_raw_parts_mut(ptr.add(tail_pos), tail_len);
(chunks, tail)
}
}