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