Rollup merge of #152304 - pitaj:stabilize-new_range_api, r=tgross35

stabilize new RangeToInclusive type

stabilizes `core::range::RangeToInclusive`

```rust
// in core::range

pub struct RangeToInclusive<Idx> {
    pub last: Idx,
}

impl<Idx: fmt::Debug> fmt::Debug for RangeInclusive<Idx> { /* ... */ }

impl<Idx: PartialOrd<Idx>> RangeToInclusive<Idx> {
    pub const fn contains<U>(&self, item: &U) -> bool
    where
        Idx: [const] PartialOrd<U>,
        U: ?Sized + [const] PartialOrd<Idx>;
}

impl<T> const RangeBounds<T> for RangeToInclusive<T> { /* ... */ }
impl<T> const RangeBounds<T> for RangeToInclusive<&T> { /* ... */ }

impl<T> const From<RangeToInclusive<T>> for legacy::RangeToInclusive<T> { /* ... */ }
impl<T> const From<legacy::RangeToInclusive<T>> for RangeToInclusive<T> { /* ... */ }

unsafe impl<T> const SliceIndex<[T]> for range::RangeToInclusive<usize> {
    type Output = [T];
    /* ... */
}
unsafe impl const SliceIndex<str> for range::RangeToInclusive<usize> {
    type Output = str;
    /* ... */
}
```

Tracking issue: https://github.com/rust-lang/rust/issues/125687
This commit is contained in:
Jonathan Brouwer
2026-03-02 09:49:22 +01:00
committed by GitHub
7 changed files with 120 additions and 19 deletions
+1
View File
@@ -268,4 +268,5 @@ fn index_mut(self, slice: &mut ByteStr) -> &mut Self::Output {
impl_slice_index!(ops::RangeInclusive<usize>);
impl_slice_index!(range::RangeInclusive<usize>);
impl_slice_index!(ops::RangeToInclusive<usize>);
impl_slice_index!(range::RangeToInclusive<usize>);
impl_slice_index!((ops::Bound<usize>, ops::Bound<usize>));
+11 -1
View File
@@ -8,7 +8,7 @@
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 @@ fn index(&self, index: ops::RangeFrom<usize>) -> &CStr {
}
}
#[unstable(feature = "new_range_api", issue = "125687")]
impl ops::Index<range::RangeFrom<usize>> for CStr {
type Output = CStr;
#[inline]
fn index(&self, index: range::RangeFrom<usize>) -> &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<CStr> for CStr {
+45 -10
View File
@@ -43,7 +43,7 @@
// 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).
@@ -546,6 +546,18 @@ fn into_bounds(self) -> (Bound<T>, Bound<T>) {
}
}
#[unstable(feature = "one_sided_range", issue = "69780")]
// #[unstable(feature = "new_range_api", issue = "125687")]
#[rustc_const_unstable(feature = "const_range", issue = "none")]
impl<T> const OneSidedRange<T> for RangeFrom<T>
where
Self: RangeBounds<T>,
{
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<T> const From<RangeFrom<T>> for legacy::RangeFrom<T> {
@@ -573,9 +585,8 @@ fn from(value: legacy::RangeFrom<T>) -> Self {
/// 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
@@ -606,14 +617,14 @@ fn from(value: legacy::RangeFrom<T>) -> Self {
#[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<Idx> {
/// 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<Idx: fmt::Debug> fmt::Debug for RangeToInclusive<Idx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "..=")?;
@@ -637,7 +648,7 @@ impl<Idx: PartialOrd<Idx>> RangeToInclusive<Idx> {
/// 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<U>(&self, item: &U) -> bool
where
@@ -648,13 +659,13 @@ pub const fn contains<U>(&self, item: &U) -> bool
}
}
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")]
impl<T> From<legacy::RangeToInclusive<T>> for RangeToInclusive<T> {
fn from(value: legacy::RangeToInclusive<T>) -> Self {
Self { last: value.end }
}
}
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")]
impl<T> From<RangeToInclusive<T>> for legacy::RangeToInclusive<T> {
fn from(value: RangeToInclusive<T>) -> Self {
Self { end: value.last }
@@ -664,7 +675,7 @@ fn from(value: RangeToInclusive<T>) -> Self {
// RangeToInclusive<Idx> cannot impl From<RangeTo<Idx>>
// 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<T> const RangeBounds<T> for RangeToInclusive<T> {
fn start_bound(&self) -> Bound<&T> {
@@ -675,6 +686,18 @@ fn end_bound(&self) -> Bound<&T> {
}
}
#[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_unstable(feature = "const_range", issue = "none")]
impl<T> const RangeBounds<T> 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<T> const IntoBounds<T> for RangeToInclusive<T> {
@@ -682,3 +705,15 @@ fn into_bounds(self) -> (Bound<T>, Bound<T>) {
(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<T> const OneSidedRange<T> for RangeToInclusive<T>
where
Self: RangeBounds<T>,
{
fn bound(self) -> (OneSidedRangeBound, T) {
(OneSidedRangeBound::EndInclusive, self.last)
}
}
+2 -2
View File
@@ -129,7 +129,7 @@ impl Sealed for (ops::Bound<usize>, ops::Bound<usize>) {}
impl Sealed for range::Range<usize> {}
#[stable(feature = "new_range_inclusive_api", since = "CURRENT_RUSTC_VERSION")]
impl Sealed for range::RangeInclusive<usize> {}
#[unstable(feature = "new_range_api", issue = "125687")]
#[stable(feature = "new_range_to_inclusive_api", since = "CURRENT_RUSTC_VERSION")]
impl Sealed for range::RangeToInclusive<usize> {}
#[unstable(feature = "new_range_api", issue = "125687")]
impl Sealed for range::RangeFrom<usize> {}
@@ -801,7 +801,7 @@ fn index_mut(self, slice: &mut [T]) -> &mut [T] {
}
/// 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<T> const SliceIndex<[T]> for range::RangeToInclusive<usize> {
type Output = [T];
+46
View File
@@ -763,6 +763,52 @@ fn index_mut(self, slice: &mut str) -> &mut Self::Output {
}
}
/// 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<str> for range::RangeToInclusive<usize> {
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
+10 -1
View File
@@ -1,8 +1,10 @@
// Stable
use std::range::{RangeInclusive, RangeInclusiveIter};
use std::range::{RangeInclusive, RangeInclusiveIter, RangeToInclusive};
fn range_inclusive(mut r: RangeInclusive<usize>) {
&[1, 2, 3][r]; // Indexing
r.start;
r.last;
r.contains(&5);
@@ -14,6 +16,13 @@ fn range_inclusive(mut r: RangeInclusive<usize>) {
i.remainder();
}
fn range_to_inclusive(mut r: RangeToInclusive<usize>) {
&[1, 2, 3][r]; // Indexing
r.last;
r.contains(&5);
}
// Unstable module
use std::range::legacy; //~ ERROR unstable
+5 -5
View File
@@ -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;
| ^^^^^^^^^^^^^^^^^^^^^