diff --git a/src/lib.rs b/src/lib.rs index 08b8008..c01b259 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -68,6 +68,18 @@ //! sizes of arrays via associated constants. For example, to obtain the size of an `ArraySize` as //! a `usize`, use the associated [`typenum::Unsigned::USIZE`] constant. //! +//! ### [`AsArrayRef`] and [`AsArrayMut`] traits +//! +//! These traits simplify obtaining references to [`Array`] and are impl'd for both [`Array`] +//! and `[T; N]`. They're analogous to traits like [`AsRef`] and [`AsMut`]. +//! +//! They make it possible to write code which uses `[T; N]` or `&[T; N]` in the external facing +//! API which can obtain references to `&Array` and call other functions which accept such +//! references, without the caller having to use `Array` in their code and while still supporting +//! generic sizes. +//! +//! For more information and a code example, see [`AsArrayRef`]. +//! //! ## Relationship with `generic-array` //! //! `hybrid-array` is directly inspired by the [`generic-array`] crate. @@ -75,8 +87,8 @@ //! However, where `generic-array` predates const generics and uses a core which is built //! on `unsafe` code, `hybrid-array`'s core implementation is built on safe code and const //! generic implementations. This allows the inner `[T; N]` field of an `Array` to be `pub` as -//! noted above, and in general for the implementation to be significantly simpler and -//! easier-to-audit. +//! noted above, and in general for the implementation to be significantly simpler, easier-to-audit, +//! and with significantly less use of `unsafe`. //! //! The only places `hybrid-array` uses unsafe are where it is absolutely necessary, primarily //! for reference conversions between `Array` and `[T; N]`, and also to provide features diff --git a/src/traits.rs b/src/traits.rs index b53b118..1988277 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -65,3 +65,82 @@ where { type Size = U; } + +/// Obtain an `&Array` reference for a given type. +/// +/// This provides functionality equivalent to `AsRef` or `Borrow`, but is deliberately +/// implemented as its own trait both so it can leverage [`AssocArraySize`] to determine the +/// array size, and also to avoid inference problems that occur when third party impls of traits +/// like [`AsRef`] and [`Borrow`] are added to `[T; N]`. +/// +/// # Usage with `[T; N]` +/// +/// ``` +/// use hybrid_array::{Array, ArraySize, AsArrayRef}; +/// +/// pub fn getn_hybrid(arr: &Array, n: usize) -> &T { +/// &arr[2] +/// } +/// +/// pub fn getn_generic(arr: &[T; N], n: usize) -> &T +/// where +/// [T; N]: AsArrayRef +/// { +/// getn_hybrid(arr.as_array_ref(), n) +/// } +/// +/// let array = [0u8, 1, 2, 3]; +/// let x = getn_generic(&array, 2); +/// assert_eq!(x, &2); +/// ``` +pub trait AsArrayRef: AssocArraySize { + /// Converts this type into an immutable [`Array`] reference. + fn as_array_ref(&self) -> &Array; +} + +/// Obtain a `&mut Array` reference for a given type. +/// +/// Companion trait to [`AsArrayRef`] for mutable references, equivalent to [`AsMut`] or +/// [`BorrowMut`]. +pub trait AsArrayMut: AsArrayRef { + /// Converts this type into a mutable [`Array`] reference. + fn as_array_mut(&mut self) -> &mut Array; +} + +impl AsArrayRef for Array +where + U: ArraySize, +{ + fn as_array_ref(&self) -> &Self { + self + } +} + +impl AsArrayMut for Array +where + U: ArraySize, +{ + fn as_array_mut(&mut self) -> &mut Self { + self + } +} + +impl AsArrayRef for [T; N] +where + Self: AssocArraySize, + U: ArraySize = Self>, +{ + fn as_array_ref(&self) -> &Array { + self.into() + } +} + +impl AsArrayMut for [T; N] +where + Self: AssocArraySize, + U: ArraySize = Self>, +{ + fn as_array_mut(&mut self) -> &mut Array { + self.into() + } +}