Skip to content

Commit

Permalink
add IntoBounds trait
Browse files Browse the repository at this point in the history
for `range_into_bounds`  feature, #136903
  • Loading branch information
pitaj committed Feb 12, 2025
1 parent 34a5ea9 commit 2047de7
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 1 deletion.
2 changes: 2 additions & 0 deletions library/core/src/ops/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down
80 changes: 80 additions & 0 deletions library/core/src/ops/range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,86 @@ impl<T> RangeBounds<T> for RangeToInclusive<&T> {
}
}

/// 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<T: Sized>: RangeBounds<T> {
/// Convert this range into the start and end bounds.
/// Returns `(start_bound, end_bound)`.
///
/// # Examples
///
/// ```
/// 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<T>, Bound<T>);
}

#[unstable(feature = "range_into_bounds", issue = "136903")]
impl<T> IntoBounds<T> for Range<T> {
fn into_bounds(self) -> (Bound<T>, Bound<T>) {
(Included(self.start), Excluded(self.end))
}
}

#[unstable(feature = "range_into_bounds", issue = "136903")]
impl<T> IntoBounds<T> for RangeFrom<T> {
fn into_bounds(self) -> (Bound<T>, Bound<T>) {
(Included(self.start), Unbounded)
}
}

#[unstable(feature = "range_into_bounds", issue = "136903")]
impl<T> IntoBounds<T> for RangeFull {
fn into_bounds(self) -> (Bound<T>, Bound<T>) {
(Unbounded, Unbounded)
}
}

#[unstable(feature = "range_into_bounds", issue = "136903")]
impl<T> IntoBounds<T> for RangeInclusive<T> {
fn into_bounds(self) -> (Bound<T>, Bound<T>) {
(
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)
},
)
}
}

#[unstable(feature = "range_into_bounds", issue = "136903")]
impl<T> IntoBounds<T> for RangeTo<T> {
fn into_bounds(self) -> (Bound<T>, Bound<T>) {
(Unbounded, Excluded(self.end))
}
}

#[unstable(feature = "range_into_bounds", issue = "136903")]
impl<T> IntoBounds<T> for RangeToInclusive<T> {
fn into_bounds(self) -> (Bound<T>, Bound<T>) {
(Unbounded, Included(self.end))
}
}

#[unstable(feature = "range_into_bounds", issue = "136903")]
impl<T> IntoBounds<T> for (Bound<T>, Bound<T>) {
fn into_bounds(self) -> (Bound<T>, Bound<T>) {
self
}
}

/// An internal helper for `split_off` functions indicating
/// which end a `OneSidedRange` is bounded on.
#[unstable(feature = "one_sided_range", issue = "69780")]
Expand Down
28 changes: 27 additions & 1 deletion library/core/src/range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down Expand Up @@ -175,6 +177,14 @@ impl<T> RangeBounds<T> for Range<&T> {
}
}

// #[unstable(feature = "range_into_bounds", issue = "136903")]
#[unstable(feature = "new_range_api", issue = "125687")]
impl<T> IntoBounds<T> for Range<T> {
fn into_bounds(self) -> (Bound<T>, Bound<T>) {
(Included(self.start), Excluded(self.end))
}
}

#[unstable(feature = "new_range_api", issue = "125687")]
impl<T> From<Range<T>> for legacy::Range<T> {
#[inline]
Expand Down Expand Up @@ -343,6 +353,14 @@ impl<T> RangeBounds<T> for RangeInclusive<&T> {
}
}

// #[unstable(feature = "range_into_bounds", issue = "136903")]
#[unstable(feature = "new_range_api", issue = "125687")]
impl<T> IntoBounds<T> for RangeInclusive<T> {
fn into_bounds(self) -> (Bound<T>, Bound<T>) {
(Included(self.start), Included(self.end))
}
}

#[unstable(feature = "new_range_api", issue = "125687")]
impl<T> From<RangeInclusive<T>> for legacy::RangeInclusive<T> {
#[inline]
Expand Down Expand Up @@ -479,6 +497,14 @@ impl<T> RangeBounds<T> for RangeFrom<&T> {
}
}

// #[unstable(feature = "range_into_bounds", issue = "136903")]
#[unstable(feature = "new_range_api", issue = "125687")]
impl<T> IntoBounds<T> for RangeFrom<T> {
fn into_bounds(self) -> (Bound<T>, Bound<T>) {
(Included(self.start), Unbounded)
}
}

#[unstable(feature = "new_range_api", issue = "125687")]
impl<T> From<RangeFrom<T>> for legacy::RangeFrom<T> {
#[inline]
Expand Down

0 comments on commit 2047de7

Please sign in to comment.