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