index_ext/
array.rs

1//! Index types that produce arrays.
2//!
3//! The default rust index types, that is `usize` and those constructed with special range syntax,
4//! produce slices. That's not necessarily bad as designing them with `const` in mind would have
5//! delay their introduction and have problems of coherency. The ergonomic overhead however muddles
6//! the intent and requires writing a never failing, but semantically fallible conversion.
7//!
8//! With the introduction of `const` generic parameters we can design a better solution with which
9//! the length of the range is statically determined and which consequently can return a proper
10//! array reference instead of a dynamically sized slice. Even better, as this happens in the type
11//! system, some parameter values can be deduced where the compiler can match with another array
12//! type!
13//!
14//! Having to decide on the length introduces new complications that are usually put off to the
15//! actual execution of indexing. If the given indices are inconsistent, i.e. the end is smaller
16//! than the start or the end of an inclusive range is the maximum possible index, then there is no
17//! possible type to represent the output. We will not solve this dilemma at the moment, and only
18//! define the simple indices which is precisely `RangeTo<usize>`.
19use core::ops::{Index, IndexMut};
20
21/// A marker struct for statically sized range to (`..n`).
22///
23/// This can make use of parameter deduction in many cases, for example if assigning the slice to a
24/// right hand side array pattern.
25///
26/// ```
27/// use index_ext::array::ArrayPrefix;
28/// # let buf = &[0u8; 3][..];
29/// let [r, g, b] = buf[ArrayPrefix];
30/// ```
31///
32/// To slice off an array in the middle of a slice, utilize the common pattern of indexing twice.
33///
34/// ```
35/// use index_ext::array::ArrayPrefix;
36/// # let buf = &[0u8; 3][..];
37/// let [u, v] = buf[1..][ArrayPrefix];
38/// ```
39pub struct ArrayPrefix<const N: usize>;
40
41impl<T, const N: usize> Index<ArrayPrefix<N>> for [T] {
42    type Output = [T; N];
43    fn index(&self, _: ArrayPrefix<{ N }>) -> &[T; N] {
44        let slice = &self[..N];
45        unsafe {
46            // SAFETY: the layout of slices and arrays of the same length are the same. We'd like
47            // to use TryFrom/TryInto here but that currently would require the relaxed bounds on
48            // array impls.
49            &*(slice.as_ptr() as *const [T; N])
50        }
51    }
52}
53
54impl<T, const N: usize> IndexMut<ArrayPrefix<N>> for [T] {
55    fn index_mut(&mut self, _: ArrayPrefix<{ N }>) -> &mut [T; N] {
56        let slice = &mut self[..N];
57        unsafe {
58            // SAFETY: the layout of slices and arrays of the same length are the same. We'd like
59            // to use TryFrom/TryInto here but that currently would require the relaxed bounds on
60            // array impls.
61            &mut *(slice.as_mut_ptr() as *mut [T; N])
62        }
63    }
64}