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