use core::convert::TryInto;
use core::hint::unreachable_unchecked;
use core::num::TryFromIntError;
use core::ops::{Range, RangeFrom, RangeTo};
use core::slice::SliceIndex;
use self::sealed::{IndexSealed, IntoIntIndex};
use super::IntSliceIndex;
pub(crate) mod sealed {
use core::num::TryFromIntError;
pub trait IndexSealed {
fn copy(&self) -> Self;
#[cold]
fn panic_msg(limit: usize, idx: Self) -> !;
}
pub trait IntoIntIndex {
type IntoIndex;
fn index(self) -> Result<Self::IntoIndex, TryFromIntError>;
}
pub trait IntSliceIndex<T: ?Sized>: Sized {
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_unchecked_mut(self, slice: &mut T) -> &mut Self::Output;
fn index(self, slice: &T) -> &Self::Output;
fn index_mut(self, slice: &mut T) -> &mut Self::Output;
}
pub trait SealedSliceIndex<T: ?Sized>: IntSliceIndex<T> {
type Output: ?Sized;
fn get(self, _: &T) -> ! {
unreachable!()
}
fn get_mut(self, _: &mut T) -> ! {
unreachable!()
}
unsafe fn get_unchecked(self, _: &T) -> ! {
unreachable!()
}
unsafe fn get_unchecked_mut(self, _: &mut T) -> ! {
unreachable!()
}
fn index(self, _: &T) -> ! {
unreachable!()
}
fn index_mut(self, _: &mut T) -> ! {
unreachable!()
}
}
impl<U: ?Sized, T: IntSliceIndex<U>> SealedSliceIndex<U> for T {
type Output = <Self as IntSliceIndex<U>>::Output;
}
}
#[repr(transparent)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TryIndex<T>(pub T);
impl<T> TryIndex<T>
where
T: TryInto<usize>,
T::Error: Into<TryFromIntError>,
{
fn into_int_index(self) -> usize {
match self.0.try_into() {
Ok(idx) => idx,
Err(error) => panic!("Invalid index, {}", error.into()),
}
}
}
impl<T> IntoIntIndex for TryIndex<T>
where
T: TryInto<usize>,
T::Error: Into<TryFromIntError>,
{
type IntoIndex = usize;
fn index(self) -> Result<usize, TryFromIntError> {
self.0.try_into().map_err(Into::into)
}
}
impl<T, U> sealed::IntSliceIndex<[U]> for TryIndex<T>
where
T: TryInto<usize>,
T::Error: Into<TryFromIntError>,
{
type Output = U;
fn get(self, slice: &[U]) -> Option<&Self::Output> {
match IntoIntIndex::index(self) {
Ok(idx) => slice.get(idx),
Err(_) => None,
}
}
fn get_mut(self, slice: &mut [U]) -> Option<&mut Self::Output> {
match IntoIntIndex::index(self) {
Ok(idx) => slice.get_mut(idx),
Err(_) => None,
}
}
unsafe fn get_unchecked(self, slice: &[U]) -> &Self::Output {
slice.get_unchecked(self.into_int_index())
}
unsafe fn get_unchecked_mut(self, slice: &mut [U]) -> &mut Self::Output {
slice.get_unchecked_mut(self.into_int_index())
}
fn index(self, slice: &[U]) -> &Self::Output {
&slice[self.into_int_index()]
}
fn index_mut(self, slice: &mut [U]) -> &mut Self::Output {
&mut slice[self.into_int_index()]
}
}
impl<T, U> IntSliceIndex<[U]> for TryIndex<T>
where
T: TryInto<usize>,
T::Error: Into<TryFromIntError>,
{
}
impl<T, U> core::ops::Index<TryIndex<T>> for [U]
where
T: TryInto<usize> + IndexSealed,
T::Error: Into<TryFromIntError>,
{
type Output = U;
fn index(&self, idx: TryIndex<T>) -> &U {
sealed::IntSliceIndex::index(idx, self)
}
}
impl<T, U> core::ops::IndexMut<TryIndex<T>> for [U]
where
T: TryInto<usize> + IndexSealed,
T::Error: Into<TryFromIntError>,
{
fn index_mut(&mut self, idx: TryIndex<T>) -> &mut Self::Output {
sealed::IntSliceIndex::index_mut(idx, self)
}
}
#[repr(transparent)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Int<T>(pub T);
impl<T, U> core::ops::Index<Int<T>> for [U]
where
T: IntSliceIndex<[U]> + IndexSealed,
{
type Output = <T as sealed::IntSliceIndex<[U]>>::Output;
fn index(&self, idx: Int<T>) -> &Self::Output {
<T as sealed::IntSliceIndex<[U]>>::index(idx.0, self)
}
}
impl<T, U> core::ops::IndexMut<Int<T>> for [U]
where
T: IntSliceIndex<[U]> + IndexSealed,
{
fn index_mut(&mut self, idx: Int<T>) -> &mut Self::Output {
<T as sealed::IntSliceIndex<[U]>>::index_mut(idx.0, self)
}
}
impl<T: TryInto<usize>> sealed::IntoIntIndex for Range<T>
where
TryFromIntError: From<T::Error>,
{
type IntoIndex = Range<usize>;
fn index(self) -> Result<Range<usize>, TryFromIntError> {
let Range { start, end } = self;
let start: usize = start.try_into()?;
let end: usize = end.try_into()?;
Ok(start..end)
}
}
impl<T: TryInto<usize>> sealed::IntoIntIndex for RangeTo<T>
where
TryFromIntError: From<T::Error>,
{
type IntoIndex = RangeTo<usize>;
fn index(self) -> Result<RangeTo<usize>, TryFromIntError> {
let end: usize = self.end.try_into()?;
Ok(..end)
}
}
impl<T: TryInto<usize>> sealed::IntoIntIndex for RangeFrom<T>
where
TryFromIntError: From<T::Error>,
{
type IntoIndex = RangeFrom<usize>;
fn index(self) -> Result<RangeFrom<usize>, TryFromIntError> {
let start: usize = self.start.try_into()?;
Ok(start..)
}
}
macro_rules! slice_index {
($($t:ty),*) => {
$(slice_index!(@$t);)*
};
(@IntSliceIndex<[U]> for $t:ty: with IntoIntIndex) => {
impl<U> sealed::IntSliceIndex<[U]> for $t {
type Output = <<Self as sealed::IntoIntIndex>::IntoIndex as SliceIndex<[U]>>::Output;
fn get(self, slice: &[U]) -> Option<&Self::Output> {
match IntoIntIndex::index(self) {
Ok(idx) => slice.get(idx),
Err(_) => None,
}
}
fn get_mut(self, slice: &mut [U]) -> Option<&mut Self::Output> {
match IntoIntIndex::index(self) {
Ok(idx) => slice.get_mut(idx),
Err(_) => None,
}
}
unsafe fn get_unchecked(self, slice: &[U]) -> &Self::Output {
match IntoIntIndex::index(self) {
Ok(idx) => slice.get_unchecked(idx),
Err(_) => unreachable_unchecked(),
}
}
unsafe fn get_unchecked_mut(self, slice: &mut [U]) -> &mut Self::Output {
match IntoIntIndex::index(self) {
Ok(idx) => slice.get_unchecked_mut(idx),
Err(_) => unreachable_unchecked(),
}
}
fn index(self, slice: &[U]) -> &Self::Output {
match sealed::IntSliceIndex::get(IndexSealed::copy(&self), slice) {
Some(output) => output,
None => IndexSealed::panic_msg(slice.len(), self),
}
}
fn index_mut(self, slice: &mut [U]) -> &mut Self::Output {
let len = slice.len();
match sealed::IntSliceIndex::get_mut(IndexSealed::copy(&self), slice) {
Some(output) => output,
None => IndexSealed::panic_msg(len, self),
}
}
}
};
(@IntSliceIndex<str> for $t:ty: with IntoIntIndex) => {
impl sealed::IntSliceIndex<str> for $t {
type Output = <<Self as sealed::IntoIntIndex>::IntoIndex as SliceIndex<str>>::Output;
fn get(self, slice: &str) -> Option<&Self::Output> {
match IntoIntIndex::index(self) {
Ok(idx) => slice.get(idx),
Err(_) => None,
}
}
fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
match IntoIntIndex::index(self) {
Ok(idx) => slice.get_mut(idx),
Err(_) => None,
}
}
unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
match IntoIntIndex::index(self) {
Ok(idx) => slice.get_unchecked(idx),
Err(_) => unreachable_unchecked(),
}
}
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
match IntoIntIndex::index(self) {
Ok(idx) => slice.get_unchecked_mut(idx),
Err(_) => unreachable_unchecked(),
}
}
fn index(self, slice: &str) -> &Self::Output {
match sealed::IntSliceIndex::get(IndexSealed::copy(&self), slice) {
Some(output) => output,
None => IndexSealed::panic_msg(slice.len(), self),
}
}
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
let len = slice.len();
match sealed::IntSliceIndex::get_mut(IndexSealed::copy(&self), slice) {
Some(output) => output,
None => IndexSealed::panic_msg(len, self),
}
}
}
};
(@$t:ty) => {
impl sealed::IntoIntIndex for $t {
type IntoIndex = usize;
fn index(self) -> Result<usize, TryFromIntError> {
Ok(self.try_into()?)
}
}
impl sealed::IndexSealed for $t {
#[inline(always)]
fn copy(&self) -> Self { *self }
#[cold]
fn panic_msg(len: usize, index: Self) -> ! {
panic!("index {} out of range for slice of length {}", index, len)
}
}
impl sealed::IndexSealed for Range<$t> {
#[inline(always)]
fn copy(&self) -> Self { Range { .. *self } }
#[cold]
fn panic_msg(len: usize, index: Self) -> ! {
panic!("index {} out of range for slice of length {}", index.end, len)
}
}
impl sealed::IndexSealed for RangeFrom<$t> {
#[inline(always)]
fn copy(&self) -> Self { RangeFrom { .. *self } }
#[cold]
fn panic_msg(len: usize, index: Self) -> ! {
panic!("index {} out of range for slice of length {}", index.start, len)
}
}
impl sealed::IndexSealed for RangeTo<$t> {
#[inline(always)]
fn copy(&self) -> Self { RangeTo { .. *self } }
#[cold]
fn panic_msg(len: usize, index: Self) -> ! {
panic!("index {} out of range for slice of length {}", index.end, len)
}
}
slice_index!(@IntSliceIndex<[U]> for $t: with IntoIntIndex);
slice_index!(@IntSliceIndex<[U]> for Range<$t>: with IntoIntIndex);
slice_index!(@IntSliceIndex<[U]> for RangeTo<$t>: with IntoIntIndex);
slice_index!(@IntSliceIndex<[U]> for RangeFrom<$t>: with IntoIntIndex);
slice_index!(@IntSliceIndex<str> for Range<$t>: with IntoIntIndex);
slice_index!(@IntSliceIndex<str> for RangeTo<$t>: with IntoIntIndex);
slice_index!(@IntSliceIndex<str> for RangeFrom<$t>: with IntoIntIndex);
impl<U> IntSliceIndex<[U]> for $t {}
impl<U> IntSliceIndex<[U]> for Range<$t> {}
impl<U> IntSliceIndex<[U]> for RangeTo<$t> {}
impl<U> IntSliceIndex<[U]> for RangeFrom<$t> {}
impl IntSliceIndex<str> for Range<$t> {}
impl IntSliceIndex<str> for RangeTo<$t> {}
impl IntSliceIndex<str> for RangeFrom<$t> {}
} }
slice_index!(u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize);