Skip to content

Commit 0450c2b

Browse files
authored
Add AsArrayRef/AsArrayMut traits (#135)
Impl'd for `Array<T, U>` and `[T; N]`. This is an alternative to #134, given the trouble we had in #131 with adding impls of core traits to `[T; N]` and the ensuing inference conflicts it can cause. The safest thing we can do is define our own traits, and these traits bound on `AssocArraySize` so they're able to handle everything related to the array size themselves, making them generic around only `T`. With this we can revert #134, which still has the potential to cause problems similar to #131. Using our own trait guarantees we won't break inference in existing code.
1 parent 1e21e27 commit 0450c2b

File tree

2 files changed

+93
-2
lines changed

2 files changed

+93
-2
lines changed

src/lib.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,15 +68,27 @@
6868
//! sizes of arrays via associated constants. For example, to obtain the size of an `ArraySize` as
6969
//! a `usize`, use the associated [`typenum::Unsigned::USIZE`] constant.
7070
//!
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+
//!
7183
//! ## Relationship with `generic-array`
7284
//!
7385
//! `hybrid-array` is directly inspired by the [`generic-array`] crate.
7486
//!
7587
//! However, where `generic-array` predates const generics and uses a core which is built
7688
//! on `unsafe` code, `hybrid-array`'s core implementation is built on safe code and const
7789
//! 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.
90+
//! noted above, and in general for the implementation to be significantly simpler, easier-to-audit,
91+
//! and with significantly less use of `unsafe`.
8092
//!
8193
//! The only places `hybrid-array` uses unsafe are where it is absolutely necessary, primarily
8294
//! for reference conversions between `Array<T, U>` and `[T; N]`, and also to provide features

src/traits.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,82 @@ where
6565
{
6666
type Size = U;
6767
}
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+
/// ```
96+
pub 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`].
105+
pub 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+
110+
impl<T, U> AsArrayRef<T> for Array<T, U>
111+
where
112+
U: ArraySize,
113+
{
114+
fn as_array_ref(&self) -> &Self {
115+
self
116+
}
117+
}
118+
119+
impl<T, U> AsArrayMut<T> for Array<T, U>
120+
where
121+
U: ArraySize,
122+
{
123+
fn as_array_mut(&mut self) -> &mut Self {
124+
self
125+
}
126+
}
127+
128+
impl<T, U, const N: usize> AsArrayRef<T> for [T; N]
129+
where
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+
138+
impl<T, U, const N: usize> AsArrayMut<T> for [T; N]
139+
where
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+
}

0 commit comments

Comments
 (0)