From 9c03369c17c6eed8b6471cb7e176f7da99f6cdfb Mon Sep 17 00:00:00 2001
From: Peter Jaszkowiak
Date: Tue, 11 Feb 2025 21:58:54 -0700
Subject: [PATCH] add `IntoBounds` trait
for `range_into_bounds` feature, #136903
---
library/core/src/ops/mod.rs | 2 +
library/core/src/ops/range.rs | 82 +++++++++++++++++++++++++++++++++++
library/core/src/range.rs | 28 +++++++++++-
3 files changed, 111 insertions(+), 1 deletion(-)
diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs
index 7b2ced2cc4bdc..627a875d9f724 100644
--- a/library/core/src/ops/mod.rs
+++ b/library/core/src/ops/mod.rs
@@ -182,6 +182,8 @@ pub use self::function::{Fn, FnMut, FnOnce};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::index::{Index, IndexMut};
pub(crate) use self::index_range::IndexRange;
+#[unstable(feature = "range_into_bounds", issue = "136903")]
+pub use self::range::IntoBounds;
#[stable(feature = "inclusive_range", since = "1.26.0")]
pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive};
#[unstable(feature = "one_sided_range", issue = "69780")]
diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs
index 42e07a0e51da4..5580faefacc0d 100644
--- a/library/core/src/ops/range.rs
+++ b/library/core/src/ops/range.rs
@@ -831,6 +831,30 @@ pub trait RangeBounds {
}
}
+/// Used to convert a range into start and end bounds, consuming the
+/// range by value.
+///
+/// `IntoBounds` is implemented by Rust’s built-in range types, produced
+/// by range syntax like `..`, `a..`, `..b`, `..=c`, `d..e`, or `f..=g`.
+#[unstable(feature = "range_into_bounds", issue = "136903")]
+pub trait IntoBounds: RangeBounds {
+ /// Convert this range into the start and end bounds.
+ /// Returns `(start_bound, end_bound)`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(range_into_bounds)]
+ ///
+ /// use std::ops::Bound::*;
+ /// use std::ops::IntoBounds;
+ ///
+ /// assert_eq!((0..5).into_bounds(), (Included(0), Excluded(5)));
+ /// assert_eq!((..=7).into_bounds(), (Unbounded, Included(7)));
+ /// ```
+ fn into_bounds(self) -> (Bound, Bound);
+}
+
use self::Bound::{Excluded, Included, Unbounded};
#[stable(feature = "collections_range", since = "1.28.0")]
@@ -843,6 +867,13 @@ impl RangeBounds for RangeFull {
}
}
+#[unstable(feature = "range_into_bounds", issue = "136903")]
+impl IntoBounds for RangeFull {
+ fn into_bounds(self) -> (Bound, Bound) {
+ (Unbounded, Unbounded)
+ }
+}
+
#[stable(feature = "collections_range", since = "1.28.0")]
impl RangeBounds for RangeFrom {
fn start_bound(&self) -> Bound<&T> {
@@ -853,6 +884,13 @@ impl RangeBounds for RangeFrom {
}
}
+#[unstable(feature = "range_into_bounds", issue = "136903")]
+impl IntoBounds for RangeFrom {
+ fn into_bounds(self) -> (Bound, Bound) {
+ (Included(self.start), Unbounded)
+ }
+}
+
#[stable(feature = "collections_range", since = "1.28.0")]
impl RangeBounds for RangeTo {
fn start_bound(&self) -> Bound<&T> {
@@ -863,6 +901,13 @@ impl RangeBounds for RangeTo {
}
}
+#[unstable(feature = "range_into_bounds", issue = "136903")]
+impl IntoBounds for RangeTo {
+ fn into_bounds(self) -> (Bound, Bound) {
+ (Unbounded, Excluded(self.end))
+ }
+}
+
#[stable(feature = "collections_range", since = "1.28.0")]
impl RangeBounds for Range {
fn start_bound(&self) -> Bound<&T> {
@@ -873,6 +918,13 @@ impl RangeBounds for Range {
}
}
+#[unstable(feature = "range_into_bounds", issue = "136903")]
+impl IntoBounds for Range {
+ fn into_bounds(self) -> (Bound, Bound) {
+ (Included(self.start), Excluded(self.end))
+ }
+}
+
#[stable(feature = "collections_range", since = "1.28.0")]
impl RangeBounds for RangeInclusive {
fn start_bound(&self) -> Bound<&T> {
@@ -889,6 +941,22 @@ impl RangeBounds for RangeInclusive {
}
}
+#[unstable(feature = "range_into_bounds", issue = "136903")]
+impl IntoBounds for RangeInclusive {
+ fn into_bounds(self) -> (Bound, Bound) {
+ (
+ Included(self.start),
+ if self.exhausted {
+ // When the iterator is exhausted, we usually have start == end,
+ // but we want the range to appear empty, containing nothing.
+ Excluded(self.end)
+ } else {
+ Included(self.end)
+ },
+ )
+ }
+}
+
#[stable(feature = "collections_range", since = "1.28.0")]
impl RangeBounds for RangeToInclusive {
fn start_bound(&self) -> Bound<&T> {
@@ -899,6 +967,13 @@ impl RangeBounds for RangeToInclusive {
}
}
+#[unstable(feature = "range_into_bounds", issue = "136903")]
+impl IntoBounds for RangeToInclusive {
+ fn into_bounds(self) -> (Bound, Bound) {
+ (Unbounded, Included(self.end))
+ }
+}
+
#[stable(feature = "collections_range", since = "1.28.0")]
impl RangeBounds for (Bound, Bound) {
fn start_bound(&self) -> Bound<&T> {
@@ -918,6 +993,13 @@ impl RangeBounds for (Bound, Bound) {
}
}
+#[unstable(feature = "range_into_bounds", issue = "136903")]
+impl IntoBounds for (Bound, Bound) {
+ fn into_bounds(self) -> (Bound, Bound) {
+ self
+ }
+}
+
#[stable(feature = "collections_range", since = "1.28.0")]
impl<'a, T: ?Sized + 'a> RangeBounds for (Bound<&'a T>, Bound<&'a T>) {
fn start_bound(&self) -> Bound<&T> {
diff --git a/library/core/src/range.rs b/library/core/src/range.rs
index 6a62928873fe8..e94499065ac9a 100644
--- a/library/core/src/range.rs
+++ b/library/core/src/range.rs
@@ -31,7 +31,9 @@ pub use iter::{IterRange, IterRangeFrom, IterRangeInclusive};
#[doc(inline)]
pub use crate::iter::Step;
#[doc(inline)]
-pub use crate::ops::{Bound, OneSidedRange, RangeBounds, RangeFull, RangeTo, RangeToInclusive};
+pub use crate::ops::{
+ Bound, IntoBounds, OneSidedRange, RangeBounds, RangeFull, RangeTo, RangeToInclusive,
+};
/// A (half-open) range bounded inclusively below and exclusively above
/// (`start..end` in a future edition).
@@ -175,6 +177,14 @@ impl RangeBounds for Range<&T> {
}
}
+// #[unstable(feature = "range_into_bounds", issue = "136903")]
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl IntoBounds for Range {
+ fn into_bounds(self) -> (Bound, Bound) {
+ (Included(self.start), Excluded(self.end))
+ }
+}
+
#[unstable(feature = "new_range_api", issue = "125687")]
impl From> for legacy::Range {
#[inline]
@@ -343,6 +353,14 @@ impl RangeBounds for RangeInclusive<&T> {
}
}
+// #[unstable(feature = "range_into_bounds", issue = "136903")]
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl IntoBounds for RangeInclusive {
+ fn into_bounds(self) -> (Bound, Bound) {
+ (Included(self.start), Included(self.end))
+ }
+}
+
#[unstable(feature = "new_range_api", issue = "125687")]
impl From> for legacy::RangeInclusive {
#[inline]
@@ -479,6 +497,14 @@ impl RangeBounds for RangeFrom<&T> {
}
}
+// #[unstable(feature = "range_into_bounds", issue = "136903")]
+#[unstable(feature = "new_range_api", issue = "125687")]
+impl IntoBounds for RangeFrom {
+ fn into_bounds(self) -> (Bound, Bound) {
+ (Included(self.start), Unbounded)
+ }
+}
+
#[unstable(feature = "new_range_api", issue = "125687")]
impl From> for legacy::RangeFrom {
#[inline]