Skip to content

Commit aeba1f4

Browse files
authored
Unrolled build for rust-lang#137304
Rollup merge of rust-lang#137304 - pitaj:rangebounds-is_empty-intersect, r=ibraheemdev add `IntoBounds::intersect` and `RangeBounds::is_empty` - ACP: rust-lang/libs-team#539 - Tracking issue for `is_empty`: rust-lang#137300 - Tracking issue for `IntoBounds`: rust-lang#136903
2 parents e6059f5 + c293af9 commit aeba1f4

File tree

2 files changed

+137
-6
lines changed

2 files changed

+137
-6
lines changed

library/core/src/ops/range.rs

+135-5
Original file line numberDiff line numberDiff line change
@@ -771,13 +771,11 @@ pub trait RangeBounds<T: ?Sized> {
771771
/// # Examples
772772
///
773773
/// ```
774-
/// # fn main() {
775774
/// use std::ops::Bound::*;
776775
/// use std::ops::RangeBounds;
777776
///
778777
/// assert_eq!((..10).start_bound(), Unbounded);
779778
/// assert_eq!((3..10).start_bound(), Included(&3));
780-
/// # }
781779
/// ```
782780
#[stable(feature = "collections_range", since = "1.28.0")]
783781
fn start_bound(&self) -> Bound<&T>;
@@ -789,13 +787,11 @@ pub trait RangeBounds<T: ?Sized> {
789787
/// # Examples
790788
///
791789
/// ```
792-
/// # fn main() {
793790
/// use std::ops::Bound::*;
794791
/// use std::ops::RangeBounds;
795792
///
796793
/// assert_eq!((3..).end_bound(), Unbounded);
797794
/// assert_eq!((3..10).end_bound(), Excluded(&10));
798-
/// # }
799795
/// ```
800796
#[stable(feature = "collections_range", since = "1.28.0")]
801797
fn end_bound(&self) -> Bound<&T>;
@@ -829,6 +825,71 @@ pub trait RangeBounds<T: ?Sized> {
829825
Unbounded => true,
830826
})
831827
}
828+
829+
/// Returns `true` if the range contains no items.
830+
/// One-sided ranges (`RangeFrom`, etc) always return `true`.
831+
///
832+
/// # Examples
833+
///
834+
/// ```
835+
/// #![feature(range_bounds_is_empty)]
836+
/// use std::ops::RangeBounds;
837+
///
838+
/// assert!(!(3..).is_empty());
839+
/// assert!(!(..2).is_empty());
840+
/// assert!(!RangeBounds::is_empty(&(3..5)));
841+
/// assert!( RangeBounds::is_empty(&(3..3)));
842+
/// assert!( RangeBounds::is_empty(&(3..2)));
843+
/// ```
844+
///
845+
/// The range is empty if either side is incomparable:
846+
///
847+
/// ```
848+
/// #![feature(range_bounds_is_empty)]
849+
/// use std::ops::RangeBounds;
850+
///
851+
/// assert!(!RangeBounds::is_empty(&(3.0..5.0)));
852+
/// assert!( RangeBounds::is_empty(&(3.0..f32::NAN)));
853+
/// assert!( RangeBounds::is_empty(&(f32::NAN..5.0)));
854+
/// ```
855+
///
856+
/// But never empty is either side is unbounded:
857+
///
858+
/// ```
859+
/// #![feature(range_bounds_is_empty)]
860+
/// use std::ops::RangeBounds;
861+
///
862+
/// assert!(!(..0).is_empty());
863+
/// assert!(!(i32::MAX..).is_empty());
864+
/// assert!(!RangeBounds::<u8>::is_empty(&(..)));
865+
/// ```
866+
///
867+
/// `(Excluded(a), Excluded(b))` is only empty if `a >= b`:
868+
///
869+
/// ```
870+
/// #![feature(range_bounds_is_empty)]
871+
/// use std::ops::Bound::*;
872+
/// use std::ops::RangeBounds;
873+
///
874+
/// assert!(!(Excluded(1), Excluded(3)).is_empty());
875+
/// assert!(!(Excluded(1), Excluded(2)).is_empty());
876+
/// assert!( (Excluded(1), Excluded(1)).is_empty());
877+
/// assert!( (Excluded(2), Excluded(1)).is_empty());
878+
/// assert!( (Excluded(3), Excluded(1)).is_empty());
879+
/// ```
880+
#[unstable(feature = "range_bounds_is_empty", issue = "137300")]
881+
fn is_empty(&self) -> bool
882+
where
883+
T: PartialOrd,
884+
{
885+
!match (self.start_bound(), self.end_bound()) {
886+
(Unbounded, _) | (_, Unbounded) => true,
887+
(Included(start), Excluded(end))
888+
| (Excluded(start), Included(end))
889+
| (Excluded(start), Excluded(end)) => start < end,
890+
(Included(start), Included(end)) => start <= end,
891+
}
892+
}
832893
}
833894

