I noticed that impl<T> [T] implements get function. This allow to get elements in a range as slice.
For example [200,200,0,0,1,1].get(..4), unfortunately, the return type is a slice, rather than array ref.
I'm looking for a way, to get this slice as a fixed size array ref.
Ideally I would like to write the code this like
let _: Option<[u8; 4]> = [200,200,0,0,1,1].get_array_ref<4>(0);
let _: Option<[u8; 1]> = [200,200,0,0,1,1].get_array_ref<1>(4);
Current get api looks like this:
pub fn get<I>(&self, index: I) -> Option<&I::Output> where I: SliceIndex<Self>;
&[T; N] implements TryFrom<&[T]>, so you can use that (or the equivalent TryInto impl) to get an array ref from a slice (though you have to first slice it to the right length).
You don't need the type annotation and map + flatten on an Option can be simplified to just and_then. So you can get away with less boilerplate, though of course a dedicated method would still be shorter.
Your proposed API is a index-length API. While this is unavoidable (since the length needs to be const, and the index shouldn't need to be), it's definitely not immediately clear.
A currently available unstable option is array_windows.
Is it possible to do this? (But might require more functioning of const generics)
// Make literals of range to be `ConstRange`, and allow it coerce to `Range<uize>`.
ConstRange<Idx, const S: Idx, const E: Idx>;
impl<T, const N: usize, const S: usize, const E: usize> SliceIndex<[T; N]>
for ConstRange<usize, S, E>
where
S < E,
S < N,
E <= N,
{
type Output = [T; E - S];
fn index(self, slice: &[T; N]) -> &Self::Output {
unsafe { self.get_unchecked(slice)) as &[T; E - S] }
}
unsafe fn get_unchecked(self, slice: *const [T; N]) -> *const Self::Output {
slice.as_ptr().add(S) as *const [T; E - S]
}
// impl other functions similarly
}
And then, it is possible to use it like this
let arr = [0, 1, 2, 3, 4];
let sub_array: [i32; 2] = arr[0..2];
With adt_const_params you can use Range itself. But to return an array based on that requires the full generic_const_exprs feature. And using every possible range (Range, RangeInclusive, RangeTo, etc.) isn't possible even then, unless we'll have some kind of generics-over-const-parameters (i.e. fn foo<T: Trait, const C: T>()).
It's cool! But it could be even better if your version fn slice_get_array can be put into a trait so that slicing on arrays can get an array, too, if the index Range<usize> is const (instead of a slice).
I'm not even sure that adding a method to the standard library is good (though it can live inside an external crate), but I'm pretty sure that re-using the existing syntax is a very bad idea. Values that affect types? And if later I'll store the range in a variable, will I need to change the type in every place too?
I agree with you. How about making a &[T] convertible (by coercing?) to a &[T; N] in a const context? Since the length of slice must be known to the compiler in a const context.