diff --git a/library/core/src/index.rs b/library/core/src/index.rs new file mode 100644 index 0000000000000..ba3bbd720906e --- /dev/null +++ b/library/core/src/index.rs @@ -0,0 +1,367 @@ +#![unstable(feature = "sliceindex_wrappers", issue = "146179")] + +//! Helper types for indexing slices. + +use crate::intrinsics::slice_get_unchecked; +use crate::slice::SliceIndex; +use crate::{ops, range}; + +/// Clamps an index, guaranteeing that it will only access valid elements of the slice. +/// +/// # Examples +/// +/// ``` +/// #![feature(sliceindex_wrappers)] +/// +/// use core::index::Clamp; +/// +/// let s: &[usize] = &[0, 1, 2, 3]; +/// +/// assert_eq!(&3, &s[Clamp(6)]); +/// assert_eq!(&[1, 2, 3], &s[Clamp(1..6)]); +/// assert_eq!(&[0, 1, 2, 3], &s[Clamp(..6)]); +/// assert_eq!(&[0, 1, 2, 3], &s[Clamp(..6)]); +/// assert_eq!(&[0, 1, 2, 3], &s[Clamp(..=6)]); +/// assert_eq!(&[3], &s[Clamp(6..)]); +/// ``` +#[unstable(feature = "sliceindex_wrappers", issue = "146179")] +#[derive(Debug)] +pub struct Clamp(pub Idx); + +/// Always accesses the last element of the slice. +/// +/// # Examples +/// +/// ``` +/// #![feature(sliceindex_wrappers)] +/// +/// use core::index::Last; +/// +/// let s = &[0, 1, 2, 3]; +/// +/// assert_eq!(&3, &s[Last]); +#[unstable(feature = "sliceindex_wrappers", issue = "146179")] +#[derive(Debug)] +pub struct Last; + +#[unstable(feature = "sliceindex_wrappers", issue = "146179")] +unsafe impl SliceIndex<[T]> for Clamp { + type Output = T; + + fn get(self, slice: &[T]) -> Option<&Self::Output> { + slice.get(self.0.min(slice.len() - 1)) + } + + fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output> { + slice.get_mut(self.0.min(slice.len() - 1)) + } + + unsafe fn get_unchecked(self, slice: *const [T]) -> *const Self::Output { + // SAFETY: the index before the length is always valid + unsafe { slice_get_unchecked(slice, self.0.min(slice.len() - 1)) } + } + + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut Self::Output { + // SAFETY: the index before the length is always valid + unsafe { slice_get_unchecked(slice, self.0.min(slice.len() - 1)) } + } + + fn index(self, slice: &[T]) -> &Self::Output { + &(*slice)[self.0.min(slice.len() - 1)] + } + + fn index_mut(self, slice: &mut [T]) -> &mut Self::Output { + &mut (*slice)[self.0.min(slice.len() - 1)] + } +} + +#[unstable(feature = "sliceindex_wrappers", issue = "146179")] +unsafe impl SliceIndex<[T]> for Clamp> { + type Output = [T]; + + fn get(self, slice: &[T]) -> Option<&Self::Output> { + (self.0.start.min(slice.len())..self.0.end.min(slice.len())).get(slice) + } + + fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output> { + (self.0.start.min(slice.len())..self.0.end.min(slice.len())).get_mut(slice) + } + + unsafe fn get_unchecked(self, slice: *const [T]) -> *const Self::Output { + // SAFETY: a range ending before len is always valid + unsafe { (self.0.start.min(slice.len())..self.0.end.min(slice.len())).get_unchecked(slice) } + } + + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut Self::Output { + // SAFETY: a range ending before len is always valid + unsafe { + (self.0.start.min(slice.len())..self.0.end.min(slice.len())).get_unchecked_mut(slice) + } + } + + fn index(self, slice: &[T]) -> &Self::Output { + (self.0.start.min(slice.len())..self.0.end.min(slice.len())).index(slice) + } + + fn index_mut(self, slice: &mut [T]) -> &mut Self::Output { + (self.0.start.min(slice.len())..self.0.end.min(slice.len())).index_mut(slice) + } +} + +#[unstable(feature = "sliceindex_wrappers", issue = "146179")] +unsafe impl SliceIndex<[T]> for Clamp> { + type Output = [T]; + + fn get(self, slice: &[T]) -> Option<&Self::Output> { + (self.0.start.min(slice.len())..self.0.end.min(slice.len())).get(slice) + } + + fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output> { + (self.0.start.min(slice.len())..self.0.end.min(slice.len())).get_mut(slice) + } + + unsafe fn get_unchecked(self, slice: *const [T]) -> *const Self::Output { + // SAFETY: a range ending before len is always valid + unsafe { (self.0.start.min(slice.len())..self.0.end.min(slice.len())).get_unchecked(slice) } + } + + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut Self::Output { + // SAFETY: a range ending before len is always valid + unsafe { + (self.0.start.min(slice.len())..self.0.end.min(slice.len())).get_unchecked_mut(slice) + } + } + + fn index(self, slice: &[T]) -> &Self::Output { + (self.0.start.min(slice.len())..self.0.end.min(slice.len())).index(slice) + } + + fn index_mut(self, slice: &mut [T]) -> &mut Self::Output { + (self.0.start.min(slice.len())..self.0.end.min(slice.len())).index_mut(slice) + } +} + +#[unstable(feature = "sliceindex_wrappers", issue = "146179")] +unsafe impl SliceIndex<[T]> for Clamp> { + type Output = [T]; + + fn get(self, slice: &[T]) -> Option<&Self::Output> { + (self.0.start.min(slice.len() - 1)..=self.0.end.min(slice.len() - 1)).get(slice) + } + + fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output> { + (self.0.start.min(slice.len() - 1)..=self.0.end.min(slice.len() - 1)).get_mut(slice) + } + + unsafe fn get_unchecked(self, slice: *const [T]) -> *const Self::Output { + // SAFETY: the index before the length is always valid + unsafe { + (self.0.start.min(slice.len() - 1)..=self.0.end.min(slice.len() - 1)) + .get_unchecked(slice) + } + } + + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut Self::Output { + // SAFETY: the index before the length is always valid + unsafe { + (self.0.start.min(slice.len() - 1)..=self.0.end.min(slice.len() - 1)) + .get_unchecked_mut(slice) + } + } + + fn index(self, slice: &[T]) -> &Self::Output { + (self.0.start.min(slice.len() - 1)..=self.0.end.min(slice.len() - 1)).index(slice) + } + + fn index_mut(self, slice: &mut [T]) -> &mut Self::Output { + (self.0.start.min(slice.len() - 1)..=self.0.end.min(slice.len() - 1)).index_mut(slice) + } +} + +#[unstable(feature = "sliceindex_wrappers", issue = "146179")] +unsafe impl SliceIndex<[T]> for Clamp> { + type Output = [T]; + + fn get(self, slice: &[T]) -> Option<&Self::Output> { + (self.0.start.min(slice.len() - 1)..).get(slice) + } + + fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output> { + (self.0.start.min(slice.len() - 1)..).get_mut(slice) + } + + unsafe fn get_unchecked(self, slice: *const [T]) -> *const Self::Output { + // SAFETY: a range ending before len is always valid + unsafe { (self.0.start.min(slice.len() - 1)..).get_unchecked(slice) } + } + + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut Self::Output { + // SAFETY: a range ending before len is always valid + unsafe { (self.0.start.min(slice.len() - 1)..).get_unchecked_mut(slice) } + } + + fn index(self, slice: &[T]) -> &Self::Output { + (self.0.start.min(slice.len() - 1)..).index(slice) + } + + fn index_mut(self, slice: &mut [T]) -> &mut Self::Output { + (self.0.start.min(slice.len() - 1)..).index_mut(slice) + } +} + +#[unstable(feature = "sliceindex_wrappers", issue = "146179")] +unsafe impl SliceIndex<[T]> for Clamp> { + type Output = [T]; + + fn get(self, slice: &[T]) -> Option<&Self::Output> { + (self.0.start.min(slice.len() - 1)..).get(slice) + } + + fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output> { + (self.0.start.min(slice.len() - 1)..).get_mut(slice) + } + + unsafe fn get_unchecked(self, slice: *const [T]) -> *const Self::Output { + // SAFETY: a range ending before len is always valid + unsafe { (self.0.start.min(slice.len() - 1)..).get_unchecked(slice) } + } + + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut Self::Output { + // SAFETY: a range ending before len is always valid + unsafe { (self.0.start.min(slice.len() - 1)..).get_unchecked_mut(slice) } + } + + fn index(self, slice: &[T]) -> &Self::Output { + (self.0.start.min(slice.len() - 1)..).index(slice) + } + + fn index_mut(self, slice: &mut [T]) -> &mut Self::Output { + (self.0.start.min(slice.len() - 1)..).index_mut(slice) + } +} + +#[unstable(feature = "sliceindex_wrappers", issue = "146179")] +unsafe impl SliceIndex<[T]> for Clamp> { + type Output = [T]; + + fn get(self, slice: &[T]) -> Option<&Self::Output> { + (..self.0.end.min(slice.len())).get(slice) + } + + fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output> { + (..self.0.end.min(slice.len())).get_mut(slice) + } + + unsafe fn get_unchecked(self, slice: *const [T]) -> *const Self::Output { + // SAFETY: a range ending before len is always valid + unsafe { (..self.0.end.min(slice.len())).get_unchecked(slice) } + } + + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut Self::Output { + // SAFETY: a range ending before len is always valid + unsafe { (..self.0.end.min(slice.len())).get_unchecked_mut(slice) } + } + + fn index(self, slice: &[T]) -> &Self::Output { + (..self.0.end.min(slice.len())).index(slice) + } + + fn index_mut(self, slice: &mut [T]) -> &mut Self::Output { + (..self.0.end.min(slice.len())).index_mut(slice) + } +} + +#[unstable(feature = "sliceindex_wrappers", issue = "146179")] +unsafe impl SliceIndex<[T]> for Clamp> { + type Output = [T]; + + fn get(self, slice: &[T]) -> Option<&Self::Output> { + (..=self.0.end.min(slice.len() - 1)).get(slice) + } + + fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output> { + (..=self.0.end.min(slice.len() - 1)).get_mut(slice) + } + + unsafe fn get_unchecked(self, slice: *const [T]) -> *const Self::Output { + // SAFETY: the index before the length is always valid + unsafe { (..=self.0.end.min(slice.len() - 1)).get_unchecked(slice) } + } + + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut Self::Output { + // SAFETY: the index before the length is always valid + unsafe { (..=self.0.end.min(slice.len() - 1)).get_unchecked_mut(slice) } + } + + fn index(self, slice: &[T]) -> &Self::Output { + (..=self.0.end.min(slice.len() - 1)).index(slice) + } + + fn index_mut(self, slice: &mut [T]) -> &mut Self::Output { + (..=self.0.end.min(slice.len() - 1)).index_mut(slice) + } +} + +#[unstable(feature = "sliceindex_wrappers", issue = "146179")] +unsafe impl SliceIndex<[T]> for Clamp { + type Output = [T]; + + fn get(self, slice: &[T]) -> Option<&Self::Output> { + (..).get(slice) + } + + fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output> { + (..).get_mut(slice) + } + + unsafe fn get_unchecked(self, slice: *const [T]) -> *const Self::Output { + // SAFETY: the index before the length is always valid + unsafe { (..).get_unchecked(slice) } + } + + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut Self::Output { + // SAFETY: the index before the length is always valid + unsafe { (..).get_unchecked_mut(slice) } + } + + fn index(self, slice: &[T]) -> &Self::Output { + (..).index(slice) + } + + fn index_mut(self, slice: &mut [T]) -> &mut Self::Output { + (..).index_mut(slice) + } +} + +#[unstable(feature = "sliceindex_wrappers", issue = "146179")] +unsafe impl SliceIndex<[T]> for Last { + type Output = T; + + fn get(self, slice: &[T]) -> Option<&Self::Output> { + slice.last() + } + + fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output> { + slice.last_mut() + } + + unsafe fn get_unchecked(self, slice: *const [T]) -> *const Self::Output { + // SAFETY: the index before the length is always valid + unsafe { slice_get_unchecked(slice, slice.len() - 1) } + } + + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut Self::Output { + // SAFETY: the index before the length is always valid + unsafe { slice_get_unchecked(slice, slice.len() - 1) } + } + + fn index(self, slice: &[T]) -> &Self::Output { + // N.B., use intrinsic indexing + &(*slice)[slice.len() - 1] + } + + fn index_mut(self, slice: &mut [T]) -> &mut Self::Output { + // N.B., use intrinsic indexing + &mut (*slice)[slice.len() - 1] + } +} diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index c306011bdda39..22237c24fd09a 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -323,6 +323,7 @@ pub mod cmp; pub mod convert; pub mod default; pub mod error; +pub mod index; pub mod marker; pub mod ops; diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index 98091e9fe83fb..82a7914b71683 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -132,6 +132,11 @@ mod private_slice_index { impl Sealed for range::RangeFrom {} impl Sealed for ops::IndexRange {} + + #[unstable(feature = "sliceindex_wrappers", issue = "146179")] + impl Sealed for crate::index::Last {} + #[unstable(feature = "sliceindex_wrappers", issue = "146179")] + impl Sealed for crate::index::Clamp {} } /// A helper trait used for indexing operations.