834895
/// Used to convert a range into start and end bounds, consuming the
@@ -845,14 +906,83 @@ pub trait IntoBounds<T>: RangeBounds<T> {
845906
///
846907
/// ```
847908
/// #![feature(range_into_bounds)]
848-
///
849909
/// use std::ops::Bound::*;
850910
/// use std::ops::IntoBounds;
851911
///
852912
/// assert_eq!((0..5).into_bounds(), (Included(0), Excluded(5)));
853913
/// assert_eq!((..=7).into_bounds(), (Unbounded, Included(7)));
854914
/// ```
855915
fn into_bounds(self) -> (Bound<T>, Bound<T>);
916+
917+
/// Compute the intersection of `self` and `other`.
918+
///
919+
/// # Examples
920+
///
921+
/// ```
922+
/// #![feature(range_into_bounds)]
923+
/// use std::ops::Bound::*;
924+
/// use std::ops::IntoBounds;
925+
///
926+
/// assert_eq!((3..).intersect(..5), (Included(3), Excluded(5)));
927+
/// assert_eq!((-12..387).intersect(0..256), (Included(0), Excluded(256)));
928+
/// assert_eq!((1..5).intersect(..), (Included(1), Excluded(5)));
929+
/// assert_eq!((1..=9).intersect(0..10), (Included(1), Included(9)));
930+
/// assert_eq!((7..=13).intersect(8..13), (Included(8), Excluded(13)));
931+
/// ```
932+
///
933+
/// Combine with `is_empty` to determine if two ranges overlap.
934+
///
935+
/// ```
936+
/// #![feature(range_into_bounds)]
937+
/// #![feature(range_bounds_is_empty)]
938+
/// use std::ops::{RangeBounds, IntoBounds};
939+
///
940+
/// assert!(!(3..).intersect(..5).is_empty());
941+
/// assert!(!(-12..387).intersect(0..256).is_empty());
942+
/// assert!((1..5).intersect(6..).is_empty());
943+
/// ```
944+
fn intersect<R>(self, other: R) -> (Bound<T>, Bound<T>)
945+
where
946+
Self: Sized,
947+
T: Ord,
948+
R: Sized + IntoBounds<T>,
949+
{
950+
let (self_start, self_end) = IntoBounds::into_bounds(self);
951+
let (other_start, other_end) = IntoBounds::into_bounds(other);
952+
953+
let start = match (self_start, other_start) {
954+
(Included(a), Included(b)) => Included(Ord::max(a, b)),
955+
(Excluded(a), Excluded(b)) => Excluded(Ord::max(a, b)),
956+
(Unbounded, Unbounded) => Unbounded,
957+
958+
(x, Unbounded) | (Unbounded, x) => x,
959+
960+
(Included(i), Excluded(e)) | (Excluded(e), Included(i)) => {
961+
if i > e {
962+
Included(i)
963+
} else {
964+
Excluded(e)
965+
}
966+
}
967+
};
968+
let end = match (self_end, other_end) {
969+
(Included(a), Included(b)) => Included(Ord::min(a, b)),
970+
(Excluded(a), Excluded(b)) => Excluded(Ord::min(a, b)),
971+
(Unbounded, Unbounded) => Unbounded,
972+
973+
(x, Unbounded) | (Unbounded, x) => x,
974+
975+
(Included(i), Excluded(e)) | (Excluded(e), Included(i)) => {
976+
if i < e {
977+
Included(i)
978+
} else {
979+
Excluded(e)
980+
}
981+
}
982+
};
983+
984+
(start, end)
985+
}
856986
}
857987

858988
use self::Bound::{Excluded, Included, Unbounded};

tests/ui/impl-trait/method-suggestion-no-duplication.stderr

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ LL | foo(|s| s.is_empty());
88
| ^^^^^^^^ method not found in `Foo`
99
|
1010
= help: items from traits can only be used if the trait is implemented and in scope
11-
= note: the following trait defines an item `is_empty`, perhaps you need to implement it:
11+
= note: the following traits define an item `is_empty`, perhaps you need to implement one of them:
1212
candidate #1: `ExactSizeIterator`
13+
candidate #2: `RangeBounds`
1314

1415
error: aborting due to 1 previous error
1516

0 commit comments

Comments
 (0)