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 fn slice_as_chunks(buf: &[T]) -> (&[Self], &[T]) {
296        assert_ne!(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 fn slice_as_chunks_mut(buf: &mut [T]) -> (&mut [Self], &mut [T]) {
319        assert_ne!(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 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 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 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 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
405impl<T, U> Array<MaybeUninit<T>, U>
406where
407    U: ArraySize,
408{
409    /// Create an uninitialized array of [`MaybeUninit`]s for the given type.
410    pub const fn uninit() -> Array<MaybeUninit<T>, U> {
411        // SAFETY: `Array` is a `repr(transparent)` newtype for `[MaybeUninit<T>, N]`, i.e. an
412        // array of uninitialized memory mediated via the `MaybeUninit` interface, where the inner
413        // type is constrained by `ArraySize` impls which can only be added by this crate.
414        //
415        // Calling `uninit().assume_init()` triggers the `clippy::uninit_assumed_init` lint, but
416        // as just mentioned the inner type we're "assuming init" for is `[MaybeUninit<T>, N]`,
417        // i.e. an array of uninitialized memory, which is always valid because definitionally no
418        // initialization is required of uninitialized memory.
419        #[allow(clippy::uninit_assumed_init)]
420        Self(unsafe { MaybeUninit::uninit().assume_init() })
421    }
422
423    /// Extract the values from an array of `MaybeUninit` containers.
424    ///
425    /// # Safety
426    ///
427    /// It is up to the caller to guarantee that all elements of the array are in an initialized
428    /// state.
429    #[inline]
430    pub unsafe fn assume_init(self) -> Array<T, U> {
431        unsafe {
432            // `Array` is a `repr(transparent)` newtype for a generic inner type which is constrained to
433            // be `[T; N]` by the `ArraySize` impls in this crate.
434            //
435            // Since we're working with a type-erased inner type and ultimately trying to convert
436            // `[MaybeUninit<T>; N]` to `[T; N]`, we can't use simpler approaches like a pointer cast
437            // or `transmute`, since the compiler can't prove to itself that the size will be the same.
438            //
439            // We've taken unique ownership of `self`, which is a `MaybeUninit` array, and as such we
440            // don't need to worry about `Drop` impls because `MaybeUninit` does not impl `Drop`.
441            // Since we have unique ownership of `self`, it's okay to make a copy because we're throwing
442            // the original away (and this should all get optimized to a noop by the compiler, anyway).
443            mem::transmute_copy(&self)
444        }
445    }
446}
447
448impl<T, U> AsRef<Array<T, U>> for Array<T, U>
449where
450    U: ArraySize,
451{
452    #[inline]
453    fn as_ref(&self) -> &Self {
454        self
455    }
456}
457
458impl<T, U> AsRef<[T]> for Array<T, U>
459where
460    U: ArraySize,
461{
462    #[inline]
463    fn as_ref(&self) -> &[T] {
464        self.0.as_ref()
465    }
466}
467
468impl<T, U, const N: usize> AsRef<[T; N]> for Array<T, U>
469where
470    U: ArraySize<ArrayType<T> = [T; N]>,
471{
472    #[inline]
473    fn as_ref(&self) -> &[T; N] {
474        &self.0
475    }
476}
477
478impl<T, U> AsMut<[T]> for Array<T, U>
479where
480    U: ArraySize,
481{
482    #[inline]
483    fn as_mut(&mut self) -> &mut [T] {
484        self.0.as_mut()
485    }
486}
487
488impl<T, U, const N: usize> AsMut<[T; N]> for Array<T, U>
489where
490    U: ArraySize<ArrayType<T> = [T; N]>,
491{
492    #[inline]
493    fn as_mut(&mut self) -> &mut [T; N] {
494        &mut self.0
495    }
496}
497
498impl<T, U> Borrow<[T]> for Array<T, U>
499where
500    U: ArraySize,
501{
502    #[inline]
503    fn borrow(&self) -> &[T] {
504        self.0.as_ref()
505    }
506}
507
508impl<T, U, const N: usize> Borrow<[T; N]> for Array<T, U>
509where
510    U: ArraySize<ArrayType<T> = [T; N]>,
511{
512    #[inline]
513    fn borrow(&self) -> &[T; N] {
514        &self.0
515    }
516}
517
518impl<T, U> BorrowMut<[T]> for Array<T, U>
519where
520    U: ArraySize,
521{
522    #[inline]
523    fn borrow_mut(&mut self) -> &mut [T] {
524        self.0.as_mut()
525    }
526}
527
528impl<T, U, const N: usize> BorrowMut<[T; N]> for Array<T, U>
529where
530    U: ArraySize<ArrayType<T> = [T; N]>,
531{
532    #[inline]
533    fn borrow_mut(&mut self) -> &mut [T; N] {
534        &mut self.0
535    }
536}
537
538impl<T, U> Clone for Array<T, U>
539where
540    T: Clone,
541    U: ArraySize,
542{
543    #[inline]
544    fn clone(&self) -> Self {
545        Self::from_fn(|n| self.0.as_ref()[n].clone())
546    }
547}
548
549impl<T, U> Copy for Array<T, U>
550where
551    T: Copy,
552    U: ArraySize,
553    U::ArrayType<T>: Copy,
554{
555}
556
557impl<T, U> Debug for Array<T, U>
558where
559    T: Debug,
560    U: ArraySize,
561{
562    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
563        f.debug_tuple("Array").field(&self.0.as_ref()).finish()
564    }
565}
566
567impl<T, U> Default for Array<T, U>
568where
569    T: Default,
570    U: ArraySize,
571{
572    #[inline]
573    fn default() -> Self {
574        Self::from_fn(|_| Default::default())
575    }
576}
577
578impl<T, U> Deref for Array<T, U>
579where
580    U: ArraySize,
581{
582    type Target = [T];
583
584    #[inline]
585    fn deref(&self) -> &[T] {
586        self.0.as_ref()
587    }
588}
589
590impl<T, U> DerefMut for Array<T, U>
591where
592    U: ArraySize,
593{
594    #[inline]
595    fn deref_mut(&mut self) -> &mut [T] {
596        self.0.as_mut()
597    }
598}
599
600impl<T, U> Eq for Array<T, U>
601where
602    T: Eq,
603    U: ArraySize,
604{
605}
606
607impl<T, U, const N: usize> From<[T; N]> for Array<T, U>
608where
609    U: ArraySize<ArrayType<T> = [T; N]>,
610{
611    #[inline]
612    fn from(arr: [T; N]) -> Array<T, U> {
613        Array(arr)
614    }
615}
616
617impl<T, U, const N: usize> From<Array<T, U>> for [T; N]
618where
619    U: ArraySize<ArrayType<T> = [T; N]>,
620{
621    #[inline]
622    fn from(arr: Array<T, U>) -> [T; N] {
623        arr.0
624    }
625}
626
627impl<'a, T, U, const N: usize> From<&'a [T; N]> for &'a Array<T, U>
628where
629    U: ArraySize<ArrayType<T> = [T; N]>,
630{
631    #[inline]
632    fn from(array_ref: &'a [T; N]) -> &'a Array<T, U> {
633        // SAFETY: `Self` is a `repr(transparent)` newtype for `[T; $len]`
634        unsafe { &*array_ref.as_ptr().cast() }
635    }
636}
637
638impl<'a, T, U, const N: usize> From<&'a Array<T, U>> for &'a [T; N]
639where
640    U: ArraySize<ArrayType<T> = [T; N]>,
641{
642    #[inline]
643    fn from(array_ref: &'a Array<T, U>) -> &'a [T; N] {
644        array_ref.as_ref()
645    }
646}
647
648impl<'a, T, U, const N: usize> From<&'a mut [T; N]> for &'a mut Array<T, U>
649where
650    U: ArraySize<ArrayType<T> = [T; N]>,
651{
652    #[inline]
653    fn from(array_ref: &'a mut [T; N]) -> &'a mut Array<T, U> {
654        // SAFETY: `Self` is a `repr(transparent)` newtype for `[T; $len]`
655        unsafe { &mut *array_ref.as_mut_ptr().cast() }
656    }
657}
658
659impl<'a, T, U, const N: usize> From<&'a mut Array<T, U>> for &'a mut [T; N]
660where
661    U: ArraySize<ArrayType<T> = [T; N]>,
662{
663    #[inline]
664    fn from(array_ref: &'a mut Array<T, U>) -> &'a mut [T; N] {
665        array_ref.as_mut()
666    }
667}
668
669#[cfg(feature = "alloc")]
670impl<T, U> From<Array<T, U>> for alloc::boxed::Box<[T]>
671where
672    U: ArraySize,
673{
674    #[inline]
675    fn from(array: Array<T, U>) -> alloc::boxed::Box<[T]> {
676        array.into_iter().collect()
677    }
678}
679
680#[cfg(feature = "alloc")]
681impl<T, U> From<&Array<T, U>> for alloc::boxed::Box<[T]>
682where
683    T: Clone,
684    U: ArraySize,
685{
686    #[inline]
687    fn from(array: &Array<T, U>) -> alloc::boxed::Box<[T]> {
688        array.as_slice().into()
689    }
690}
691
692#[cfg(feature = "alloc")]
693impl<T, U> From<Array<T, U>> for alloc::vec::Vec<T>
694where
695    U: ArraySize,
696{
697    #[inline]
698    fn from(array: Array<T, U>) -> alloc::vec::Vec<T> {
699        array.into_iter().collect()
700    }
701}
702
703#[cfg(feature = "alloc")]
704impl<T, U> From<&Array<T, U>> for alloc::vec::Vec<T>
705where
706    T: Clone,
707    U: ArraySize,
708{
709    #[inline]
710    fn from(array: &Array<T, U>) -> alloc::vec::Vec<T> {
711        array.as_slice().into()
712    }
713}
714
715impl<T, U> Hash for Array<T, U>
716where
717    T: Hash,
718    U: ArraySize,
719{
720    #[inline]
721    fn hash<H: Hasher>(&self, state: &mut H) {
722        self.0.as_ref().hash(state);
723    }
724}
725
726impl<T, I, U> Index<I> for Array<T, U>
727where
728    [T]: Index<I>,
729    U: ArraySize,
730{
731    type Output = <[T] as Index<I>>::Output;
732
733    #[inline]
734    fn index(&self, index: I) -> &Self::Output {
735        Index::index(self.as_slice(), index)
736    }
737}
738
739impl<T, I, U> IndexMut<I> for Array<T, U>
740where
741    [T]: IndexMut<I>,
742    U: ArraySize,
743{
744    #[inline]
745    fn index_mut(&mut self, index: I) -> &mut Self::Output {
746        IndexMut::index_mut(self.as_mut_slice(), index)
747    }
748}
749
750impl<T, U> PartialEq for Array<T, U>
751where
752    T: PartialEq,
753    U: ArraySize,
754{
755    #[inline]
756    fn eq(&self, other: &Self) -> bool {
757        self.0.as_ref().eq(other.0.as_ref())
758    }
759}
760
761impl<T, U, const N: usize> PartialEq<[T; N]> for Array<T, U>
762where
763    T: PartialEq,
764    U: ArraySize<ArrayType<T> = [T; N]>,
765{
766    #[inline]
767    fn eq(&self, other: &[T; N]) -> bool {
768        self.0.eq(other)
769    }
770}
771
772impl<T, U, const N: usize> PartialEq<Array<T, U>> for [T; N]
773where
774    T: PartialEq,
775    U: ArraySize<ArrayType<T> = [T; N]>,
776{
777    #[inline]
778    fn eq(&self, other: &Array<T, U>) -> bool {
779        self.eq(&other.0)
780    }
781}
782
783impl<T, U> PartialOrd for Array<T, U>
784where
785    T: PartialOrd,
786    U: ArraySize,
787{
788    #[inline]
789    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
790        self.0.as_ref().partial_cmp(other.0.as_ref())
791    }
792}
793
794impl<T, U> Ord for Array<T, U>
795where
796    T: Ord,
797    U: ArraySize,
798{
799    #[inline]
800    fn cmp(&self, other: &Self) -> Ordering {
801        self.0.as_ref().cmp(other.0.as_ref())
802    }
803}
804
805/// SAFETY: `Array` is a `repr(transparent)` newtype for `[T; N]`, so as long as `T: Send` it should
806/// also be `Send`.
807unsafe impl<T, U: ArraySize> Send for Array<T, U> where T: Send {}
808
809/// SAFETY: `Array` is a `repr(transparent)` newtype for `[T; N]`, so as long as `T: Sync` it should
810/// also be `Sync`.
811unsafe impl<T, U: ArraySize> Sync for Array<T, U> where T: Sync {}
812
813impl<'a, T, U> TryFrom<&'a [T]> for Array<T, U>
814where
815    Self: Clone,
816    U: ArraySize,
817{
818    type Error = TryFromSliceError;
819
820    #[inline]
821    fn try_from(slice: &'a [T]) -> Result<Array<T, U>, TryFromSliceError> {
822        <&'a Self>::try_from(slice).cloned()
823    }
824}
825
826#[cfg(feature = "alloc")]
827impl<T, U> TryFrom<alloc::boxed::Box<[T]>> for Array<T, U>
828where
829    Self: Clone,
830    U: ArraySize,
831{
832    type Error = TryFromSliceError;
833
834    #[inline]
835    fn try_from(b: alloc::boxed::Box<[T]>) -> Result<Self, TryFromSliceError> {
836        Self::try_from(&*b)
837    }
838}
839
840#[cfg(feature = "alloc")]
841impl<'a, T, U> TryFrom<&'a alloc::boxed::Box<[T]>> for Array<T, U>
842where
843    Self: Clone,
844    U: ArraySize,
845{
846    type Error = TryFromSliceError;
847
848    #[inline]
849    fn try_from(b: &'a alloc::boxed::Box<[T]>) -> Result<Self, TryFromSliceError> {
850        Self::try_from(&**b)
851    }
852}
853
854#[cfg(feature = "alloc")]
855impl<T, U> TryFrom<alloc::vec::Vec<T>> for Array<T, U>
856where
857    Self: Clone,
858    U: ArraySize,
859{
860    type Error = TryFromSliceError;
861
862    #[inline]
863    fn try_from(v: alloc::vec::Vec<T>) -> Result<Self, TryFromSliceError> {
864        Self::try_from(v.as_slice())
865    }
866}
867
868#[cfg(feature = "alloc")]
869impl<'a, T, U> TryFrom<&'a alloc::vec::Vec<T>> for Array<T, U>
870where
871    Self: Clone,
872    U: ArraySize,
873{
874    type Error = TryFromSliceError;
875
876    #[inline]
877    fn try_from(v: &'a alloc::vec::Vec<T>) -> Result<Self, TryFromSliceError> {
878        Self::try_from(v.as_slice())
879    }
880}
881
882impl<'a, T, U> TryFrom<&'a [T]> for &'a Array<T, U>
883where
884    U: ArraySize,
885{
886    type Error = TryFromSliceError;
887
888    #[inline]
889    fn try_from(slice: &'a [T]) -> Result<Self, TryFromSliceError> {
890        check_slice_length::<T, U>(slice)?;
891
892        // SAFETY: `Array<T, U>` is a `repr(transparent)` newtype for a core
893        // array with length checked above.
894        Ok(unsafe { &*slice.as_ptr().cast() })
895    }
896}
897
898impl<'a, T, U> TryFrom<&'a mut [T]> for &'a mut Array<T, U>
899where
900    U: ArraySize,
901{
902    type Error = TryFromSliceError;
903
904    #[inline]
905    fn try_from(slice: &'a mut [T]) -> Result<Self, TryFromSliceError> {
906        check_slice_length::<T, U>(slice)?;
907
908        // SAFETY: `Array<T, U>` is a `repr(transparent)` newtype for a core
909        // array with length checked above.
910        Ok(unsafe { &mut *slice.as_mut_ptr().cast() })
911    }
912}
913
914#[cfg(feature = "bytemuck")]
915unsafe impl<T, U> Pod for Array<T, U>
916where
917    T: Pod,
918    U: ArraySize,
919    U::ArrayType<T>: Copy,
920{
921}
922
923#[cfg(feature = "bytemuck")]
924unsafe impl<T, U> Zeroable for Array<T, U>
925where
926    T: Zeroable,
927    U: ArraySize,
928{
929}
930
931#[cfg(feature = "subtle")]
932impl<T, U> ConditionallySelectable for Array<T, U>
933where
934    Self: Copy,
935    T: ConditionallySelectable,
936    U: ArraySize,
937{
938    #[inline]
939    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
940        let mut output = *a;
941        output.conditional_assign(b, choice);
942        output
943    }
944
945    fn conditional_assign(&mut self, other: &Self, choice: Choice) {
946        for (a_i, b_i) in self.iter_mut().zip(other) {
947            a_i.conditional_assign(b_i, choice)
948        }
949    }
950}
951
952#[cfg(feature = "subtle")]
953impl<T, U> ConstantTimeEq for Array<T, U>
954where
955    T: ConstantTimeEq,
956    U: ArraySize,
957{
958    #[inline]
959    fn ct_eq(&self, other: &Self) -> Choice {
960        self.iter()
961            .zip(other.iter())
962            .fold(Choice::from(1), |acc, (a, b)| acc & a.ct_eq(b))
963    }
964}
965
966#[cfg(feature = "zeroize")]
967impl<T, U> Zeroize for Array<T, U>
968where
969    T: Zeroize,
970    U: ArraySize,
971{
972    #[inline]
973    fn zeroize(&mut self) {
974        self.0.as_mut().iter_mut().zeroize()
975    }
976}
977
978#[cfg(feature = "zeroize")]
979impl<T, U> ZeroizeOnDrop for Array<T, U>
980where
981    T: ZeroizeOnDrop,
982    U: ArraySize,
983{
984}
985
986/// Generate a [`TryFromSliceError`] if the slice doesn't match the given length.
987#[cfg_attr(debug_assertions, allow(clippy::panic_in_result_fn))]
988fn check_slice_length<T, U: ArraySize>(slice: &[T]) -> Result<(), TryFromSliceError> {
989    debug_assert_eq!(Array::<(), U>::default().len(), U::USIZE);
990
991    if slice.len() != U::USIZE {
992        // Hack: `TryFromSliceError` lacks a public constructor
993        <&[T; 1]>::try_from([].as_slice())?;
994
995        #[cfg(debug_assertions)]
996        unreachable!();
997    }
998
999    Ok(())
1000}