hybrid_array/
traits.rs

1//! Trait definitions.
2
3use crate::Array;
4use core::{
5    borrow::{Borrow, BorrowMut},
6    ops::{Index, IndexMut, Range},
7};
8use typenum::Unsigned;
9
10/// Trait which associates a [`usize`] size and `ArrayType` with a
11/// `typenum`-provided [`Unsigned`] integer.
12///
13/// # Safety
14///
15/// `ArrayType` MUST be an array with a number of elements exactly equal to
16/// [`Unsigned::USIZE`]. Breaking this requirement will cause undefined behavior.
17///
18/// NOTE: This trait is effectively sealed and can not be implemented by third-party crates.
19/// It is implemented only for a number of types defined in [`typenum::consts`].
20pub unsafe trait ArraySize: Unsigned {
21    /// Array type which corresponds to this size.
22    ///
23    /// This is always defined to be `[T; N]` where `N` is the same as
24    /// [`ArraySize::USIZE`][`typenum::Unsigned::USIZE`].
25    type ArrayType<T>: AssocArraySize<Size = Self>
26        + AsRef<[T]>
27        + AsMut<[T]>
28        + Borrow<[T]>
29        + BorrowMut<[T]>
30        + From<Array<T, Self>>
31        + Index<usize>
32        + Index<Range<usize>>
33        + IndexMut<usize>
34        + IndexMut<Range<usize>>
35        + Into<Array<T, Self>>
36        + IntoIterator<Item = T>;
37}
38
39/// Associates an [`ArraySize`] with a given type. Can be used to accept `[T; N]` const generic
40/// arguments and convert to [`Array`] internally.
41///
42/// This trait is also the magic glue that makes the [`ArrayN`][`crate::ArrayN`] type alias work.
43///
44/// # Example
45///
46/// ```
47/// use hybrid_array::{ArrayN, AssocArraySize};
48///
49/// pub fn example<const N: usize>(bytes: &[u8; N])
50/// where
51///     [u8; N]: AssocArraySize + AsRef<ArrayN<u8, N>>
52/// {
53///     // _arrayn is ArrayN<u8, N>
54///     let _arrayn = bytes.as_ref();
55/// }
56/// ```
57pub trait AssocArraySize: Sized {
58    /// Size of an array type, expressed as a [`typenum`]-based [`ArraySize`].
59    type Size: ArraySize;
60}
61
62impl<T, U> AssocArraySize for Array<T, U>
63where
64    U: ArraySize,
65{
66    type Size = U;
67}
68
69/// Obtain an `&Array` reference for a given type.
70///
71/// This provides functionality equivalent to `AsRef<Array>` or `Borrow<Array>`, but is deliberately
72/// implemented as its own trait both so it can leverage [`AssocArraySize`] to determine the
73/// array size, and also to avoid inference problems that occur when third party impls of traits
74/// like [`AsRef`] and [`Borrow`] are added to `[T; N]`.
75///
76/// # Usage with `[T; N]`
77///
78/// ```
79/// use hybrid_array::{Array, ArraySize, AsArrayRef};
80///
81/// pub fn getn_hybrid<T, U: ArraySize>(arr: &Array<T, U>, n: usize) -> &T {
82///     &arr[2]
83/// }
84///
85/// pub fn getn_generic<T, const N: usize>(arr: &[T; N], n: usize) -> &T
86/// where
87///     [T; N]: AsArrayRef<T>
88/// {
89///     getn_hybrid(arr.as_array_ref(), n)
90/// }
91///
92/// let array = [0u8, 1, 2, 3];
93/// let x = getn_generic(&array, 2);
94/// assert_eq!(x, &2);
95/// ```
96pub trait AsArrayRef<T>: AssocArraySize {
97    /// Converts this type into an immutable [`Array`] reference.
98    fn as_array_ref(&self) -> &Array<T, Self::Size>;
99}
100
101/// Obtain a `&mut Array` reference for a given type.
102///
103/// Companion trait to [`AsArrayRef`] for mutable references, equivalent to [`AsMut`] or
104/// [`BorrowMut`].
105pub trait AsArrayMut<T>: AsArrayRef<T> {
106    /// Converts this type into a mutable [`Array`] reference.
107    fn as_array_mut(&mut self) -> &mut Array<T, Self::Size>;
108}
109
110impl<T, U> AsArrayRef<T> for Array<T, U>
111where
112    U: ArraySize,
113{
114    fn as_array_ref(&self) -> &Self {
115        self
116    }
117}
118
119impl<T, U> AsArrayMut<T> for Array<T, U>
120where
121    U: ArraySize,
122{
123    fn as_array_mut(&mut self) -> &mut Self {
124        self
125    }
126}
127
128impl<T, U, const N: usize> AsArrayRef<T> for [T; N]
129where
130    Self: AssocArraySize<Size = U>,
131    U: ArraySize<ArrayType<T> = Self>,
132{
133    fn as_array_ref(&self) -> &Array<T, U> {
134        self.into()
135    }
136}
137
138impl<T, U, const N: usize> AsArrayMut<T> for [T; N]
139where
140    Self: AssocArraySize<Size = U>,
141    U: ArraySize<ArrayType<T> = Self>,
142{
143    fn as_array_mut(&mut self) -> &mut Array<T, U> {
144        self.into()
145    }
146}