hybrid_array/
lib.rs

1#![no_std]
2#![cfg_attr(docsrs, feature(doc_auto_cfg))]
3#![doc = include_str!("../README.md")]
4#![doc(
5    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
6    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
7)]
8#![warn(
9    clippy::arithmetic_side_effects,
10    clippy::cast_lossless,
11    clippy::cast_possible_truncation,
12    clippy::cast_possible_wrap,
13    clippy::cast_precision_loss,
14    clippy::cast_sign_loss,
15    clippy::checked_conversions,
16    clippy::from_iter_instead_of_collect,
17    clippy::missing_errors_doc,
18    clippy::mod_module_files,
19    clippy::implicit_saturating_sub,
20    clippy::panic,
21    clippy::panic_in_result_fn,
22    clippy::unwrap_used,
23    missing_docs,
24    missing_debug_implementations,
25    trivial_casts,
26    trivial_numeric_casts,
27    unused_lifetimes,
28    unused_qualifications
29)]
30
31//! ## Features
32//!
33//! This crate exposes the following feature flags. The default is NO features.
34//!
35//! - `bytemuck`: impls the `Pod` and `Zeroable` traits
36//! - `serde`: impls the `Deserialize` and `Serialize` traits for `Array`
37//! - `zeroize`: impls [`Zeroize`](https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html) for `Array<T: Zeroize, U>`
38//!
39//! ## Usage
40//!
41//! The two core types in this crate are as follows:
42//!
43//! - [`Array<T, U>`]: wrapper for `[T; N]` where `U` is an [`ArraySize`] provided by [`typenum`]
44//!   whose associated [`ArraySize::ArrayType<T>`] determines the inner array size.
45//! - [`ArrayN<T, N>`]: type alias for [`Array`] which is const generic around `const N: usize`.
46//!   This provides a linkage between const generics and [`typenum`].
47//!
48//! The [`Array`] type has an inner `pub [T; N]` field, which means writing a literal can be
49//! expressed as follows:
50//!
51//! ```
52//! use hybrid_array::{Array, sizes::U4};
53//!
54//! let arr: Array<u8, U4> = Array([1, 2, 3, 4]);
55//! ```
56//!
57//! ### About [`typenum`]
58//!
59//! The [`typenum`] crate provides a type-level implementation of numbers and arithmetic operations.
60//!
61//! While [`typenum`] can be used to express arbitrary integers using the type system, the
62//! `hybrid-array` crate is limited to the array sizes in the [`sizes`] module, which have
63//! names like [`U0`][`sizes::U0`], [`U1`][`sizes::U1`], [`U2`][`sizes::U2`], [`U3`][`sizes::U3`],
64//! etc. All supported sizes will have an impl of [`ArraySize`], which is the trait providing
65//! linkage between [`typenum`]-based types and core arrays / const generics.
66//!
67//! [`ArraySize`] bounds on the [`typenum::Unsigned`] trait, which can be used to obtain integer
68//! sizes of arrays via associated constants. For example, to obtain the size of an `ArraySize` as
69//! a `usize`, use the associated [`typenum::Unsigned::USIZE`] constant.
70//!
71//! ### [`AsArrayRef`] and [`AsArrayMut`] traits
72//!
73//! These traits simplify obtaining references to [`Array`] and are impl'd for both [`Array`]
74//! and `[T; N]`. They're analogous to traits like [`AsRef`] and [`AsMut`].
75//!
76//! They make it possible to write code which uses `[T; N]` or `&[T; N]` in the external facing
77//! API which can obtain references to `&Array` and call other functions which accept such
78//! references, without the caller having to use `Array` in their code and while still supporting
79//! generic sizes.
80//!
81//! For more information and a code example, see [`AsArrayRef`].
82//!
83//! ## Relationship with `generic-array`
84//!
85//! `hybrid-array` is directly inspired by the [`generic-array`] crate.
86//!
87//! However, where `generic-array` predates const generics and uses a core which is built
88//! on `unsafe` code, `hybrid-array`'s core implementation is built on safe code and const
89//! generic implementations. This allows the inner `[T; N]` field of an `Array` to be `pub` as
90//! noted above, and in general for the implementation to be significantly simpler, easier-to-audit,
91//! and with significantly less use of `unsafe`.
92//!
93//! The only places `hybrid-array` uses unsafe are where it is absolutely necessary, primarily
94//! for reference conversions between `Array<T, U>` and `[T; N]`, and also to provide features
95//! which are not yet stable in `core`/`std`, such as [`Array::try_from_fn`].
96//!
97//! [`generic-array`]: https://docs.rs/generic-array
98//!
99//! ## Migrating from `generic-array`
100//!
101//! *NOTE: this guide assumes a migration from `generic-array` v0.14*
102//!
103//! `hybrid-array` has been designed to largely be a drop-in replacement for
104//! `generic-array`, albeit with a public inner array type and significantly less
105//! `unsafe` code.
106//!
107//! The bulk of the migration work can be accomplished by making the following find/replace-style
108//! substitutions in your `.rs` files:
109//!
110//! - Replace `generic_array` with `hybrid_array`
111//! - Replace `GenericArray<T, U>` with `Array<T, U>`
112//! - Replace `ArrayLength<T>` with `ArraySize`
113//! - Replace usages of the `Concat` and `Split` traits with [`Array::concat`] and [`Array::split`]
114//! - Replace `<U as ArrayLength<T>>::ArrayType` with `<U as ArraySize>::ArrayType<T>`
115//! - Replace usages of the `arr![N; A, B, C]` macro with `Array([A, B, C])`
116//!
117//! If you have any questions, please
118//! [start a discussion](https://github.com/RustCrypto/hybrid-array/discussions).
119
120#[cfg(feature = "alloc")]
121extern crate alloc;
122
123pub mod sizes;
124
125mod from_fn;
126mod iter;
127mod traits;
128
129#[cfg(feature = "serde")]
130mod serde;
131
132pub use crate::{iter::TryFromIteratorError, traits::*};
133pub use typenum;
134
135use core::{
136    array::TryFromSliceError,
137    borrow::{Borrow, BorrowMut},
138    cmp::Ordering,
139    fmt::{self, Debug},
140    hash::{Hash, Hasher},
141    mem::{self, ManuallyDrop, MaybeUninit},
142    ops::{Add, Deref, DerefMut, Index, IndexMut, Sub},
143    ptr,
144    slice::{self, Iter, IterMut},
145};
146use typenum::{Diff, Sum};
147
148#[cfg(feature = "bytemuck")]
149use bytemuck::{Pod, Zeroable};
150
151#[cfg(feature = "subtle")]
152use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
153
154#[cfg(feature = "zeroize")]
155use zeroize::{Zeroize, ZeroizeOnDrop};
156
157/// Type alias for [`Array`] which is const generic around a size `N`, ala `[T; N]`.
158pub type ArrayN<T, const N: usize> = Array<T, <[T; N] as AssocArraySize>::Size>;
159
160/// [`Array`] is a newtype for an inner `[T; N]` array where `N` is determined by a generic
161/// [`ArraySize`] parameter, which is a marker trait for a numeric value determined by ZSTs that
162/// impl the [`typenum::Unsigned`] trait.
163///
164/// The inner `[T; N]` field is `pub` which means it's possible to write [`Array`] literals like:
165///
166/// [`Array`] is defined as `repr(transparent)`, meaning it can be used anywhere an appropriately
167/// sized `[T; N]` type is used in unsafe code / FFI.
168///
169/// ```
170/// use hybrid_array::{Array, sizes::U3};
171///
172/// let arr: Array<u8, U3> = Array([1, 2, 3]);
173/// ```
174#[repr(transparent)]
175pub struct Array<T, U: ArraySize>(pub U::ArrayType<T>);
176
177type SplitResult<T, U, N> = (Array<T, N>, Array<T, Diff<U, N>>);
178type SplitRefResult<'a, T, U, N> = (&'a Array<T, N>, &'a Array<T, Diff<U, N>>);
179type SplitRefMutResult<'a, T, U, N> = (&'a mut Array<T, N>, &'a mut Array<T, Diff<U, N>>);
180
181impl<T, U> Array<T, U>
182where
183    U: ArraySize,
184{
185    /// Returns a slice containing the entire array. Equivalent to `&s[..]`.
186    #[inline]
187    pub fn as_slice(&self) -> &[T] {
188        self.0.as_ref()
189    }
190
191    /// Returns a mutable slice containing the entire array. Equivalent to `&mut s[..]`.
192    #[inline]
193    pub fn as_mut_slice(&mut self) -> &mut [T] {
194        self.0.as_mut()
195    }
196
197    /// Returns an iterator over the array.
198    #[inline]
199    pub fn iter(&self) -> Iter<'_, T> {
200        self.as_slice().iter()
201    }
202
203    /// Returns an iterator that allows modifying each value.
204    #[inline]
205    pub fn iter_mut(&mut self) -> IterMut<'_, T> {
206        self.as_mut().iter_mut()
207    }
208
209    /// Returns an array of the same size as `self`, with function `f` applied to each element in
210    /// order.
211    pub fn map<F, O>(self, f: F) -> Array<O, U>
212    where
213        F: FnMut(T) -> O,
214    {
215        self.into_iter().map(f).collect()
216    }
217
218    /// Concatenates `self` with `other`.
219    #[inline]
220    pub fn concat<N>(self, other: Array<T, N>) -> Array<T, Sum<U, N>>
221    where
222        N: ArraySize,
223        U: Add<N>,
224        Sum<U, N>: ArraySize,
225    {
226        let mut c = Array::uninit();
227        let (left, right) = c.split_at_mut(self.len());
228        for (val, dst) in self.into_iter().zip(left) {
229            dst.write(val);
230        }
231        for (val, dst) in other.into_iter().zip(right) {
232            dst.write(val);
233        }
234        // SAFETY: We wrote to every element of `c`.
235        unsafe { c.assume_init() }
236    }
237
238    /// Splits `self` at index `N` in two arrays.
239    ///
240    /// New arrays hold the original memory from `self`.
241    #[inline]
242    pub fn split<N>(self) -> SplitResult<T, U, N>
243    where
244        U: Sub<N>,
245        N: ArraySize,
246        Diff<U, N>: ArraySize,
247    {
248        unsafe {
249            let array = ManuallyDrop::new(self);
250            let head = ptr::read(array.as_ptr().cast());
251            let tail = ptr::read(array.as_ptr().add(N::USIZE).cast());
252            (head, tail)
253        }
254    }
255
256    /// Splits `&self` at index `N` in two array references.
257    #[inline]
258    pub fn split_ref<N>(&self) -> SplitRefResult<'_, T, U, N>
259    where
260        U: Sub<N>,
261        N: ArraySize,
262        Diff<U, N>: ArraySize,
263    {
264        unsafe {
265            let array_ptr = self.as_ptr();
266            let head = &*array_ptr.cast();
267            let tail = &*array_ptr.add(N::USIZE).cast();
268            (head, tail)
269        }
270    }
271
272    /// Splits `&mut self` at index `N` in two mutable array references.
273    #[inline]
274    pub fn split_ref_mut<N>(&mut self) -> SplitRefMutResult<'_, T, U, N>
275    where
276        U: Sub<N>,
277        N: ArraySize,
278        Diff<U, N>: ArraySize,
279    {
280        unsafe {
281            let array_ptr = self.as_mut_ptr();
282            let head = &mut *array_ptr.cast();
283            let tail = &mut *array_ptr.add(N::USIZE).cast();
284            (head, tail)
285        }
286    }
287
288    /// Splits the shared slice into a slice of `U`-element arrays, starting at the beginning
289    /// of the slice, and a remainder slice with length strictly less than `U`.
290    ///
291    /// # Panics
292    /// Panics if `U` is 0.
293    #[allow(clippy::arithmetic_side_effects)]
294    #[inline]
295    pub const fn slice_as_chunks(buf: &[T]) -> (&[Self], &[T]) {
296        assert!(U::USIZE != 0, "chunk size must be non-zero");
297        // Arithmetic safety: we have checked that `N::USIZE` is not zero, thus
298        // division always returns correct result. `tail_pos` can not be bigger than `buf.len()`,
299        // thus overflow on multiplication and underflow on substraction are impossible.
300        let chunks_len = buf.len() / U::USIZE;
301        let tail_pos = U::USIZE * chunks_len;
302        let tail_len = buf.len() - tail_pos;
303        unsafe {
304            let ptr = buf.as_ptr();
305            let chunks = slice::from_raw_parts(ptr.cast(), chunks_len);
306            let tail = slice::from_raw_parts(ptr.add(tail_pos), tail_len);
307            (chunks, tail)
308        }
309    }
310
311    /// Splits the exclusive slice into a slice of `U`-element arrays, starting at the beginning
312    /// of the slice, and a remainder slice with length strictly less than `U`.
313    ///
314    /// # Panics
315    /// Panics if `U` is 0.
316    #[allow(clippy::arithmetic_side_effects)]
317    #[inline]
318    pub const fn slice_as_chunks_mut(buf: &mut [T]) -> (&mut [Self], &mut [T]) {
319        assert!(U::USIZE != 0, "chunk size must be non-zero");
320        // Arithmetic safety: we have checked that `N::USIZE` is not zero, thus
321        // division always returns correct result. `tail_pos` can not be bigger than `buf.len()`,
322        // thus overflow on multiplication and underflow on substraction are impossible.
323        let chunks_len = buf.len() / U::USIZE;
324        let tail_pos = U::USIZE * chunks_len;
325        let tail_len = buf.len() - tail_pos;
326        unsafe {
327            let ptr = buf.as_mut_ptr();
328            let chunks = slice::from_raw_parts_mut(ptr.cast(), chunks_len);
329            let tail = slice::from_raw_parts_mut(ptr.add(tail_pos), tail_len);
330            (chunks, tail)
331        }
332    }
333
334    /// Convert the given slice into a reference to a hybrid array.
335    ///
336    /// # Panics
337    ///
338    /// Panics if the slice's length doesn't match the array type.
339    #[deprecated(since = "0.2.0", note = "use `TryFrom` instead")]
340    #[inline]
341    pub fn from_slice(slice: &[T]) -> &Self {
342        slice.try_into().expect("slice length mismatch")
343    }
344
345    /// Convert the given mutable slice to a mutable reference to a hybrid array.
346    ///
347    /// # Panics
348    ///
349    /// Panics if the slice's length doesn't match the array type.
350    #[deprecated(since = "0.2.0", note = "use `TryFrom` instead")]
351    #[inline]
352    pub fn from_mut_slice(slice: &mut [T]) -> &mut Self {
353        slice.try_into().expect("slice length mismatch")
354    }
355
356    /// Clone the contents of the slice as a new hybrid array.
357    ///
358    /// # Panics
359    ///
360    /// Panics if the slice's length doesn't match the array type.
361    #[deprecated(since = "0.2.0", note = "use `TryFrom` instead")]
362    #[inline]
363    pub fn clone_from_slice(slice: &[T]) -> Self
364    where
365        Self: Clone,
366    {
367        slice.try_into().expect("slice length mismatch")
368    }
369}
370
371// Impls which depend on the inner array type being `[T; N]`.
372impl<T, U, const N: usize> Array<T, U>
373where
374    U: ArraySize<ArrayType<T> = [T; N]>,
375{
376    /// Transform slice to slice of core array type.
377    #[inline]
378    pub const fn cast_slice_to_core(slice: &[Self]) -> &[[T; N]] {
379        // SAFETY: `Self` is a `repr(transparent)` newtype for `[T; N]`
380        unsafe { slice::from_raw_parts(slice.as_ptr().cast(), slice.len()) }
381    }
382
383    /// Transform mutable slice to mutable slice of core array type.
384    #[inline]
385    pub const fn cast_slice_to_core_mut(slice: &mut [Self]) -> &mut [[T; N]] {
386        // SAFETY: `Self` is a `repr(transparent)` newtype for `[T; N]`
387        unsafe { slice::from_raw_parts_mut(slice.as_mut_ptr().cast(), slice.len()) }
388    }
389
390    /// Transform slice to slice of core array type.
391    #[inline]
392    pub const fn cast_slice_from_core(slice: &[[T; N]]) -> &[Self] {
393        // SAFETY: `Self` is a `repr(transparent)` newtype for `[T; N]`
394        unsafe { slice::from_raw_parts(slice.as_ptr().cast(), slice.len()) }
395    }
396
397    /// Transform mutable slice to mutable slice of core array type.
398    #[inline]
399    pub const fn cast_slice_from_core_mut(slice: &mut [[T; N]]) -> &mut [Self] {
400        // SAFETY: `Self` is a `repr(transparent)` newtype for `[T; N]`
401        unsafe { slice::from_raw_parts_mut(slice.as_mut_ptr().cast(), slice.len()) }
402    }
403
404    /// Obtain a flattened slice from a slice of array chunks.
405    #[inline]
406    pub fn slice_as_flattened(slice: &[Self]) -> &[T] {
407        Self::cast_slice_to_core(slice).as_flattened()
408    }
409
410    /// Obtain a mutable flattened slice from a mutable slice of array chunks.
411    #[inline]
412    pub fn slice_as_flattened_mut(slice: &mut [Self]) -> &mut [T] {
413        Self::cast_slice_to_core_mut(slice).as_flattened_mut()
414    }
415}
416
417impl<T, U> Array<MaybeUninit<T>, U>
418where
419    U: ArraySize,
420{
421    /// Create an uninitialized array of [`MaybeUninit`]s for the given type.
422    pub const fn uninit() -> Array<MaybeUninit<T>, U> {
423        // SAFETY: `Array` is a `repr(transparent)` newtype for `[MaybeUninit<T>, N]`, i.e. an
424        // array of uninitialized memory mediated via the `MaybeUninit` interface, where the inner
425        // type is constrained by `ArraySize` impls which can only be added by this crate.
426        //
427        // Calling `uninit().assume_init()` triggers the `clippy::uninit_assumed_init` lint, but
428        // as just mentioned the inner type we're "assuming init" for is `[MaybeUninit<T>, N]`,
429        // i.e. an array of uninitialized memory, which is always valid because definitionally no
430        // initialization is required of uninitialized memory.
431        #[allow(clippy::uninit_assumed_init)]
432        Self(unsafe { MaybeUninit::uninit().assume_init() })
433    }
434
435    /// Extract the values from an array of `MaybeUninit` containers.
436    ///
437    /// # Safety
438    ///
439    /// It is up to the caller to guarantee that all elements of the array are in an initialized
440    /// state.
441    #[inline]
442    pub unsafe fn assume_init(self) -> Array<T, U> {
443        unsafe {
444            // `Array` is a `repr(transparent)` newtype for a generic inner type which is constrained to
445            // be `[T; N]` by the `ArraySize` impls in this crate.
446            //
447            // Since we're working with a type-erased inner type and ultimately trying to convert
448            // `[MaybeUninit<T>; N]` to `[T; N]`, we can't use simpler approaches like a pointer cast
449            // or `transmute`, since the compiler can't prove to itself that the size will be the same.
450            //
451            // We've taken unique ownership of `self`, which is a `MaybeUninit` array, and as such we
452            // don't need to worry about `Drop` impls because `MaybeUninit` does not impl `Drop`.
453            // Since we have unique ownership of `self`, it's okay to make a copy because we're throwing
454            // the original away (and this should all get optimized to a noop by the compiler, anyway).
455            mem::transmute_copy(&self)
456        }
457    }
458}
459
460impl<T, U> AsRef<Array<T, U>> for Array<T, U>
461where
462    U: ArraySize,
463{
464    #[inline]
465    fn as_ref(&self) -> &Self {
466        self
467    }
468}
469
470impl<T, U> AsRef<[T]> for Array<T, U>
471where
472    U: ArraySize,
473{
474    #[inline]
475    fn as_ref(&self) -> &[T] {
476        self.0.as_ref()
477    }
478}
479
480impl<T, U, const N: usize> AsRef<[T; N]> for Array<T, U>
481where
482    U: ArraySize<ArrayType<T> = [T; N]>,
483{
484    #[inline]
485    fn as_ref(&self) -> &[T; N] {
486        &self.0
487    }
488}
489
490impl<T, U> AsMut<[T]> for Array<T, U>
491where
492    U: ArraySize,
493{
494    #[inline]
495    fn as_mut(&mut self) -> &mut [T] {
496        self.0.as_mut()
497    }
498}
499
500impl<T, U, const N: usize> AsMut<[T; N]> for Array<T, U>
501where
502    U: ArraySize<ArrayType<T> = [T; N]>,
503{
504    #[inline]
505    fn as_mut(&mut self) -> &mut [T; N] {
506        &mut self.0
507    }
508}
509
510impl<T, U> Borrow<[T]> for Array<T, U>
511where
512    U: ArraySize,
513{
514    #[inline]
515    fn borrow(&self) -> &[T] {
516        self.0.as_ref()
517    }
518}
519
520impl<T, U, const N: usize> Borrow<[T; N]> for Array<T, U>
521where
522    U: ArraySize<ArrayType<T> = [T; N]>,
523{
524    #[inline]
525    fn borrow(&self) -> &[T; N] {
526        &self.0
527    }
528}
529
530impl<T, U> BorrowMut<[T]> for Array<T, U>
531where
532    U: ArraySize,
533{
534    #[inline]
535    fn borrow_mut(&mut self) -> &mut [T] {
536        self.0.as_mut()
537    }
538}
539
540impl<T, U, const N: usize> BorrowMut<[T; N]> for Array<T, U>
541where
542    U: ArraySize<ArrayType<T> = [T; N]>,
543{
544    #[inline]
545    fn borrow_mut(&mut self) -> &mut [T; N] {
546        &mut self.0
547    }
548}
549
550impl<T, U> Clone for Array<T, U>
551where
552    T: Clone,
553    U: ArraySize,
554{
555    #[inline]
556    fn clone(&self) -> Self {
557        Self::from_fn(|n| self.0.as_ref()[n].clone())
558    }
559}
560
561impl<T, U> Copy for Array<T, U>
562where
563    T: Copy,
564    U: ArraySize,
565    U::ArrayType<T>: Copy,
566{
567}
568
569impl<T, U> Debug for Array<T, U>
570where
571    T: Debug,
572    U: ArraySize,
573{
574    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
575        f.debug_tuple("Array").field(&self.0.as_ref()).finish()
576    }
577}
578
579impl<T, U> Default for Array<T, U>
580where
581    T: Default,
582    U: ArraySize,
583{
584    #[inline]
585    fn default() -> Self {
586        Self::from_fn(|_| Default::default())
587    }
588}
589
590impl<T, U> Deref for Array<T, U>
591where
592    U: ArraySize,
593{
594    type Target = [T];
595
596    #[inline]
597    fn deref(&self) -> &[T] {
598        self.0.as_ref()
599    }
600}
601
602impl<T, U> DerefMut for Array<T, U>
603where
604    U: ArraySize,
605{
606    #[inline]
607    fn deref_mut(&mut self) -> &mut [T] {
608        self.0.as_mut()
609    }
610}
611
612impl<T, U> Eq for Array<T, U>
613where
614    T: Eq,
615    U: ArraySize,
616{
617}
618
619impl<T, U, const N: usize> From<[T; N]> for Array<T, U>
620where
621    U: ArraySize<ArrayType<T> = [T; N]>,
622{
623    #[inline]
624    fn from(arr: [T; N]) -> Array<T, U> {
625        Array(arr)
626    }
627}
628
629impl<T, U, const N: usize> From<Array<T, U>> for [T; N]
630where
631    U: ArraySize<ArrayType<T> = [T; N]>,
632{
633    #[inline]
634    fn from(arr: Array<T, U>) -> [T; N] {
635        arr.0
636    }
637}
638
639impl<'a, T, U, const N: usize> From<&'a [T; N]> for &'a Array<T, U>
640where
641    U: ArraySize<ArrayType<T> = [T; N]>,
642{
643    #[inline]
644    fn from(array_ref: &'a [T; N]) -> &'a Array<T, U> {
645        // SAFETY: `Self` is a `repr(transparent)` newtype for `[T; $len]`
646        unsafe { &*array_ref.as_ptr().cast() }
647    }
648}
649
650impl<'a, T, U, const N: usize> From<&'a Array<T, U>> for &'a [T; N]
651where
652    U: ArraySize<ArrayType<T> = [T; N]>,
653{
654    #[inline]
655    fn from(array_ref: &'a Array<T, U>) -> &'a [T; N] {
656        array_ref.as_ref()
657    }
658}
659
660impl<'a, T, U, const N: usize> From<&'a mut [T; N]> for &'a mut Array<T, U>
661where
662    U: ArraySize<ArrayType<T> = [T; N]>,
663{
664    #[inline]
665    fn from(array_ref: &'a mut [T; N]) -> &'a mut Array<T, U> {
666        // SAFETY: `Self` is a `repr(transparent)` newtype for `[T; $len]`
667        unsafe { &mut *array_ref.as_mut_ptr().cast() }
668    }
669}
670
671impl<'a, T, U, const N: usize> From<&'a mut Array<T, U>> for &'a mut [T; N]
672where
673    U: ArraySize<ArrayType<T> = [T; N]>,
674{
675    #[inline]
676    fn from(array_ref: &'a mut Array<T, U>) -> &'a mut [T; N] {
677        array_ref.as_mut()
678    }
679}
680
681#[cfg(feature = "alloc")]
682impl<T, U> From<Array<T, U>> for alloc::boxed::Box<[T]>
683where
684    U: ArraySize,
685{
686    #[inline]
687    fn from(array: Array<T, U>) -> alloc::boxed::Box<[T]> {
688        array.into_iter().collect()
689    }
690}
691
692#[cfg(feature = "alloc")]
693impl<T, U> From<&Array<T, U>> for alloc::boxed::Box<[T]>
694where
695    T: Clone,
696    U: ArraySize,
697{
698    #[inline]
699    fn from(array: &Array<T, U>) -> alloc::boxed::Box<[T]> {
700        array.as_slice().into()
701    }
702}
703
704#[cfg(feature = "alloc")]
705impl<T, U> From<Array<T, U>> for alloc::vec::Vec<T>
706where
707    U: ArraySize,
708{
709    #[inline]
710    fn from(array: Array<T, U>) -> alloc::vec::Vec<T> {
711        array.into_iter().collect()
712    }
713}
714
715#[cfg(feature = "alloc")]
716impl<T, U> From<&Array<T, U>> for alloc::vec::Vec<T>
717where
718    T: Clone,
719    U: ArraySize,
720{
721    #[inline]
722    fn from(array: &Array<T, U>) -> alloc::vec::Vec<T> {
723        array.as_slice().into()
724    }
725}
726
727impl<T, U> Hash for Array<T, U>
728where
729    T: Hash,
730    U: ArraySize,
731{
732    #[inline]
733    fn hash<H: Hasher>(&self, state: &mut H) {
734        self.0.as_ref().hash(state);
735    }
736}
737
738impl<T, I, U> Index<I> for Array<T, U>
739where
740    [T]: Index<I>,
741    U: ArraySize,
742{
743    type Output = <[T] as Index<I>>::Output;
744
745    #[inline]
746    fn index(&self, index: I) -> &Self::Output {
747        Index::index(self.as_slice(), index)
748    }
749}
750
751impl<T, I, U> IndexMut<I> for Array<T, U>
752where
753    [T]: IndexMut<I>,
754    U: ArraySize,
755{
756    #[inline]
757    fn index_mut(&mut self, index: I) -> &mut Self::Output {
758        IndexMut::index_mut(self.as_mut_slice(), index)
759    }
760}
761
762impl<T, U> PartialEq for Array<T, U>
763where
764    T: PartialEq,
765    U: ArraySize,
766{
767    #[inline]
768    fn eq(&self, other: &Self) -> bool {
769        self.0.as_ref().eq(other.0.as_ref())
770    }
771}
772
773impl<T, U, const N: usize> PartialEq<[T; N]> for Array<T, U>
774where
775    T: PartialEq,
776    U: ArraySize<ArrayType<T> = [T; N]>,
777{
778    #[inline]
779    fn eq(&self, other: &[T; N]) -> bool {
780        self.0.eq(other)
781    }
782}
783
784impl<T, U, const N: usize> PartialEq<Array<T, U>> for [T; N]
785where
786    T: PartialEq,
787    U: ArraySize<ArrayType<T> = [T; N]>,
788{
789    #[inline]
790    fn eq(&self, other: &Array<T, U>) -> bool {
791        self.eq(&other.0)
792    }
793}
794
795impl<T, U> PartialOrd for Array<T, U>
796where
797    T: PartialOrd,
798    U: ArraySize,
799{
800    #[inline]
801    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
802        self.0.as_ref().partial_cmp(other.0.as_ref())
803    }
804}
805
806impl<T, U> Ord for Array<T, U>
807where
808    T: Ord,
809    U: ArraySize,
810{
811    #[inline]
812    fn cmp(&self, other: &Self) -> Ordering {
813        self.0.as_ref().cmp(other.0.as_ref())
814    }
815}
816
817/// SAFETY: `Array` is a `repr(transparent)` newtype for `[T; N]`, so as long as `T: Send` it should
818/// also be `Send`.
819unsafe impl<T, U: ArraySize> Send for Array<T, U> where T: Send {}
820
821/// SAFETY: `Array` is a `repr(transparent)` newtype for `[T; N]`, so as long as `T: Sync` it should
822/// also be `Sync`.
823unsafe impl<T, U: ArraySize> Sync for Array<T, U> where T: Sync {}
824
825impl<'a, T, U> TryFrom<&'a [T]> for Array<T, U>
826where
827    Self: Clone,
828    U: ArraySize,
829{
830    type Error = TryFromSliceError;
831
832    #[inline]
833    fn try_from(slice: &'a [T]) -> Result<Array<T, U>, TryFromSliceError> {
834        <&'a Self>::try_from(slice).cloned()
835    }
836}
837
838#[cfg(feature = "alloc")]
839impl<T, U> TryFrom<alloc::boxed::Box<[T]>> for Array<T, U>
840where
841    Self: Clone,
842    U: ArraySize,
843{
844    type Error = TryFromSliceError;
845
846    #[inline]
847    fn try_from(b: alloc::boxed::Box<[T]>) -> Result<Self, TryFromSliceError> {
848        Self::try_from(&*b)
849    }
850}
851
852#[cfg(feature = "alloc")]
853impl<'a, T, U> TryFrom<&'a alloc::boxed::Box<[T]>> for Array<T, U>
854where
855    Self: Clone,
856    U: ArraySize,
857{
858    type Error = TryFromSliceError;
859
860    #[inline]
861    fn try_from(b: &'a alloc::boxed::Box<[T]>) -> Result<Self, TryFromSliceError> {
862        Self::try_from(&**b)
863    }
864}
865
866#[cfg(feature = "alloc")]
867impl<T, U> TryFrom<alloc::vec::Vec<T>> for Array<T, U>
868where
869    Self: Clone,
870    U: ArraySize,
871{
872    type Error = TryFromSliceError;
873
874    #[inline]
875    fn try_from(v: alloc::vec::Vec<T>) -> Result<Self, TryFromSliceError> {
876        Self::try_from(v.as_slice())
877    }
878}
879
880#[cfg(feature = "alloc")]
881impl<'a, T, U> TryFrom<&'a alloc::vec::Vec<T>> for Array<T, U>
882where
883    Self: Clone,
884    U: ArraySize,
885{
886    type Error = TryFromSliceError;
887
888    #[inline]
889    fn try_from(v: &'a alloc::vec::Vec<T>) -> Result<Self, TryFromSliceError> {
890        Self::try_from(v.as_slice())
891    }
892}
893
894impl<'a, T, U> TryFrom<&'a [T]> for &'a Array<T, U>
895where
896    U: ArraySize,
897{
898    type Error = TryFromSliceError;
899
900    #[inline]
901    fn try_from(slice: &'a [T]) -> Result<Self, TryFromSliceError> {
902        check_slice_length::<T, U>(slice)?;
903
904        // SAFETY: `Array<T, U>` is a `repr(transparent)` newtype for a core
905        // array with length checked above.
906        Ok(unsafe { &*slice.as_ptr().cast() })
907    }
908}
909
910impl<'a, T, U> TryFrom<&'a mut [T]> for &'a mut Array<T, U>
911where
912    U: ArraySize,
913{
914    type Error = TryFromSliceError;
915
916    #[inline]
917    fn try_from(slice: &'a mut [T]) -> Result<Self, TryFromSliceError> {
918        check_slice_length::<T, U>(slice)?;
919
920        // SAFETY: `Array<T, U>` is a `repr(transparent)` newtype for a core
921        // array with length checked above.
922        Ok(unsafe { &mut *slice.as_mut_ptr().cast() })
923    }
924}
925
926#[cfg(feature = "bytemuck")]
927unsafe impl<T, U> Pod for Array<T, U>
928where
929    T: Pod,
930    U: ArraySize,
931    U::ArrayType<T>: Copy,
932{
933}
934
935#[cfg(feature = "bytemuck")]
936unsafe impl<T, U> Zeroable for Array<T, U>
937where
938    T: Zeroable,
939    U: ArraySize,
940{
941}
942
943#[cfg(feature = "subtle")]
944impl<T, U> ConditionallySelectable for Array<T, U>
945where
946    Self: Copy,
947    T: ConditionallySelectable,
948    U: ArraySize,
949{
950    #[inline]
951    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
952        let mut output = *a;
953        output.conditional_assign(b, choice);
954        output
955    }
956
957    fn conditional_assign(&mut self, other: &Self, choice: Choice) {
958        for (a_i, b_i) in self.iter_mut().zip(other) {
959            a_i.conditional_assign(b_i, choice)
960        }
961    }
962}
963
964#[cfg(feature = "subtle")]
965impl<T, U> ConstantTimeEq for Array<T, U>
966where
967    T: ConstantTimeEq,
968    U: ArraySize,
969{
970    #[inline]
971    fn ct_eq(&self, other: &Self) -> Choice {
972        self.iter()
973            .zip(other.iter())
974            .fold(Choice::from(1), |acc, (a, b)| acc & a.ct_eq(b))
975    }
976}
977
978#[cfg(feature = "zeroize")]
979impl<T, U> Zeroize for Array<T, U>
980where
981    T: Zeroize,
982    U: ArraySize,
983{
984    #[inline]
985    fn zeroize(&mut self) {
986        self.0.as_mut().iter_mut().zeroize()
987    }
988}
989
990#[cfg(feature = "zeroize")]
991impl<T, U> ZeroizeOnDrop for Array<T, U>
992where
993    T: ZeroizeOnDrop,
994    U: ArraySize,
995{
996}
997
998/// Generate a [`TryFromSliceError`] if the slice doesn't match the given length.
999#[cfg_attr(debug_assertions, allow(clippy::panic_in_result_fn))]
1000fn check_slice_length<T, U: ArraySize>(slice: &[T]) -> Result<(), TryFromSliceError> {
1001    debug_assert_eq!(Array::<(), U>::default().len(), U::USIZE);
1002
1003    if slice.len() != U::USIZE {
1004        // Hack: `TryFromSliceError` lacks a public constructor
1005        <&[T; 1]>::try_from([].as_slice())?;
1006
1007        #[cfg(debug_assertions)]
1008        unreachable!();
1009    }
1010
1011    Ok(())
1012}