Skip to content

Commit 00c87a6

Browse files
Rollup merge of rust-lang#42134 - scottmcm:rangeinclusive-struct, r=aturon
Make RangeInclusive just a two-field struct Not being an enum improves ergonomics and consistency, especially since NonEmpty variant wasn't prevented from being empty. It can still be iterable without an extra "done" bit by making the range have !(start <= end), which is even possible without changing the Step trait. Implements merged rust-lang/rfcs#1980; tracking issue rust-lang#28237. This is definitely a breaking change to anything consuming `RangeInclusive` directly (not as an Iterator) or constructing it without using the sugar. Is there some change that would make sense before this so compilation failures could be compatibly fixed ahead of time? r? @aturon (as FCP proposer on the RFC)
2 parents 989c8e8 + 7eaca60 commit 00c87a6

File tree

9 files changed

+149
-255
lines changed

9 files changed

+149
-255
lines changed

src/libcollections/range.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -106,16 +106,10 @@ impl<T> RangeArgument<T> for Range<T> {
106106
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
107107
impl<T> RangeArgument<T> for RangeInclusive<T> {
108108
fn start(&self) -> Bound<&T> {
109-
match *self {
110-
RangeInclusive::Empty{ ref at } => Included(at),
111-
RangeInclusive::NonEmpty { ref start, .. } => Included(start),
112-
}
109+
Included(&self.start)
113110
}
114111
fn end(&self) -> Bound<&T> {
115-
match *self {
116-
RangeInclusive::Empty{ ref at } => Excluded(at),
117-
RangeInclusive::NonEmpty { ref end, .. } => Included(end),
118-
}
112+
Included(&self.end)
119113
}
120114
}
121115

src/libcore/iter/range.rs

+55-119
Original file line numberDiff line numberDiff line change
@@ -403,61 +403,35 @@ impl<A: Step + Clone> Iterator for StepBy<A, ops::RangeInclusive<A>> {
403403

404404
#[inline]
405405
fn next(&mut self) -> Option<A> {
406-
use ops::RangeInclusive::*;
407-
408-
// this function has a sort of odd structure due to borrowck issues
409-
// we may need to replace self.range, so borrows of start and end need to end early
410-
411-
let (finishing, n) = match self.range {
412-
Empty { .. } => return None, // empty iterators yield no values
413-
414-
NonEmpty { ref mut start, ref mut end } => {
415-
let rev = self.step_by.is_negative();
416-
417-
// march start towards (maybe past!) end and yield the old value
418-
if (rev && start >= end) ||
419-
(!rev && start <= end)
420-
{
421-
match start.step(&self.step_by) {
422-
Some(mut n) => {
423-
mem::swap(start, &mut n);
424-
(None, Some(n)) // yield old value, remain non-empty
425-
},
426-
None => {
427-
let mut n = end.clone();
428-
mem::swap(start, &mut n);
429-
(None, Some(n)) // yield old value, remain non-empty
430-
}
431-
}
432-
} else {
433-
// found range in inconsistent state (start at or past end), so become empty
434-
(Some(end.replace_zero()), None)
435-
}
436-
}
437-
};
406+
let rev = self.step_by.is_negative();
438407

439-
// turn into an empty iterator if we've reached the end
440-
if let Some(end) = finishing {
441-
self.range = Empty { at: end };
408+
if (rev && self.range.start >= self.range.end) ||
409+
(!rev && self.range.start <= self.range.end)
410+
{
411+
match self.range.start.step(&self.step_by) {
412+
Some(n) => {
413+
Some(mem::replace(&mut self.range.start, n))
414+
},
415+
None => {
416+
let last = self.range.start.replace_one();
417+
self.range.end.replace_zero();
418+
self.step_by.replace_one();
419+
Some(last)
420+
},
421+
}
422+
}
423+
else {
424+
None
442425
}
443-
444-
n
445426
}
446427

447428
#[inline]
448429
fn size_hint(&self) -> (usize, Option<usize>) {
449-
use ops::RangeInclusive::*;
450-
451-
match self.range {
452-
Empty { .. } => (0, Some(0)),
453-
454-
NonEmpty { ref start, ref end } =>
455-
match Step::steps_between(start,
456-
end,
457-
&self.step_by) {
458-
Some(hint) => (hint.saturating_add(1), hint.checked_add(1)),
459-
None => (0, None)
460-
}
430+
match Step::steps_between(&self.range.start,
431+
&self.range.end,
432+
&self.step_by) {
433+
Some(hint) => (hint.saturating_add(1), hint.checked_add(1)),
434+
None => (0, None)
461435
}
462436
}
463437
}
@@ -583,56 +557,31 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> where
583557

584558
#[inline]
585559
fn next(&mut self) -> Option<A> {
586-
use ops::RangeInclusive::*;
587-
588-
// this function has a sort of odd structure due to borrowck issues
589-
// we may need to replace self, so borrows of self.start and self.end need to end early
590-
591-
let (finishing, n) = match *self {
592-
Empty { .. } => (None, None), // empty iterators yield no values
593-
594-
NonEmpty { ref mut start, ref mut end } => {
595-
if start == end {
596-
(Some(end.replace_one()), Some(start.replace_one()))
597-
} else if start < end {
598-
let mut n = start.add_one();
599-
mem::swap(&mut n, start);
600-
601-
// if the iterator is done iterating, it will change from
602-
// NonEmpty to Empty to avoid unnecessary drops or clones,
603-
// we'll reuse either start or end (they are equal now, so
604-
// it doesn't matter which) to pull out end, we need to swap
605-
// something back in
606-
607-
(if n == *end { Some(end.replace_one()) } else { None },
608-
// ^ are we done yet?
609-
Some(n)) // < the value to output
610-
} else {
611-
(Some(start.replace_one()), None)
612-
}
613-
}
614-
};
615-
616-
// turn into an empty iterator if this is the last value
617-
if let Some(end) = finishing {
618-
*self = Empty { at: end };
560+
use cmp::Ordering::*;
561+
562+
match self.start.partial_cmp(&self.end) {
563+
Some(Less) => {
564+
let n = self.start.add_one();
565+
Some(mem::replace(&mut self.start, n))
566+
},
567+
Some(Equal) => {
568+
let last = self.start.replace_one();
569+
self.end.replace_zero();
570+
Some(last)
571+
},
572+
_ => None,
619573
}
620-
621-
n
622574
}
623575

624576
#[inline]
625577
fn size_hint(&self) -> (usize, Option<usize>) {
626-
use ops::RangeInclusive::*;
627-
628-
match *self {
629-
Empty { .. } => (0, Some(0)),
578+
if !(self.start <= self.end) {
579+
return (0, Some(0));
580+
}
630581

631-
NonEmpty { ref start, ref end } =>
632-
match Step::steps_between_by_one(start, end) {
633-
Some(hint) => (hint.saturating_add(1), hint.checked_add(1)),
634-
None => (0, None),
635-
}
582+
match Step::steps_between_by_one(&self.start, &self.end) {
583+
Some(hint) => (hint.saturating_add(1), hint.checked_add(1)),
584+
None => (0, None),
636585
}
637586
}
638587
}
@@ -644,33 +593,20 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> where
644593
{
645594
#[inline]
646595
fn next_back(&mut self) -> Option<A> {
647-
use ops::RangeInclusive::*;
648-
649-
// see Iterator::next for comments
650-
651-
let (finishing, n) = match *self {
652-
Empty { .. } => return None,
653-
654-
NonEmpty { ref mut start, ref mut end } => {
655-
if start == end {
656-
(Some(start.replace_one()), Some(end.replace_one()))
657-
} else if start < end {
658-
let mut n = end.sub_one();
659-
mem::swap(&mut n, end);
660-
661-
(if n == *start { Some(start.replace_one()) } else { None },
662-
Some(n))
663-
} else {
664-
(Some(end.replace_one()), None)
665-
}
666-
}
667-
};
668-
669-
if let Some(start) = finishing {
670-
*self = Empty { at: start };
596+
use cmp::Ordering::*;
597+
598+
match self.start.partial_cmp(&self.end) {
599+
Some(Less) => {
600+
let n = self.end.sub_one();
601+
Some(mem::replace(&mut self.end, n))
602+
},
603+
Some(Equal) => {
604+
let last = self.end.replace_zero();
605+
self.start.replace_one();
606+
Some(last)
607+
},
608+
_ => None,
671609
}
672-
673-
n
674610
}
675611
}
676612

src/libcore/ops.rs

+8-32
Original file line numberDiff line numberDiff line change
@@ -2271,7 +2271,7 @@ impl<Idx: PartialOrd<Idx>> RangeTo<Idx> {
22712271
/// ```
22722272
/// #![feature(inclusive_range,inclusive_range_syntax)]
22732273
/// fn main() {
2274-
/// assert_eq!((3...5), std::ops::RangeInclusive::NonEmpty{ start: 3, end: 5 });
2274+
/// assert_eq!((3...5), std::ops::RangeInclusive{ start: 3, end: 5 });
22752275
/// assert_eq!(3+4+5, (3...5).sum());
22762276
///
22772277
/// let arr = [0, 1, 2, 3];
@@ -2281,45 +2281,23 @@ impl<Idx: PartialOrd<Idx>> RangeTo<Idx> {
22812281
/// ```
22822282
#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186
22832283
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
2284-
pub enum RangeInclusive<Idx> {
2285-
/// Empty range (iteration has finished)
2284+
pub struct RangeInclusive<Idx> {
2285+
/// The lower bound of the range (inclusive).
22862286
#[unstable(feature = "inclusive_range",
22872287
reason = "recently added, follows RFC",
22882288
issue = "28237")]
2289-
Empty {
2290-
/// The point at which iteration finished
2291-
#[unstable(feature = "inclusive_range",
2292-
reason = "recently added, follows RFC",
2293-
issue = "28237")]
2294-
at: Idx
2295-
},
2296-
/// Non-empty range (iteration will yield value(s))
2289+
pub start: Idx,
2290+
/// The upper bound of the range (inclusive).
22972291
#[unstable(feature = "inclusive_range",
22982292
reason = "recently added, follows RFC",
22992293
issue = "28237")]
2300-
NonEmpty {
2301-
/// The lower bound of the range (inclusive).
2302-
#[unstable(feature = "inclusive_range",
2303-
reason = "recently added, follows RFC",
2304-
issue = "28237")]
2305-
start: Idx,
2306-
/// The upper bound of the range (inclusive).
2307-
#[unstable(feature = "inclusive_range",
2308-
reason = "recently added, follows RFC",
2309-
issue = "28237")]
2310-
end: Idx,
2311-
},
2294+
pub end: Idx,
23122295
}
23132296

23142297
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
23152298
impl<Idx: fmt::Debug> fmt::Debug for RangeInclusive<Idx> {
23162299
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2317-
use self::RangeInclusive::*;
2318-
2319-
match *self {
2320-
Empty { ref at } => write!(fmt, "[empty range @ {:?}]", at),
2321-
NonEmpty { ref start, ref end } => write!(fmt, "{:?}...{:?}", start, end),
2322-
}
2300+
write!(fmt, "{:?}...{:?}", self.start, self.end)
23232301
}
23242302
}
23252303

@@ -2341,9 +2319,7 @@ impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> {
23412319
/// }
23422320
/// ```
23432321
pub fn contains(&self, item: Idx) -> bool {
2344-
if let &RangeInclusive::NonEmpty{ref start, ref end} = self {
2345-
(*start <= item) && (item <= *end)
2346-
} else { false }
2322+
self.start <= item && item <= self.end
23472323
}
23482324
}
23492325

0 commit comments

Comments
 (0)