libs (slice | inherent-impl | impls-libstd)
panic_safe_slicing
Add "panic-safe" or "total" alternatives to the existing panicking indexing syntax.
SliceExt::get
and SliceExt::get_mut
can be thought as non-panicking versions of the simple
indexing syntax, a[idx]
, and SliceExt::get_unchecked
and SliceExt::get_unchecked_mut
can
be thought of as unsafe versions with bounds checks elided. However, there is no such equivalent for
a[start..end]
, a[start..]
, or a[..end]
. This RFC proposes such methods to fill the gap.
The get
, get_mut
, get_unchecked
, and get_unchecked_mut
will be made generic over usize
as well as ranges of usize
like slice's Index
implementation currently is. This will allow e.g.
a.get(start..end)
which will behave analagously to a[start..end]
.
Because methods cannot be overloaded in an ad-hoc manner in the same way that traits may be
implemented, we introduce a SliceIndex
trait which is implemented by types which can index into a
slice:
pub trait SliceIndex<T> {
type Output: ?Sized;
fn get(self, slice: &[T]) -> Option<&Self::Output>;
fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output>;
unsafe fn get_unchecked(self, slice: &[T]) -> &Self::Output;
unsafe fn get_mut_unchecked(self, slice: &[T]) -> &mut Self::Output;
fn index(self, slice: &[T]) -> &Self::Output;
fn index_mut(self, slice: &mut [T]) -> &mut Self::Output;
}
impl<T> SliceIndex<T> for usize {
type Output = T;
// ...
}
impl<T, R> SliceIndex<T> for R
where R: RangeArgument<usize>
{
type Output = [T];
// ...
}
And then alter the Index
, IndexMut
, get
, get_mut
, get_unchecked
, and get_mut_unchecked
implementations to be generic over SliceIndex
:
impl<T> [T] {
pub fn get<I>(&self, idx: I) -> Option<I::Output>
where I: SliceIndex<T>
{
idx.get(self)
}
pub fn get_mut<I>(&mut self, idx: I) -> Option<I::Output>
where I: SliceIndex<T>
{
idx.get_mut(self)
}
pub unsafe fn get_unchecked<I>(&self, idx: I) -> I::Output
where I: SliceIndex<T>
{
idx.get_unchecked(self)
}
pub unsafe fn get_mut_unchecked<I>(&mut self, idx: I) -> I::Output
where I: SliceIndex<T>
{
idx.get_mut_unchecked(self)
}
}
impl<T, I> Index<I> for [T]
where I: SliceIndex<T>
{
type Output = I::Output;
fn index(&self, idx: I) -> &I::Output {
idx.index(self)
}
}
impl<T, I> IndexMut<I> for [T]
where I: SliceIndex<T>
{
fn index_mut(&self, idx: I) -> &mut I::Output {
idx.index_mut(self)
}
}
SliceIndex
trait is unfortunate - it's tuned for exactly the set of methods it's used by.
It only exists because inherent methods cannot be overloaded the same way that trait
implementations can be. It would most likely remain unstable indefinitely.get_slice
etc methods rather than overloading
get
etc. This avoids the utility trait but is somewhat less ergonomic.SliceIndex
trait with a collection would be
backwards compatible.None