diff --git a/library/core/src/bstr/traits.rs b/library/core/src/bstr/traits.rs index ff46bb13ba4eb..427278df1babf 100644 --- a/library/core/src/bstr/traits.rs +++ b/library/core/src/bstr/traits.rs @@ -274,4 +274,5 @@ impl_slice_index!(range::RangeFrom); impl_slice_index!(ops::RangeInclusive); impl_slice_index!(range::RangeInclusive); impl_slice_index!(ops::RangeToInclusive); +impl_slice_index!(range::RangeToInclusive); impl_slice_index!((ops::Bound, ops::Bound)); diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 621277179bb38..5fc97d9a69efd 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -8,7 +8,7 @@ use crate::iter::FusedIterator; use crate::marker::PhantomData; use crate::ptr::NonNull; use crate::slice::memchr; -use crate::{fmt, ops, slice, str}; +use crate::{fmt, ops, range, slice, str}; // FIXME: because this is doc(inline)d, we *have* to use intra-doc links because the actual link // depends on where the item is being documented. however, since this is libcore, we can't @@ -716,6 +716,16 @@ impl ops::Index> for CStr { } } +#[unstable(feature = "new_range_api", issue = "125687")] +impl ops::Index> for CStr { + type Output = CStr; + + #[inline] + fn index(&self, index: range::RangeFrom) -> &CStr { + ops::Index::index(self, ops::RangeFrom::from(index)) + } +} + #[stable(feature = "cstring_asref", since = "1.7.0")] #[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const AsRef for CStr { diff --git a/library/core/src/range.rs b/library/core/src/range.rs index fe488355ad15c..b86b20fb50af6 100644 --- a/library/core/src/range.rs +++ b/library/core/src/range.rs @@ -43,7 +43,7 @@ pub use iter::{RangeFromIter, RangeIter}; // pub use crate::ops::{Bound, IntoBounds, OneSidedRange, RangeBounds, RangeFull, RangeTo}; use crate::iter::Step; use crate::ops::Bound::{self, Excluded, Included, Unbounded}; -use crate::ops::{IntoBounds, RangeBounds}; +use crate::ops::{IntoBounds, OneSidedRange, OneSidedRangeBound, RangeBounds}; /// A (half-open) range bounded inclusively below and exclusively above /// (`start..end` in a future edition). @@ -555,6 +555,18 @@ impl const IntoBounds for RangeFrom { } } +#[unstable(feature = "one_sided_range", issue = "69780")] +// #[unstable(feature = "new_range_api", issue = "125687")] +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const OneSidedRange for RangeFrom +where + Self: RangeBounds, +{ + fn bound(self) -> (OneSidedRangeBound, T) { + (OneSidedRangeBound::StartInclusive, self.start) + } +} + #[unstable(feature = "new_range_api", issue = "125687")] #[rustc_const_unstable(feature = "const_index", issue = "143775")] impl const From> for legacy::RangeFrom { @@ -582,9 +594,8 @@ impl const From> for RangeFrom { /// The `..=last` syntax is a `RangeToInclusive`: /// /// ``` -/// #![feature(new_range_api)] /// #![feature(new_range)] -/// assert_eq!((..=5), std::range::RangeToInclusive{ last: 5 }); +/// assert_eq!((..=5), std::range::RangeToInclusive { last: 5 }); /// ``` /// /// It does not have an [`IntoIterator`] implementation, so you can't use it in a @@ -615,14 +626,14 @@ impl const From> for RangeFrom { #[lang = "RangeToInclusiveCopy"] #[doc(alias = "..=")] #[derive(Copy, Clone, PartialEq, Eq, Hash)] -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")] pub struct RangeToInclusive { /// The upper bound of the range (inclusive) - #[unstable(feature = "new_range_api", issue = "125687")] + #[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")] pub last: Idx, } -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")] impl fmt::Debug for RangeToInclusive { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { write!(fmt, "..=")?; @@ -646,7 +657,7 @@ impl> RangeToInclusive { /// assert!(!(..=f32::NAN).contains(&0.5)); /// ``` #[inline] - #[unstable(feature = "new_range_api", issue = "125687")] + #[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_range", issue = "none")] pub const fn contains(&self, item: &U) -> bool where @@ -657,13 +668,13 @@ impl> RangeToInclusive { } } -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")] impl From> for RangeToInclusive { fn from(value: legacy::RangeToInclusive) -> Self { Self { last: value.end } } } -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")] impl From> for legacy::RangeToInclusive { fn from(value: RangeToInclusive) -> Self { Self { end: value.last } @@ -673,7 +684,7 @@ impl From> for legacy::RangeToInclusive { // RangeToInclusive cannot impl From> // because underflow would be possible with (..0).into() -#[unstable(feature = "new_range_api", issue = "125687")] +#[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_range", issue = "none")] impl const RangeBounds for RangeToInclusive { fn start_bound(&self) -> Bound<&T> { @@ -684,6 +695,18 @@ impl const RangeBounds for RangeToInclusive { } } +#[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const RangeBounds for RangeToInclusive<&T> { + fn start_bound(&self) -> Bound<&T> { + Unbounded + } + fn end_bound(&self) -> Bound<&T> { + Included(self.last) + } +} + +// #[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")] #[unstable(feature = "range_into_bounds", issue = "136903")] #[rustc_const_unstable(feature = "const_range", issue = "none")] impl const IntoBounds for RangeToInclusive { @@ -691,3 +714,15 @@ impl const IntoBounds for RangeToInclusive { (Unbounded, Included(self.last)) } } + +// #[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")] +#[unstable(feature = "one_sided_range", issue = "69780")] +#[rustc_const_unstable(feature = "const_range", issue = "none")] +impl const OneSidedRange for RangeToInclusive +where + Self: RangeBounds, +{ + fn bound(self) -> (OneSidedRangeBound, T) { + (OneSidedRangeBound::EndInclusive, self.last) + } +} diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index 31d9931e474a6..dacb5d4519bda 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -129,7 +129,7 @@ mod private_slice_index { impl Sealed for range::Range {} #[stable(feature = "new_range_inclusive_api", since = "CURRENT_RUSTC_VERSION")] impl Sealed for range::RangeInclusive {} - #[unstable(feature = "new_range_api", issue = "125687")] + #[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")] impl Sealed for range::RangeToInclusive {} #[unstable(feature = "new_range_api", issue = "125687")] impl Sealed for range::RangeFrom {} @@ -802,7 +802,7 @@ unsafe impl const SliceIndex<[T]> for ops::RangeToInclusive { } /// The methods `index` and `index_mut` panic if the end of the range is out of bounds. -#[stable(feature = "inclusive_range", since = "1.26.0")] +#[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")] #[rustc_const_unstable(feature = "const_index", issue = "143775")] unsafe impl const SliceIndex<[T]> for range::RangeToInclusive { type Output = [T]; diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index b63fe96ea99d5..86d8944dc6850 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -756,6 +756,52 @@ unsafe impl const SliceIndex for ops::RangeToInclusive { } } +/// Implements substring slicing with syntax `&self[..= last]` or `&mut +/// self[..= last]`. +/// +/// Returns a slice of the given string from the byte range \[0, `last`\]. +/// Equivalent to `&self [0 .. last + 1]`, except if `last` has the maximum +/// value for `usize`. +/// +/// This operation is *O*(1). +/// +/// # Panics +/// +/// Panics if `last` does not point to the ending byte offset of a character +/// (`last + 1` is either a starting byte offset as defined by +/// `is_char_boundary`, or equal to `len`), or if `last >= len`. +#[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_unstable(feature = "const_index", issue = "143775")] +unsafe impl const SliceIndex for range::RangeToInclusive { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + (0..=self.last).get(slice) + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + (0..=self.last).get_mut(slice) + } + #[inline] + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { + // SAFETY: the caller must uphold the safety contract for `get_unchecked`. + unsafe { (0..=self.last).get_unchecked(slice) } + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { + // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`. + unsafe { (0..=self.last).get_unchecked_mut(slice) } + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + (0..=self.last).index(slice) + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + (0..=self.last).index_mut(slice) + } +} + /// Parse a value from a string /// /// `FromStr`'s [`from_str`] method is often used implicitly, through diff --git a/tests/ui/range/new_range_stability.rs b/tests/ui/range/new_range_stability.rs index 7200e1ac95d27..2d129fb6815f5 100644 --- a/tests/ui/range/new_range_stability.rs +++ b/tests/ui/range/new_range_stability.rs @@ -1,8 +1,10 @@ // Stable -use std::range::{RangeInclusive, RangeInclusiveIter}; +use std::range::{RangeInclusive, RangeInclusiveIter, RangeToInclusive}; fn range_inclusive(mut r: RangeInclusive) { + &[1, 2, 3][r]; // Indexing + r.start; r.last; r.contains(&5); @@ -14,6 +16,13 @@ fn range_inclusive(mut r: RangeInclusive) { i.remainder(); } +fn range_to_inclusive(mut r: RangeToInclusive) { + &[1, 2, 3][r]; // Indexing + + r.last; + r.contains(&5); +} + // Unstable module use std::range::legacy; //~ ERROR unstable diff --git a/tests/ui/range/new_range_stability.stderr b/tests/ui/range/new_range_stability.stderr index 871d691794ff0..b5a7e06e5f2ea 100644 --- a/tests/ui/range/new_range_stability.stderr +++ b/tests/ui/range/new_range_stability.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature `new_range_api` - --> $DIR/new_range_stability.rs:19:5 + --> $DIR/new_range_stability.rs:28:5 | LL | use std::range::legacy; | ^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | use std::range::legacy; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `new_range_api` - --> $DIR/new_range_stability.rs:23:5 + --> $DIR/new_range_stability.rs:32:5 | LL | use std::range::RangeFrom; | ^^^^^^^^^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | use std::range::RangeFrom; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `new_range_api` - --> $DIR/new_range_stability.rs:24:5 + --> $DIR/new_range_stability.rs:33:5 | LL | use std::range::Range; | ^^^^^^^^^^^^^^^^^ @@ -29,7 +29,7 @@ LL | use std::range::Range; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `new_range_api` - --> $DIR/new_range_stability.rs:25:5 + --> $DIR/new_range_stability.rs:34:5 | LL | use std::range::RangeFromIter; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -39,7 +39,7 @@ LL | use std::range::RangeFromIter; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `new_range_api` - --> $DIR/new_range_stability.rs:26:5 + --> $DIR/new_range_stability.rs:35:5 | LL | use std::range::RangeIter; | ^^^^^^^^^^^^^^^^^^^^^