From 0e2e6ebffca7d188d1045e7ebb1a84fa29bfbcaf Mon Sep 17 00:00:00 2001 From: Matt Fellenz Date: Tue, 30 May 2023 17:55:16 -0700 Subject: [PATCH 1/2] impl SliceIndex for (Bound, Bound) --- core/src/slice/index.rs | 6 ++--- core/src/slice/mod.rs | 2 +- core/src/str/traits.rs | 52 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/core/src/slice/index.rs b/core/src/slice/index.rs index e1e3bcc05..d313e8e01 100644 --- a/core/src/slice/index.rs +++ b/core/src/slice/index.rs @@ -727,7 +727,7 @@ where } /// Convert pair of `ops::Bound`s into `ops::Range` without performing any bounds checking and (in debug) overflow checking -fn into_range_unchecked( +pub(crate) fn into_range_unchecked( len: usize, (start, end): (ops::Bound, ops::Bound), ) -> ops::Range { @@ -747,7 +747,7 @@ fn into_range_unchecked( /// Convert pair of `ops::Bound`s into `ops::Range`. /// Returns `None` on overflowing indices. -fn into_range( +pub(crate) fn into_range( len: usize, (start, end): (ops::Bound, ops::Bound), ) -> Option> { @@ -772,7 +772,7 @@ fn into_range( /// Convert pair of `ops::Bound`s into `ops::Range`. /// Panics on overflowing indices. -fn into_slice_range( +pub(crate) fn into_slice_range( len: usize, (start, end): (ops::Bound, ops::Bound), ) -> ops::Range { diff --git a/core/src/slice/mod.rs b/core/src/slice/mod.rs index 4f13ea979..d95662afd 100644 --- a/core/src/slice/mod.rs +++ b/core/src/slice/mod.rs @@ -38,7 +38,7 @@ pub mod sort; mod ascii; mod cmp; -mod index; +pub(crate) mod index; mod iter; mod raw; mod rotate; diff --git a/core/src/str/traits.rs b/core/src/str/traits.rs index 1d52335f2..a7d7eff60 100644 --- a/core/src/str/traits.rs +++ b/core/src/str/traits.rs @@ -252,6 +252,58 @@ unsafe impl SliceIndex for ops::Range { } } +/// Implements substring slicing for arbitrary bounds. +/// +/// Returns a slice of the given string bounded by the byte indices +/// provided by each bound. +/// +/// This operation is *O*(1). +/// +/// # Panics +/// +/// Panics if `begin` or `end` (if it exists and once adjusted for +/// inclusion/exclusion) does not point to the starting byte offset of +/// a character (as defined by `is_char_boundary`), if `begin > end`, or if +/// `end > len`. +#[stable(feature = "slice_index_str_with_ops_bound_pair", since = "CURRENT_RUSTC_VERSION")] +unsafe impl SliceIndex for (ops::Bound, ops::Bound) { + type Output = str; + + #[inline] + fn get(self, slice: &str) -> Option<&str> { + crate::slice::index::into_range(slice.len(), self)?.get(slice) + } + + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut str> { + crate::slice::index::into_range(slice.len(), self)?.get_mut(slice) + } + + #[inline] + unsafe fn get_unchecked(self, slice: *const str) -> *const str { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. + unsafe { crate::slice::index::into_range_unchecked(slice.len(), self).get_unchecked(slice) } + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut str { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. + unsafe { + crate::slice::index::into_range_unchecked(slice.len(), self).get_unchecked_mut(slice) + } + } + + #[inline] + fn index(self, slice: &str) -> &str { + crate::slice::index::into_slice_range(slice.len(), self).index(slice) + } + + #[inline] + fn index_mut(self, slice: &mut str) -> &mut str { + crate::slice::index::into_slice_range(slice.len(), self).index_mut(slice) + } +} + /// Implements substring slicing with syntax `&self[.. end]` or `&mut /// self[.. end]`. /// From b497a7c4bedcd72d41fb8696185840f1c1ffee9f Mon Sep 17 00:00:00 2001 From: Matt Fellenz Date: Mon, 31 Jul 2023 11:41:51 -0700 Subject: [PATCH 2/2] Work around missing <*str>::len --- core/src/str/traits.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/str/traits.rs b/core/src/str/traits.rs index a7d7eff60..49f9f6d4a 100644 --- a/core/src/str/traits.rs +++ b/core/src/str/traits.rs @@ -281,16 +281,16 @@ unsafe impl SliceIndex for (ops::Bound, ops::Bound) { #[inline] unsafe fn get_unchecked(self, slice: *const str) -> *const str { + let len = (slice as *const [u8]).len(); // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. - unsafe { crate::slice::index::into_range_unchecked(slice.len(), self).get_unchecked(slice) } + unsafe { crate::slice::index::into_range_unchecked(len, self).get_unchecked(slice) } } #[inline] unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut str { + let len = (slice as *mut [u8]).len(); // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. - unsafe { - crate::slice::index::into_range_unchecked(slice.len(), self).get_unchecked_mut(slice) - } + unsafe { crate::slice::index::into_range_unchecked(len, self).get_unchecked_mut(slice) } } #[inline]