#![deny(missing_docs)]
#![deny(meta_variable_misuse)]
#![no_std]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
pub extern crate typenum;
#[doc(hidden)]
#[cfg(feature = "alloc")]
pub extern crate alloc;
mod hex;
mod impls;
mod iter;
#[cfg(feature = "alloc")]
mod impl_alloc;
#[cfg(feature = "const-default")]
mod impl_const_default;
#[cfg(feature = "serde")]
mod impl_serde;
#[cfg(feature = "zeroize")]
mod impl_zeroize;
use core::iter::FromIterator;
use core::marker::PhantomData;
use core::mem::{ManuallyDrop, MaybeUninit};
use core::ops::{Deref, DerefMut};
use core::{mem, ptr, slice};
use typenum::bit::{B0, B1};
use typenum::generic_const_mappings::{Const, ToUInt};
use typenum::uint::{UInt, UTerm, Unsigned};
#[doc(hidden)]
#[cfg_attr(test, macro_use)]
pub mod arr;
pub mod functional;
pub mod sequence;
mod internal;
use internal::{ArrayConsumer, IntrusiveArrayBuilder, Sealed};
#[cfg(feature = "internals")]
pub mod internals {
pub use crate::internal::{ArrayBuilder, ArrayConsumer, IntrusiveArrayBuilder};
}
use self::functional::*;
use self::sequence::*;
pub use self::iter::GenericArrayIter;
pub unsafe trait ArrayLength: Unsigned + 'static {
type ArrayType<T>: Sealed;
}
unsafe impl ArrayLength for UTerm {
#[doc(hidden)]
type ArrayType<T> = [T; 0];
}
pub trait IntoArrayLength {
type ArrayLength: ArrayLength;
}
impl<const N: usize> IntoArrayLength for Const<N>
where
Const<N>: ToUInt,
typenum::U<N>: ArrayLength,
{
type ArrayLength = typenum::U<N>;
}
impl<N> IntoArrayLength for N
where
N: ArrayLength,
{
type ArrayLength = Self;
}
pub type ConstArrayLength<const N: usize> = <Const<N> as IntoArrayLength>::ArrayLength;
#[allow(dead_code)]
#[repr(C)]
#[doc(hidden)]
pub struct GenericArrayImplEven<T, U> {
parent1: U,
parent2: U,
_marker: PhantomData<T>,
}
#[allow(dead_code)]
#[repr(C)]
#[doc(hidden)]
pub struct GenericArrayImplOdd<T, U> {
parent1: U,
parent2: U,
data: T,
}
impl<T: Clone, U: Clone> Clone for GenericArrayImplEven<T, U> {
#[inline(always)]
fn clone(&self) -> GenericArrayImplEven<T, U> {
unsafe { core::hint::unreachable_unchecked() }
}
}
impl<T: Clone, U: Clone> Clone for GenericArrayImplOdd<T, U> {
#[inline(always)]
fn clone(&self) -> GenericArrayImplOdd<T, U> {
unsafe { core::hint::unreachable_unchecked() }
}
}
impl<T: Copy, U: Copy> Copy for GenericArrayImplEven<T, U> {}
impl<T: Copy, U: Copy> Copy for GenericArrayImplOdd<T, U> {}
impl<T, U> Sealed for GenericArrayImplEven<T, U> {}
impl<T, U> Sealed for GenericArrayImplOdd<T, U> {}
unsafe impl<N: ArrayLength> ArrayLength for UInt<N, B0> {
#[doc(hidden)]
type ArrayType<T> = GenericArrayImplEven<T, N::ArrayType<T>>;
}
unsafe impl<N: ArrayLength> ArrayLength for UInt<N, B1> {
#[doc(hidden)]
type ArrayType<T> = GenericArrayImplOdd<T, N::ArrayType<T>>;
}
#[repr(transparent)]
pub struct GenericArray<T, N: ArrayLength> {
#[allow(dead_code)] data: N::ArrayType<T>,
}
unsafe impl<T: Send, N: ArrayLength> Send for GenericArray<T, N> {}
unsafe impl<T: Sync, N: ArrayLength> Sync for GenericArray<T, N> {}
impl<T, N: ArrayLength> Deref for GenericArray<T, N> {
type Target = [T];
#[inline(always)]
fn deref(&self) -> &[T] {
GenericArray::as_slice(self)
}
}
impl<T, N: ArrayLength> DerefMut for GenericArray<T, N> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut [T] {
GenericArray::as_mut_slice(self)
}
}
impl<'a, T: 'a, N: ArrayLength> IntoIterator for &'a GenericArray<T, N> {
type IntoIter = slice::Iter<'a, T>;
type Item = &'a T;
fn into_iter(self: &'a GenericArray<T, N>) -> Self::IntoIter {
self.as_slice().iter()
}
}
impl<'a, T: 'a, N: ArrayLength> IntoIterator for &'a mut GenericArray<T, N> {
type IntoIter = slice::IterMut<'a, T>;
type Item = &'a mut T;
fn into_iter(self: &'a mut GenericArray<T, N>) -> Self::IntoIter {
self.as_mut_slice().iter_mut()
}
}
impl<T, N: ArrayLength> FromIterator<T> for GenericArray<T, N> {
#[inline]
fn from_iter<I>(iter: I) -> GenericArray<T, N>
where
I: IntoIterator<Item = T>,
{
match Self::try_from_iter(iter) {
Ok(res) => res,
Err(_) => from_iter_length_fail(N::USIZE),
}
}
}
#[inline(never)]
#[cold]
pub(crate) fn from_iter_length_fail(length: usize) -> ! {
panic!("GenericArray::from_iter expected {length} items");
}
unsafe impl<T, N: ArrayLength> GenericSequence<T> for GenericArray<T, N>
where
Self: IntoIterator<Item = T>,
{
type Length = N;
type Sequence = Self;
#[inline(always)]
fn generate<F>(mut f: F) -> GenericArray<T, N>
where
F: FnMut(usize) -> T,
{
unsafe {
let mut array = GenericArray::<T, N>::uninit();
let mut builder = IntrusiveArrayBuilder::new(&mut array);
{
let (builder_iter, position) = builder.iter_position();
builder_iter.enumerate().for_each(|(i, dst)| {
dst.write(f(i));
*position += 1;
});
}
builder.finish();
IntrusiveArrayBuilder::array_assume_init(array)
}
}
#[inline(always)]
fn inverted_zip<B, U, F>(
self,
lhs: GenericArray<B, Self::Length>,
mut f: F,
) -> MappedSequence<GenericArray<B, Self::Length>, B, U>
where
GenericArray<B, Self::Length>:
GenericSequence<B, Length = Self::Length> + MappedGenericSequence<B, U>,
Self: MappedGenericSequence<T, U>,
F: FnMut(B, Self::Item) -> U,
{
unsafe {
if mem::needs_drop::<T>() || mem::needs_drop::<B>() {
let mut left = ArrayConsumer::new(lhs);
let mut right = ArrayConsumer::new(self);
let (left_array_iter, left_position) = left.iter_position();
let (right_array_iter, right_position) = right.iter_position();
FromIterator::from_iter(left_array_iter.zip(right_array_iter).map(|(l, r)| {
let left_value = ptr::read(l);
let right_value = ptr::read(r);
*left_position += 1;
*right_position = *left_position;
f(left_value, right_value)
}))
} else {
let left = ManuallyDrop::new(lhs);
let right = ManuallyDrop::new(self);
FromIterator::from_iter(left.iter().zip(right.iter()).map(|(l, r)| {
f(ptr::read(l), ptr::read(r)) }))
}
}
}
#[inline(always)]
fn inverted_zip2<B, Lhs, U, F>(self, lhs: Lhs, mut f: F) -> MappedSequence<Lhs, B, U>
where
Lhs: GenericSequence<B, Length = Self::Length> + MappedGenericSequence<B, U>,
Self: MappedGenericSequence<T, U>,
F: FnMut(Lhs::Item, Self::Item) -> U,
{
unsafe {
if mem::needs_drop::<T>() {
let mut right = ArrayConsumer::new(self);
let (right_array_iter, right_position) = right.iter_position();
FromIterator::from_iter(right_array_iter.zip(lhs).map(|(r, left_value)| {
let right_value = ptr::read(r);
*right_position += 1;
f(left_value, right_value)
}))
} else {
let right = ManuallyDrop::new(self);
FromIterator::from_iter(right.iter().zip(lhs).map(|(r, left_value)| {
f(left_value, ptr::read(r)) }))
}
}
}
}
impl<T, U, N: ArrayLength> MappedGenericSequence<T, U> for GenericArray<T, N>
where
GenericArray<U, N>: GenericSequence<U, Length = N>,
{
type Mapped = GenericArray<U, N>;
}
impl<T, N: ArrayLength> FunctionalSequence<T> for GenericArray<T, N>
where
Self: GenericSequence<T, Item = T, Length = N>,
{
#[inline(always)]
fn map<U, F>(self, mut f: F) -> MappedSequence<Self, T, U>
where
Self: MappedGenericSequence<T, U>,
F: FnMut(T) -> U,
{
unsafe {
let mut source = ArrayConsumer::new(self);
let (array_iter, position) = source.iter_position();
FromIterator::from_iter(array_iter.map(|src| {
let value = ptr::read(src);
*position += 1;
f(value)
}))
}
}
#[inline(always)]
fn zip<B, Rhs, U, F>(self, rhs: Rhs, f: F) -> MappedSequence<Self, T, U>
where
Self: MappedGenericSequence<T, U>,
Rhs: MappedGenericSequence<B, U, Mapped = MappedSequence<Self, T, U>>,
Rhs: GenericSequence<B, Length = Self::Length>,
F: FnMut(T, Rhs::Item) -> U,
{
rhs.inverted_zip(self, f)
}
#[inline(always)]
fn fold<U, F>(self, init: U, mut f: F) -> U
where
F: FnMut(U, T) -> U,
{
unsafe {
let mut source = ArrayConsumer::new(self);
let (array_iter, position) = source.iter_position();
array_iter.fold(init, |acc, src| {
let value = ptr::read(src);
*position += 1;
f(acc, value)
})
}
}
}
impl<T, N: ArrayLength> GenericArray<T, N> {
pub const fn len() -> usize {
N::USIZE
}
#[inline(always)]
pub const fn as_slice(&self) -> &[T] {
unsafe { slice::from_raw_parts(self as *const Self as *const T, N::USIZE) }
}
#[inline(always)]
pub const fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { slice::from_raw_parts_mut(self as *mut Self as *mut T, N::USIZE) }
}
#[inline(always)]
pub const fn from_slice(slice: &[T]) -> &GenericArray<T, N> {
if slice.len() != N::USIZE {
panic!("slice.len() != N in GenericArray::from_slice");
}
unsafe { &*(slice.as_ptr() as *const GenericArray<T, N>) }
}
#[inline(always)]
pub const fn try_from_slice(slice: &[T]) -> Result<&GenericArray<T, N>, LengthError> {
if slice.len() != N::USIZE {
return Err(LengthError);
}
Ok(unsafe { &*(slice.as_ptr() as *const GenericArray<T, N>) })
}
#[inline(always)]
pub const fn from_mut_slice(slice: &mut [T]) -> &mut GenericArray<T, N> {
assert!(
slice.len() == N::USIZE,
"slice.len() != N in GenericArray::from_mut_slice"
);
unsafe { &mut *(slice.as_mut_ptr() as *mut GenericArray<T, N>) }
}
#[inline(always)]
pub const fn try_from_mut_slice(
slice: &mut [T],
) -> Result<&mut GenericArray<T, N>, LengthError> {
match slice.len() == N::USIZE {
true => Ok(GenericArray::from_mut_slice(slice)),
false => Err(LengthError),
}
}
pub const fn chunks_from_slice(slice: &[T]) -> (&[GenericArray<T, N>], &[T]) {
if N::USIZE == 0 {
assert!(slice.is_empty(), "GenericArray length N must be non-zero");
return (&[], &[]);
}
let num_chunks = slice.len() / N::USIZE; let num_in_chunks = num_chunks * N::USIZE;
let num_remainder = slice.len() - num_in_chunks;
unsafe {
(
slice::from_raw_parts(slice.as_ptr() as *const GenericArray<T, N>, num_chunks),
slice::from_raw_parts(slice.as_ptr().add(num_in_chunks), num_remainder),
)
}
}
pub const fn chunks_from_slice_mut(slice: &mut [T]) -> (&mut [GenericArray<T, N>], &mut [T]) {
if N::USIZE == 0 {
assert!(slice.is_empty(), "GenericArray length N must be non-zero");
return (&mut [], &mut []);
}
let num_chunks = slice.len() / N::USIZE; let num_in_chunks = num_chunks * N::USIZE;
let num_remainder = slice.len() - num_in_chunks;
unsafe {
(
slice::from_raw_parts_mut(
slice.as_mut_ptr() as *mut GenericArray<T, N>,
num_chunks,
),
slice::from_raw_parts_mut(slice.as_mut_ptr().add(num_in_chunks), num_remainder),
)
}
}
#[inline(always)]
pub const fn slice_from_chunks(slice: &[GenericArray<T, N>]) -> &[T] {
unsafe { slice::from_raw_parts(slice.as_ptr() as *const T, slice.len() * N::USIZE) }
}
#[inline(always)]
pub const fn slice_from_chunks_mut(slice: &mut [GenericArray<T, N>]) -> &mut [T] {
unsafe { slice::from_raw_parts_mut(slice.as_mut_ptr() as *mut T, slice.len() * N::USIZE) }
}
#[inline(always)]
pub const fn from_array<const U: usize>(value: [T; U]) -> Self
where
Const<U>: IntoArrayLength<ArrayLength = N>,
{
unsafe { crate::const_transmute(value) }
}
#[inline(always)]
pub const fn into_array<const U: usize>(self) -> [T; U]
where
Const<U>: IntoArrayLength<ArrayLength = N>,
{
unsafe { crate::const_transmute(self) }
}
#[inline(always)]
pub const fn from_chunks<const U: usize>(chunks: &[[T; U]]) -> &[GenericArray<T, N>]
where
Const<U>: IntoArrayLength<ArrayLength = N>,
{
unsafe { mem::transmute(chunks) }
}
#[inline(always)]
pub const fn from_chunks_mut<const U: usize>(chunks: &mut [[T; U]]) -> &mut [GenericArray<T, N>]
where
Const<U>: IntoArrayLength<ArrayLength = N>,
{
unsafe { mem::transmute(chunks) }
}
#[inline(always)]
pub const fn into_chunks<const U: usize>(chunks: &[GenericArray<T, N>]) -> &[[T; U]]
where
Const<U>: IntoArrayLength<ArrayLength = N>,
{
unsafe { mem::transmute(chunks) }
}
#[inline(always)]
pub const fn into_chunks_mut<const U: usize>(chunks: &mut [GenericArray<T, N>]) -> &mut [[T; U]]
where
Const<U>: IntoArrayLength<ArrayLength = N>,
{
unsafe { mem::transmute(chunks) }
}
}
impl<T, N: ArrayLength> GenericArray<T, N> {
#[inline(always)]
#[allow(clippy::uninit_assumed_init)]
pub const fn uninit() -> GenericArray<MaybeUninit<T>, N> {
unsafe {
MaybeUninit::<GenericArray<MaybeUninit<T>, N>>::uninit().assume_init()
}
}
#[inline(always)]
pub const unsafe fn assume_init(array: GenericArray<MaybeUninit<T>, N>) -> Self {
const_transmute::<_, MaybeUninit<GenericArray<T, N>>>(array).assume_init()
}
}
#[derive(Debug, Clone, Copy)]
pub struct LengthError;
impl core::fmt::Display for LengthError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("LengthError: Slice or iterator does not match GenericArray length")
}
}
impl<'a, T, N: ArrayLength> TryFrom<&'a [T]> for &'a GenericArray<T, N> {
type Error = LengthError;
#[inline(always)]
fn try_from(slice: &'a [T]) -> Result<Self, Self::Error> {
GenericArray::try_from_slice(slice)
}
}
impl<'a, T, N: ArrayLength> TryFrom<&'a mut [T]> for &'a mut GenericArray<T, N> {
type Error = LengthError;
#[inline(always)]
fn try_from(slice: &'a mut [T]) -> Result<Self, Self::Error> {
GenericArray::try_from_mut_slice(slice)
}
}
impl<T, N: ArrayLength> GenericArray<T, N> {
#[inline]
pub fn try_from_iter<I>(iter: I) -> Result<Self, LengthError>
where
I: IntoIterator<Item = T>,
{
let mut iter = iter.into_iter();
match iter.size_hint() {
(n, _) if n > N::USIZE => return Err(LengthError),
(_, Some(n)) if n < N::USIZE => return Err(LengthError),
_ => {}
}
unsafe {
let mut array = GenericArray::uninit();
let mut builder = IntrusiveArrayBuilder::new(&mut array);
builder.extend(&mut iter);
if !builder.is_full() || iter.next().is_some() {
return Err(LengthError);
}
Ok({
builder.finish();
IntrusiveArrayBuilder::array_assume_init(array)
})
}
}
}
#[inline(always)]
#[cfg_attr(not(feature = "internals"), doc(hidden))]
pub const unsafe fn const_transmute<A, B>(a: A) -> B {
if mem::size_of::<A>() != mem::size_of::<B>() {
panic!("Size mismatch for generic_array::const_transmute");
}
#[repr(C)]
union Union<A, B> {
a: ManuallyDrop<A>,
b: ManuallyDrop<B>,
}
let a = ManuallyDrop::new(a);
ManuallyDrop::into_inner(Union { a }.b)
}
#[cfg(test)]
mod test {
#[inline(never)]
pub fn black_box<T>(val: T) -> T {
use core::{mem, ptr};
let ret = unsafe { ptr::read_volatile(&val) };
mem::forget(val);
ret
}
#[test]
fn test_assembly() {
use crate::functional::*;
let a = black_box(arr![1, 3, 5, 7]);
let b = black_box(arr![2, 4, 6, 8]);
let c = (&a).zip(b, |l, r| l + r);
let d = a.fold(0, |a, x| a + x);
assert_eq!(c, arr![3, 7, 11, 15]);
assert_eq!(d, 16);
}
}