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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
//! 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.
    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 a reference to the inner array.
    fn as_core_array(&self) -> &[T; N];

    /// Returns a mutable reference to the inner array.
    fn as_mut_core_array(&mut self) -> &mut [T; N];

    /// Create array from Rust's core array type.
    fn from_core_array(arr: [T; N]) -> Self;

    /// Create array reference from reference to Rust's core array type.
    fn ref_from_core_array(arr: &[T; N]) -> &Self;

    /// Create mutable array reference from reference to Rust's core array type.
    fn ref_mut_from_core_array(arr: &mut [T; N]) -> &mut Self;

    /// 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 as_core_array(&self) -> &[T; N] {
        self
    }

    #[inline]
    fn as_mut_core_array(&mut self) -> &mut [T; N] {
        self
    }

    #[inline]
    fn from_core_array(arr: [T; N]) -> Self {
        arr
    }

    #[inline]
    fn ref_from_core_array(array_ref: &[T; N]) -> &Self {
        array_ref
    }

    #[inline]
    fn ref_mut_from_core_array(array_ref: &mut [T; N]) -> &mut Self {
        array_ref
    }

    #[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> {}