#![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
)]
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};
mod impls;
#[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(ArrayExt::from_fn(cb))
}
pub fn from_slice(slice: &[T]) -> Result<Self, TryFromSliceError>
where
T: Copy,
{
ArrayExt::from_slice(slice).map(Self)
}
#[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,
{
Self::ref_from_slice(slice).clone()
}
#[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, const N: usize> AsRef<[T; N]> for Array<T, U>
where
Self: ArrayOps<T, N>,
U: ArraySize,
{
#[inline]
fn as_ref(&self) -> &[T; N] {
self.as_core_array()
}
}
impl<T, U, const N: usize> AsMut<[T; N]> for Array<T, U>
where
Self: ArrayOps<T, N>,
U: ArraySize,
{
#[inline]
fn as_mut(&mut self) -> &mut [T; N] {
self.as_mut_core_array()
}
}
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, 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(U::ArrayType::<T>::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(ArrayExt::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<'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 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<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> 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
T: Copy,
U: ArraySize,
{
type Error = TryFromSliceError;
#[inline]
fn try_from(slice: &'a [T]) -> Result<Array<T, U>, TryFromSliceError> {
ArrayExt::from_slice(slice).map(Self)
}
}
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_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>:
AsRef<[T; N]>
+ AsMut<[T; N]>
+ Borrow<[T; N]>
+ BorrowMut<[T; N]>
+ From<[T; N]>
+ Index<usize>
+ Index<Range<usize>>
+ IndexMut<usize>
+ IndexMut<Range<usize>>
+ IntoIterator
+ Sized
{
const SIZE: usize;
type Size: ArraySize;
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;
}
pub trait ArrayExt<T>: Sized {
fn from_fn<F>(cb: F) -> Self
where
F: FnMut(usize) -> T;
fn from_slice(slice: &[T]) -> Result<Self, TryFromSliceError>
where
T: Copy;
}
impl<T, const N: usize> ArrayExt<T> for [T; N] {
fn from_fn<F>(mut cb: F) -> Self
where
F: FnMut(usize) -> T,
{
let mut idx = 0;
[(); N].map(|_| {
let res = cb(idx);
idx = idx.saturating_add(1); res
})
}
fn from_slice(slice: &[T]) -> Result<Self, TryFromSliceError>
where
T: Copy,
{
slice.try_into()
}
}
pub unsafe trait ArraySize: Unsigned {
type ArrayType<T>: ArrayExt<T> + AsRef<[T]> + AsMut<[T]> + IntoArray<T> + IntoIterator<Item = T>;
}
pub trait IntoArray<T> {
type Size: ArraySize;
fn into_hybrid_array(self) -> Array<T, Self::Size>;
}
#[allow(clippy::arithmetic_side_effects)]
pub fn slice_as_chunks<T, N: ArraySize>(buf: &[T]) -> (&[Array<T, N>], &[T]) {
assert!(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!(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)
}
}