Skip to main content

hybrid_array/
lib.rs

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