1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
//! Trait definitions.
use crate::{slice_as_chunks, slice_as_chunks_mut, Array, FromFn};
use core::{
borrow::{Borrow, BorrowMut},
ops::{Index, IndexMut, Range},
};
use typenum::Unsigned;
/// Trait which associates a [`usize`] size and `ArrayType` with a
/// `typenum`-provided [`Unsigned`] integer.
///
/// # Safety
///
/// `ArrayType` MUST be an array with a number of elements exactly equal to
/// [`Unsigned::USIZE`]. Breaking this requirement will cause undefined behavior.
///
/// NOTE: This trait is effectively sealed and can not be implemented by third-party crates.
/// It is implemented only for a number of types defined in [`typenum::consts`].
pub unsafe trait ArraySize: Unsigned {
/// Array type which corresponds to this size.
///
/// This is always defined to be `[T; N]` where `N` is the same as
/// [`ArraySize::USIZE`][`typenum::Unsigned::USIZE`].
type ArrayType<T>: AssociatedArraySize<Size = Self>
+ From<Array<T, Self>>
+ FromFn<T>
+ Into<Array<T, Self>>
+ IntoIterator<Item = T>
+ SliceOps<T>;
}
/// Associates an [`ArraySize`] with a given type.
pub trait AssociatedArraySize: Sized {
/// Size of an array type, expressed as a [`typenum`]-based [`ArraySize`].
type Size: ArraySize;
}
impl<T, U> AssociatedArraySize for Array<T, U>
where
U: ArraySize,
{
type Size = U;
}
/// Array operations which are const generic over a given array size.
pub trait ArrayOps<T, const N: usize>:
Borrow<[T; N]>
+ BorrowMut<[T; N]>
+ From<[T; N]>
+ FromFn<T>
+ Into<[T; N]>
+ IntoIterator<Item = T>
+ Sized
+ SliceOps<T>
{
/// Size of an array as a `usize`.
///
/// Not to be confused with [`AssociatedArraySize::Size`], which is [`typenum`]-based.
const SIZE: usize;
/// Returns an array of the same size as `self`, with function `f` applied to each element
/// in order.
fn map_to_core_array<F, U>(self, f: F) -> [U; N]
where
F: FnMut(T) -> U;
/// Transform slice to slice of core array type
fn cast_slice_to_core(slice: &[Self]) -> &[[T; N]];
/// Transform mutable slice to mutable slice of core array type
fn cast_slice_to_core_mut(slice: &mut [Self]) -> &mut [[T; N]];
/// Transform slice to slice of core array type
fn cast_slice_from_core(slice: &[[T; N]]) -> &[Self];
/// Transform mutable slice to mutable slice of core array type
fn cast_slice_from_core_mut(slice: &mut [[T; N]]) -> &mut [Self];
}
impl<T, const N: usize> ArrayOps<T, N> for [T; N] {
const SIZE: usize = N;
#[inline]
fn map_to_core_array<F, U>(self, f: F) -> [U; N]
where
F: FnMut(T) -> U,
{
self.map(f)
}
#[inline]
fn cast_slice_to_core(slice: &[Self]) -> &[[T; N]] {
slice
}
#[inline]
fn cast_slice_to_core_mut(slice: &mut [Self]) -> &mut [[T; N]] {
slice
}
#[inline]
fn cast_slice_from_core(slice: &[[T; N]]) -> &[Self] {
slice
}
#[inline]
fn cast_slice_from_core_mut(slice: &mut [[T; N]]) -> &mut [Self] {
slice
}
}
/// Slice operations which don't have access to a const generic array size.
pub trait SliceOps<T>:
AsRef<[T]>
+ AsMut<[T]>
+ Borrow<[T]>
+ BorrowMut<[T]>
+ Index<usize>
+ Index<Range<usize>>
+ IndexMut<usize>
+ IndexMut<Range<usize>>
{
/// Splits the shared slice into a slice of `N`-element arrays.
///
/// See [`slice_as_chunks`] for more information.
#[inline]
fn as_array_chunks<N: ArraySize>(&self) -> (&[Array<T, N>], &[T]) {
slice_as_chunks(self.as_ref())
}
/// Splits the exclusive slice into a slice of `N`-element arrays.
///
/// See [`slice_as_chunks_mut`] for more information.
#[inline]
fn as_array_chunks_mut<N: ArraySize>(&mut self) -> (&mut [Array<T, N>], &mut [T]) {
slice_as_chunks_mut(self.as_mut())
}
}
impl<T> SliceOps<T> for [T] {}
impl<T, const N: usize> SliceOps<T> for [T; N] {}
impl<T, U: ArraySize> SliceOps<T> for Array<T, U> {}