// support that mode.
pub(crate) start: Idx,
pub(crate) end: Idx,
- pub(crate) is_empty: Option<bool>,
- // This field is:
- // - `None` when next() or next_back() was never called
- // - `Some(false)` when `start <= end` assuming no overflow
- // - `Some(true)` otherwise
- // The field cannot be a simple `bool` because the `..=` constructor can
- // accept non-PartialOrd types, also we want the constructor to be const.
-}
-
-trait RangeInclusiveEquality: Sized {
- fn canonicalized_is_empty(range: &RangeInclusive<Self>) -> bool;
-}
-
-impl<T> RangeInclusiveEquality for T {
- #[inline]
- default fn canonicalized_is_empty(range: &RangeInclusive<Self>) -> bool {
- range.is_empty.unwrap_or_default()
- }
-}
-impl<T: PartialOrd> RangeInclusiveEquality for T {
- #[inline]
- fn canonicalized_is_empty(range: &RangeInclusive<Self>) -> bool {
- range.is_empty()
- }
+ // This field is:
+ // - `false` upon construction
+ // - `false` when iteration has yielded an element and the iterator is not exhausted
+ // - `true` when iteration has been used to exhaust the iterator
+ //
+ // This is required to support PartialEq and Hash without a PartialOrd bound or specialization.
+ pub(crate) exhausted: bool,
}
#[stable(feature = "inclusive_range", since = "1.26.0")]
impl<Idx: PartialEq> PartialEq for RangeInclusive<Idx> {
#[inline]
fn eq(&self, other: &Self) -> bool {
- self.start == other.start
- && self.end == other.end
- && RangeInclusiveEquality::canonicalized_is_empty(self)
- == RangeInclusiveEquality::canonicalized_is_empty(other)
+ self.start == other.start && self.end == other.end && self.exhausted == other.exhausted
}
}
fn hash<H: Hasher>(&self, state: &mut H) {
self.start.hash(state);
self.end.hash(state);
- RangeInclusiveEquality::canonicalized_is_empty(self).hash(state);
+ self.exhausted.hash(state);
}
}
#[rustc_promotable]
#[rustc_const_stable(feature = "const_range_new", since = "1.32.0")]
pub const fn new(start: Idx, end: Idx) -> Self {
- Self { start, end, is_empty: None }
+ Self { start, end, exhausted: false }
}
/// Returns the lower bound of the range (inclusive).
self.start.fmt(fmt)?;
write!(fmt, "..=")?;
self.end.fmt(fmt)?;
+ if self.exhausted {
+ write!(fmt, " (exhausted)")?;
+ }
Ok(())
}
}
#[unstable(feature = "range_is_empty", reason = "recently added", issue = "48111")]
#[inline]
pub fn is_empty(&self) -> bool {
- self.is_empty.unwrap_or_else(|| !(self.start <= self.end))
- }
-
- // If this range's `is_empty` is field is unknown (`None`), update it to be a concrete value.
- #[inline]
- pub(crate) fn compute_is_empty(&mut self) {
- if self.is_empty.is_none() {
- self.is_empty = Some(!(self.start <= self.end));
- }
+ self.exhausted || !(self.start <= self.end)
}
}