#![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::{IntoIter, TryFromSliceError},
borrow::{Borrow, BorrowMut},
cmp::Ordering,
fmt::{self, Debug},
hash::{Hash, Hasher},
ops::{Deref, DerefMut, Index, IndexMut, Range},
slice::{Iter, IterMut},
};
use typenum::Unsigned;
#[repr(transparent)]
pub struct Array<T, U: ArraySize>(pub U::ArrayType<T>);
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]
fn iter(&self) -> Iter<'_, T> {
self.as_ref().iter()
}
#[inline]
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()
}
}
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> 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 type ByteArray<U> = Array<u8, U>;
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>;
}
pub trait IntoArray<T> {
type Size: ArraySize;
fn into_hybrid_array(self) -> Array<T, Self::Size>;
}
macro_rules! impl_array_size {
($($len:expr => $ty:ident),+) => {
$(
impl<T> ArrayOps<T, $len> for Array<T, typenum::$ty> {
const SIZE: usize = $len;
type Size = typenum::$ty;
#[inline]
fn as_core_array(&self) -> &[T; $len] {
&self.0
}
#[inline]
fn as_mut_core_array(&mut self) -> &mut [T; $len] {
&mut self.0
}
#[inline]
fn from_core_array(arr: [T; $len]) -> Self {
Self(arr)
}
#[inline]
fn ref_from_core_array(array_ref: &[T; $len]) -> &Self {
unsafe { &*(array_ref.as_ptr() as *const Self) }
}
#[inline]
fn ref_from_mut_core_array(array_ref: &mut [T; $len]) -> &mut Self {
unsafe { &mut *(array_ref.as_mut_ptr() as *mut Self) }
}
#[inline]
fn map_to_core_array<F, U>(self, f: F) -> [U; $len]
where
F: FnMut(T) -> U
{
self.0.map(f)
}
}
unsafe impl ArraySize for typenum::$ty {
type ArrayType<T> = [T; $len];
}
impl<T> IntoArray<T> for [T; $len] {
type Size = typenum::$ty;
fn into_hybrid_array(self) -> Array<T, Self::Size> {
Array::from_core_array(self)
}
}
impl<T> IntoIterator for Array<T, typenum::$ty> {
type Item = T;
type IntoIter = IntoIter<T, $len>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'a, T> IntoIterator for &'a Array<T, typenum::$ty> {
type Item = &'a T;
type IntoIter = Iter<'a, T>;
fn into_iter(self) -> Iter<'a, T> {
self.iter()
}
}
impl<'a, T> IntoIterator for &'a mut Array<T, typenum::$ty> {
type Item = &'a mut T;
type IntoIter = IterMut<'a, T>;
#[inline]
fn into_iter(self) -> IterMut<'a, T> {
self.iter_mut()
}
}
)+
};
}
impl_array_size! {
0 => U0,
1 => U1,
2 => U2,
3 => U3,
4 => U4,
5 => U5,
6 => U6,
7 => U7,
8 => U8,
9 => U9,
10 => U10,
11 => U11,
12 => U12,
13 => U13,
14 => U14,
15 => U15,
16 => U16,
17 => U17,
18 => U18,
19 => U19,
20 => U20,
21 => U21,
22 => U22,
23 => U23,
24 => U24,
25 => U25,
26 => U26,
27 => U27,
28 => U28,
29 => U29,
30 => U30,
31 => U31,
32 => U32,
33 => U33,
34 => U34,
35 => U35,
36 => U36,
37 => U37,
38 => U38,
39 => U39,
40 => U40,
41 => U41,
42 => U42,
43 => U43,
44 => U44,
45 => U45,
46 => U46,
47 => U47,
48 => U48,
49 => U49,
50 => U50,
51 => U51,
52 => U52,
53 => U53,
54 => U54,
55 => U55,
56 => U56,
57 => U57,
58 => U58,
59 => U59,
60 => U60,
61 => U61,
62 => U62,
63 => U63,
64 => U64,
96 => U96,
128 => U128,
192 => U192,
256 => U256,
384 => U384,
448 => U448,
512 => U512,
768 => U768,
896 => U896,
1024 => U1024,
2048 => U2048,
4096 => U4096,
8192 => U8192
}
#[cfg(test)]
mod tests {
use super::ByteArray;
use crate::Array;
use typenum::{U0, U3, U6, U7};
const EXAMPLE_SLICE: &[u8] = &[1, 2, 3, 4, 5, 6];
#[test]
fn clone_from_slice() {
let array = Array::<u8, U6>::clone_from_slice(EXAMPLE_SLICE);
assert_eq!(array.as_slice(), EXAMPLE_SLICE);
}
#[test]
fn tryfrom_slice_for_array() {
assert!(ByteArray::<U0>::try_from(EXAMPLE_SLICE).is_err());
assert!(ByteArray::<U3>::try_from(EXAMPLE_SLICE).is_err());
let array_ref = ByteArray::<U6>::try_from(EXAMPLE_SLICE).expect("slice contains 6 bytes");
assert_eq!(&*array_ref, EXAMPLE_SLICE);
assert!(ByteArray::<U7>::try_from(EXAMPLE_SLICE).is_err());
}
#[test]
fn tryfrom_slice_for_array_ref() {
assert!(<&ByteArray<U0>>::try_from(EXAMPLE_SLICE).is_err());
assert!(<&ByteArray::<U3>>::try_from(EXAMPLE_SLICE).is_err());
let array_ref = <&ByteArray<U6>>::try_from(EXAMPLE_SLICE).expect("slice contains 6 bytes");
assert_eq!(array_ref.as_slice(), EXAMPLE_SLICE);
assert!(<&ByteArray::<U7>>::try_from(EXAMPLE_SLICE).is_err());
}
}