From 26ac2d9264dee6bd2518336830aedd2c5797ac0c Mon Sep 17 00:00:00 2001 From: Jeremy Smart Date: Sat, 6 Sep 2025 01:14:31 -0400 Subject: [PATCH 1/2] add SliceIndex wrapper types Last and Clamp --- library/core/src/index.rs | 228 ++++++++++++++++++++++++++++++++ library/core/src/lib.rs | 1 + library/core/src/slice/index.rs | 5 + 3 files changed, 234 insertions(+) create mode 100644 library/core/src/index.rs diff --git a/library/core/src/index.rs b/library/core/src/index.rs new file mode 100644 index 0000000000000..c2d520f537be5 --- /dev/null +++ b/library/core/src/index.rs @@ -0,0 +1,228 @@ +use crate::intrinsics::slice_get_unchecked; +use crate::range; +use crate::slice::SliceIndex; + +#[unstable(feature = "sliceindex_wrappers", issue = "146179")] +pub struct Clamp(pub Idx); + +#[unstable(feature = "sliceindex_wrappers", issue = "146179")] +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..self.0.end.min(slice.len())).get(slice) + } + + fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output> { + (self.0.start..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..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..self.0.end.min(slice.len())).get_unchecked_mut(slice) } + } + + fn index(self, slice: &[T]) -> &Self::Output { + (self.0.start..self.0.end.min(slice.len())).index(slice) + } + + fn index_mut(self, slice: &mut [T]) -> &mut Self::Output { + (self.0.start..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..=self.0.end.min(slice.len() - 1)).get(slice) + } + + fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output> { + (self.0.start..=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..=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..=self.0.end.min(slice.len() - 1)).get_unchecked_mut(slice) } + } + + fn index(self, slice: &[T]) -> &Self::Output { + (self.0.start..=self.0.end.min(slice.len() - 1)).index(slice) + } + + fn index_mut(self, slice: &mut [T]) -> &mut Self::Output { + (self.0.start..=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..slice.len()).get(slice) + } + + fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output> { + (self.0.start..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..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..slice.len()).get_unchecked_mut(slice) } + } + + fn index(self, slice: &[T]) -> &Self::Output { + (self.0.start..slice.len()).index(slice) + } + + fn index_mut(self, slice: &mut [T]) -> &mut Self::Output { + (self.0.start..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> { + (0..self.0.end.min(slice.len())).get(slice) + } + + fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output> { + (0..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 { (0..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 { (0..self.0.end.min(slice.len())).get_unchecked_mut(slice) } + } + + fn index(self, slice: &[T]) -> &Self::Output { + (0..self.0.end.min(slice.len())).index(slice) + } + + fn index_mut(self, slice: &mut [T]) -> &mut Self::Output { + (0..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> { + (0..=self.0.end.min(slice.len() - 1)).get(slice) + } + + fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output> { + (0..=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 { (0..=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 { (0..=self.0.end.min(slice.len() - 1)).get_unchecked_mut(slice) } + } + + fn index(self, slice: &[T]) -> &Self::Output { + (0..=self.0.end.min(slice.len() - 1)).index(slice) + } + + fn index_mut(self, slice: &mut [T]) -> &mut Self::Output { + (0..=self.0.end.min(slice.len() - 1)).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. From 18e44d5c17fe5c4fbd80c6645f54a8e3207c75eb Mon Sep 17 00:00:00 2001 From: Jeremy Smart Date: Sat, 6 Sep 2025 05:30:07 +0000 Subject: [PATCH 2/2] Update lib.rs --- library/core/src/index.rs | 203 ++++++++++++++++++++++++++++++++------ 1 file changed, 171 insertions(+), 32 deletions(-) diff --git a/library/core/src/index.rs b/library/core/src/index.rs index c2d520f537be5..ba3bbd720906e 100644 --- a/library/core/src/index.rs +++ b/library/core/src/index.rs @@ -1,11 +1,47 @@ +#![unstable(feature = "sliceindex_wrappers", issue = "146179")] + +//! Helper types for indexing slices. + use crate::intrinsics::slice_get_unchecked; -use crate::range; 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")] @@ -44,29 +80,64 @@ unsafe impl SliceIndex<[T]> for Clamp> { type Output = [T]; fn get(self, slice: &[T]) -> Option<&Self::Output> { - (self.0.start..self.0.end.min(slice.len())).get(slice) + (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..self.0.end.min(slice.len())).get_mut(slice) + (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..self.0.end.min(slice.len())).get_unchecked(slice) } + 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..self.0.end.min(slice.len())).get_unchecked_mut(slice) } + 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..self.0.end.min(slice.len())).index(slice) + (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..self.0.end.min(slice.len())).index_mut(slice) + (self.0.start.min(slice.len())..self.0.end.min(slice.len())).index_mut(slice) } } @@ -75,29 +146,35 @@ unsafe impl SliceIndex<[T]> for Clamp> { type Output = [T]; fn get(self, slice: &[T]) -> Option<&Self::Output> { - (self.0.start..=self.0.end.min(slice.len() - 1)).get(slice) + (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..=self.0.end.min(slice.len() - 1)).get_mut(slice) + (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..=self.0.end.min(slice.len() - 1)).get_unchecked(slice) } + 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..=self.0.end.min(slice.len() - 1)).get_unchecked_mut(slice) } + 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..=self.0.end.min(slice.len() - 1)).index(slice) + (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..=self.0.end.min(slice.len() - 1)).index_mut(slice) + (self.0.start.min(slice.len() - 1)..=self.0.end.min(slice.len() - 1)).index_mut(slice) } } @@ -106,29 +183,60 @@ unsafe impl SliceIndex<[T]> for Clamp> { type Output = [T]; fn get(self, slice: &[T]) -> Option<&Self::Output> { - (self.0.start..slice.len()).get(slice) + (self.0.start.min(slice.len() - 1)..).get(slice) } fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output> { - (self.0.start..slice.len()).get_mut(slice) + (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..slice.len()).get_unchecked(slice) } + 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..slice.len()).get_unchecked_mut(slice) } + unsafe { (self.0.start.min(slice.len() - 1)..).get_unchecked_mut(slice) } } fn index(self, slice: &[T]) -> &Self::Output { - (self.0.start..slice.len()).index(slice) + (self.0.start.min(slice.len() - 1)..).index(slice) } fn index_mut(self, slice: &mut [T]) -> &mut Self::Output { - (self.0.start..slice.len()).index_mut(slice) + (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) } } @@ -137,29 +245,29 @@ unsafe impl SliceIndex<[T]> for Clamp> { type Output = [T]; fn get(self, slice: &[T]) -> Option<&Self::Output> { - (0..self.0.end.min(slice.len())).get(slice) + (..self.0.end.min(slice.len())).get(slice) } fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output> { - (0..self.0.end.min(slice.len())).get_mut(slice) + (..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 { (0..self.0.end.min(slice.len())).get_unchecked(slice) } + 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 { (0..self.0.end.min(slice.len())).get_unchecked_mut(slice) } + unsafe { (..self.0.end.min(slice.len())).get_unchecked_mut(slice) } } fn index(self, slice: &[T]) -> &Self::Output { - (0..self.0.end.min(slice.len())).index(slice) + (..self.0.end.min(slice.len())).index(slice) } fn index_mut(self, slice: &mut [T]) -> &mut Self::Output { - (0..self.0.end.min(slice.len())).index_mut(slice) + (..self.0.end.min(slice.len())).index_mut(slice) } } @@ -168,29 +276,60 @@ unsafe impl SliceIndex<[T]> for Clamp> { type Output = [T]; fn get(self, slice: &[T]) -> Option<&Self::Output> { - (0..=self.0.end.min(slice.len() - 1)).get(slice) + (..=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> { - (0..=self.0.end.min(slice.len() - 1)).get_mut(slice) + (..).get_mut(slice) } unsafe fn get_unchecked(self, slice: *const [T]) -> *const Self::Output { // SAFETY: the index before the length is always valid - unsafe { (0..=self.0.end.min(slice.len() - 1)).get_unchecked(slice) } + 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 { (0..=self.0.end.min(slice.len() - 1)).get_unchecked_mut(slice) } + unsafe { (..).get_unchecked_mut(slice) } } fn index(self, slice: &[T]) -> &Self::Output { - (0..=self.0.end.min(slice.len() - 1)).index(slice) + (..).index(slice) } fn index_mut(self, slice: &mut [T]) -> &mut Self::Output { - (0..=self.0.end.min(slice.len() - 1)).index_mut(slice) + (..).index_mut(slice) } }