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