use std::ops;
pub trait SliceIndex<T: ?Sized> {
type Output: ?Sized;
unsafe fn get_unchecked(self, slice: &T) -> &Self::Output;
fn index(self, slice: &T) -> &Self::Output;
}
impl<T> SliceIndex<[T]> for usize {
type Output = T;
#[inline]
unsafe fn get_unchecked(self, slice: &[T]) -> &T {
&*slice.as_ptr().offset(self as isize)
}
#[inline]
fn index(self, slice: &[T]) -> &T {
&(*slice)[self]
}
}
#[inline(never)]
#[cold]
fn slice_index_len_fail(index: usize, len: usize) -> ! {
panic!("index {} out of range for slice of length {}", index, len);
}
#[inline(never)]
#[cold]
fn slice_index_order_fail(index: usize, end: usize) -> ! {
panic!("slice index starts at {} but ends at {}", index, end);
}
impl<T> SliceIndex<[T]> for ops::Range<usize> {
type Output = [T];
#[inline]
unsafe fn get_unchecked(self, slice: &[T]) -> &[T] {
use std::slice::from_raw_parts;
from_raw_parts(
slice.as_ptr().offset(self.start as isize),
self.end - self.start,
)
}
#[inline]
fn index(self, slice: &[T]) -> &[T] {
if self.start > self.end {
slice_index_order_fail(self.start, self.end);
} else if self.end > slice.len() {
slice_index_len_fail(self.end, slice.len());
}
unsafe { self.get_unchecked(slice) }
}
}
impl<T> SliceIndex<[T]> for ops::RangeTo<usize> {
type Output = [T];
#[inline]
unsafe fn get_unchecked(self, slice: &[T]) -> &[T] {
(0..self.end).get_unchecked(slice)
}
#[inline]
fn index(self, slice: &[T]) -> &[T] {
(0..self.end).index(slice)
}
}
impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
type Output = [T];
#[inline]
unsafe fn get_unchecked(self, slice: &[T]) -> &[T] {
(self.start..slice.len()).get_unchecked(slice)
}
#[inline]
fn index(self, slice: &[T]) -> &[T] {
(self.start..slice.len()).index(slice)
}
}
impl<T> SliceIndex<[T]> for ops::RangeFull {
type Output = [T];
#[inline]
unsafe fn get_unchecked(self, slice: &[T]) -> &[T] {
slice
}
#[inline]
fn index(self, slice: &[T]) -> &[T] {
slice
}
}