Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,27 @@
//! 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.
//!
//! 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<T, U>` and `[T; N]`, and also to provide features
Expand Down
79 changes: 79 additions & 0 deletions src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,82 @@ where
{
type Size = U;
}

/// Obtain an `&Array` reference for a given type.
///
/// This provides functionality equivalent to `AsRef<Array>` or `Borrow<Array>`, 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<T, U: ArraySize>(arr: &Array<T, U>, n: usize) -> &T {
/// &arr[2]
/// }
///
/// pub fn getn_generic<T, const N: usize>(arr: &[T; N], n: usize) -> &T
/// where
/// [T; N]: AsArrayRef<T>
/// {
/// 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<T>: AssocArraySize {
/// Converts this type into an immutable [`Array`] reference.
fn as_array_ref(&self) -> &Array<T, Self::Size>;
}

/// Obtain a `&mut Array` reference for a given type.
///
/// Companion trait to [`AsArrayRef`] for mutable references, equivalent to [`AsMut`] or
/// [`BorrowMut`].
pub trait AsArrayMut<T>: AsArrayRef<T> {
/// Converts this type into a mutable [`Array`] reference.
fn as_array_mut(&mut self) -> &mut Array<T, Self::Size>;
}

impl<T, U> AsArrayRef<T> for Array<T, U>
where
U: ArraySize,
{
fn as_array_ref(&self) -> &Self {
self
}
}

impl<T, U> AsArrayMut<T> for Array<T, U>
where
U: ArraySize,
{
fn as_array_mut(&mut self) -> &mut Self {
self
}
}

impl<T, U, const N: usize> AsArrayRef<T> for [T; N]
where
Self: AssocArraySize<Size = U>,
U: ArraySize<ArrayType<T> = Self>,
{
fn as_array_ref(&self) -> &Array<T, U> {
self.into()
}
}

impl<T, U, const N: usize> AsArrayMut<T> for [T; N]
where
Self: AssocArraySize<Size = U>,
U: ArraySize<ArrayType<T> = Self>,
{
fn as_array_mut(&mut self) -> &mut Array<T, U> {
self.into()
}
}