hybrid_array/traits.rs
1//! Trait definitions.
2
3use crate::Array;
4use core::{
5 borrow::{Borrow, BorrowMut},
6 fmt::Debug,
7 ops::{Index, IndexMut, Range},
8};
9use typenum::Unsigned;
10
11/// Trait which associates a [`usize`] size and `ArrayType` with a
12/// `typenum`-provided [`Unsigned`] integer.
13///
14/// # Safety
15///
16/// `ArrayType` MUST be an array with a number of elements exactly equal to
17/// [`Unsigned::USIZE`]. Breaking this requirement will cause undefined behavior.
18///
19/// NOTE: This trait is effectively sealed and can not be implemented by third-party crates.
20/// It is implemented only for a number of types defined in [`typenum::consts`].
21pub unsafe trait ArraySize: Unsigned + Debug {
22 /// Array type which corresponds to this size.
23 ///
24 /// This is always defined to be `[T; N]` where `N` is the same as
25 /// [`ArraySize::USIZE`][`typenum::Unsigned::USIZE`].
26 type ArrayType<T>: AssocArraySize<Size = Self>
27 + AsRef<[T]>
28 + AsMut<[T]>
29 + Borrow<[T]>
30 + BorrowMut<[T]>
31 + From<Array<T, Self>>
32 + Index<usize>
33 + Index<Range<usize>>
34 + IndexMut<usize>
35 + IndexMut<Range<usize>>
36 + Into<Array<T, Self>>
37 + IntoIterator<Item = T>;
38}
39
40/// Associates an [`ArraySize`] with a given type. Can be used to accept `[T; N]` const generic
41/// arguments and convert to [`Array`] internally.
42///
43/// This trait is also the magic glue that makes the [`ArrayN`][`crate::ArrayN`] type alias work.
44///
45/// # Example
46///
47/// ```
48/// use hybrid_array::{ArrayN, AssocArraySize};
49///
50/// pub fn example<const N: usize>(bytes: &[u8; N])
51/// where
52/// [u8; N]: AssocArraySize + AsRef<ArrayN<u8, N>>
53/// {
54/// // _arrayn is ArrayN<u8, N>
55/// let _arrayn = bytes.as_ref();
56/// }
57/// ```
58pub trait AssocArraySize: Sized {
59 /// Size of an array type, expressed as a [`typenum`]-based [`ArraySize`].
60 type Size: ArraySize;
61}
62
63impl<T, U> AssocArraySize for Array<T, U>
64where
65 U: ArraySize,
66{
67 type Size = U;
68}
69
70/// Obtain an `&Array` reference for a given type.
71///
72/// This provides functionality equivalent to `AsRef<Array>` or `Borrow<Array>`, but is deliberately
73/// implemented as its own trait both so it can leverage [`AssocArraySize`] to determine the
74/// array size, and also to avoid inference problems that occur when third party impls of traits
75/// like [`AsRef`] and [`Borrow`] are added to `[T; N]`.
76///
77/// # Usage with `[T; N]`
78///
79/// ```
80/// use hybrid_array::{Array, ArraySize, AsArrayRef};
81///
82/// pub fn getn_hybrid<T, U: ArraySize>(arr: &Array<T, U>, n: usize) -> &T {
83/// &arr[2]
84/// }
85///
86/// pub fn getn_generic<T, const N: usize>(arr: &[T; N], n: usize) -> &T
87/// where
88/// [T; N]: AsArrayRef<T>
89/// {
90/// getn_hybrid(arr.as_array_ref(), n)
91/// }
92///
93/// let array = [0u8, 1, 2, 3];
94/// let x = getn_generic(&array, 2);
95/// assert_eq!(x, &2);
96/// ```
97pub trait AsArrayRef<T>: AssocArraySize {
98 /// Converts this type into an immutable [`Array`] reference.
99 fn as_array_ref(&self) -> &Array<T, Self::Size>;
100}
101
102/// Obtain a `&mut Array` reference for a given type.
103///
104/// Companion trait to [`AsArrayRef`] for mutable references, equivalent to [`AsMut`] or
105/// [`BorrowMut`].
106pub trait AsArrayMut<T>: AsArrayRef<T> {
107 /// Converts this type into a mutable [`Array`] reference.
108 fn as_array_mut(&mut self) -> &mut Array<T, Self::Size>;
109}
110
111impl<T, U> AsArrayRef<T> for Array<T, U>
112where
113 U: ArraySize,
114{
115 fn as_array_ref(&self) -> &Self {
116 self
117 }
118}
119
120impl<T, U> AsArrayMut<T> for Array<T, U>
121where
122 U: ArraySize,
123{
124 fn as_array_mut(&mut self) -> &mut Self {
125 self
126 }
127}
128
129impl<T, U, const N: usize> AsArrayRef<T> for [T; N]
130where
131 Self: AssocArraySize<Size = U>,
132 U: ArraySize<ArrayType<T> = Self>,
133{
134 fn as_array_ref(&self) -> &Array<T, U> {
135 self.into()
136 }
137}
138
139impl<T, U, const N: usize> AsArrayMut<T> for [T; N]
140where
141 Self: AssocArraySize<Size = U>,
142 U: ArraySize<ArrayType<T> = Self>,
143{
144 fn as_array_mut(&mut self) -> &mut Array<T, U> {
145 self.into()
146 }
147}
148
149/// Extension trait for `[T]` providing methods for working with [`Array`].
150pub trait SliceExt<T>: sealed::Sealed {
151 /// Get a reference to an array from a slice, if the slice is exactly the size of the array.
152 ///
153 /// Returns `None` if the slice's length is not exactly equal to the array size.
154 fn as_hybrid_array<U: ArraySize>(&self) -> Option<&Array<T, U>>;
155
156 /// Get a mutable reference to an array from a slice, if the slice is exactly the size of the
157 /// array.
158 ///
159 /// Returns `None` if the slice's length is not exactly equal to the array size.
160 fn as_mut_hybrid_array<U: ArraySize>(&mut self) -> Option<&mut Array<T, U>>;
161
162 /// Splits the shared slice into a slice of `U`-element arrays, starting at the beginning
163 /// of the slice, and a remainder slice with length strictly less than `U`.
164 ///
165 /// # Panics
166 /// If `U` is 0.
167 fn as_hybrid_chunks<U: ArraySize>(&self) -> (&[Array<T, U>], &[T]);
168
169 /// Splits the exclusive slice into a slice of `U`-element arrays, starting at the beginning
170 /// of the slice, and a remainder slice with length strictly less than `U`.
171 ///
172 /// # Panics
173 /// If `U` is 0.
174 fn as_hybrid_chunks_mut<U: ArraySize>(&mut self) -> (&mut [Array<T, U>], &mut [T]);
175}
176
177impl<T> SliceExt<T> for [T] {
178 fn as_hybrid_array<U: ArraySize>(&self) -> Option<&Array<T, U>> {
179 Array::slice_as_array(self)
180 }
181
182 fn as_mut_hybrid_array<U: ArraySize>(&mut self) -> Option<&mut Array<T, U>> {
183 Array::slice_as_mut_array(self)
184 }
185
186 fn as_hybrid_chunks<U: ArraySize>(&self) -> (&[Array<T, U>], &[T]) {
187 Array::slice_as_chunks(self)
188 }
189
190 fn as_hybrid_chunks_mut<U: ArraySize>(&mut self) -> (&mut [Array<T, U>], &mut [T]) {
191 Array::slice_as_chunks_mut(self)
192 }
193}
194
195impl<T> sealed::Sealed for [T] {}
196
197mod sealed {
198 pub trait Sealed {}
199}