core/
range.rs

1//! # Experimental replacement range types
2//!
3//! The types within this module are meant to replace the existing
4//! `Range`, `RangeInclusive`, and `RangeFrom` types in a future edition.
5//!
6//! ```
7//! #![feature(new_range_api)]
8//! use core::range::{Range, RangeFrom, RangeInclusive};
9//!
10//! let arr = [0, 1, 2, 3, 4];
11//! assert_eq!(arr[                      ..   ], [0, 1, 2, 3, 4]);
12//! assert_eq!(arr[                      .. 3 ], [0, 1, 2      ]);
13//! assert_eq!(arr[                      ..=3 ], [0, 1, 2, 3   ]);
14//! assert_eq!(arr[     RangeFrom::from(1..  )], [   1, 2, 3, 4]);
15//! assert_eq!(arr[         Range::from(1..3 )], [   1, 2      ]);
16//! assert_eq!(arr[RangeInclusive::from(1..=3)], [   1, 2, 3   ]);
17//! ```
18
19use crate::fmt;
20use crate::hash::Hash;
21
22mod iter;
23
24#[unstable(feature = "new_range_api", issue = "125687")]
25pub mod legacy;
26
27use Bound::{Excluded, Included, Unbounded};
28#[doc(inline)]
29pub use iter::{IterRange, IterRangeFrom, IterRangeInclusive};
30
31#[doc(inline)]
32pub use crate::iter::Step;
33#[doc(inline)]
34pub use crate::ops::{
35    Bound, IntoBounds, OneSidedRange, RangeBounds, RangeFull, RangeTo, RangeToInclusive,
36};
37
38/// A (half-open) range bounded inclusively below and exclusively above
39/// (`start..end` in a future edition).
40///
41/// The range `start..end` contains all values with `start <= x < end`.
42/// It is empty if `start >= end`.
43///
44/// # Examples
45///
46/// ```
47/// #![feature(new_range_api)]
48/// use core::range::Range;
49///
50/// assert_eq!(Range::from(3..5), Range { start: 3, end: 5 });
51/// assert_eq!(3 + 4 + 5, Range::from(3..6).into_iter().sum());
52/// ```
53#[lang = "RangeCopy"]
54#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
55#[unstable(feature = "new_range_api", issue = "125687")]
56pub struct Range<Idx> {
57    /// The lower bound of the range (inclusive).
58    #[unstable(feature = "new_range_api", issue = "125687")]
59    pub start: Idx,
60    /// The upper bound of the range (exclusive).
61    #[unstable(feature = "new_range_api", issue = "125687")]
62    pub end: Idx,
63}
64
65#[unstable(feature = "new_range_api", issue = "125687")]
66impl<Idx: fmt::Debug> fmt::Debug for Range<Idx> {
67    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
68        self.start.fmt(fmt)?;
69        write!(fmt, "..")?;
70        self.end.fmt(fmt)?;
71        Ok(())
72    }
73}
74
75impl<Idx: Step> Range<Idx> {
76    /// Creates an iterator over the elements within this range.
77    ///
78    /// Shorthand for `.clone().into_iter()`
79    ///
80    /// # Examples
81    ///
82    /// ```
83    /// #![feature(new_range_api)]
84    /// use core::range::Range;
85    ///
86    /// let mut i = Range::from(3..9).iter().map(|n| n*n);
87    /// assert_eq!(i.next(), Some(9));
88    /// assert_eq!(i.next(), Some(16));
89    /// assert_eq!(i.next(), Some(25));
90    /// ```
91    #[unstable(feature = "new_range_api", issue = "125687")]
92    #[inline]
93    pub fn iter(&self) -> IterRange<Idx> {
94        self.clone().into_iter()
95    }
96}
97
98impl<Idx: PartialOrd<Idx>> Range<Idx> {
99    /// Returns `true` if `item` is contained in the range.
100    ///
101    /// # Examples
102    ///
103    /// ```
104    /// #![feature(new_range_api)]
105    /// use core::range::Range;
106    ///
107    /// assert!(!Range::from(3..5).contains(&2));
108    /// assert!( Range::from(3..5).contains(&3));
109    /// assert!( Range::from(3..5).contains(&4));
110    /// assert!(!Range::from(3..5).contains(&5));
111    ///
112    /// assert!(!Range::from(3..3).contains(&3));
113    /// assert!(!Range::from(3..2).contains(&3));
114    ///
115    /// assert!( Range::from(0.0..1.0).contains(&0.5));
116    /// assert!(!Range::from(0.0..1.0).contains(&f32::NAN));
117    /// assert!(!Range::from(0.0..f32::NAN).contains(&0.5));
118    /// assert!(!Range::from(f32::NAN..1.0).contains(&0.5));
119    /// ```
120    #[inline]
121    #[unstable(feature = "new_range_api", issue = "125687")]
122    pub fn contains<U>(&self, item: &U) -> bool
123    where
124        Idx: PartialOrd<U>,
125        U: ?Sized + PartialOrd<Idx>,
126    {
127        <Self as RangeBounds<Idx>>::contains(self, item)
128    }
129
130    /// Returns `true` if the range contains no items.
131    ///
132    /// # Examples
133    ///
134    /// ```
135    /// #![feature(new_range_api)]
136    /// use core::range::Range;
137    ///
138    /// assert!(!Range::from(3..5).is_empty());
139    /// assert!( Range::from(3..3).is_empty());
140    /// assert!( Range::from(3..2).is_empty());
141    /// ```
142    ///
143    /// The range is empty if either side is incomparable:
144    ///
145    /// ```
146    /// #![feature(new_range_api)]
147    /// use core::range::Range;
148    ///
149    /// assert!(!Range::from(3.0..5.0).is_empty());
150    /// assert!( Range::from(3.0..f32::NAN).is_empty());
151    /// assert!( Range::from(f32::NAN..5.0).is_empty());
152    /// ```
153    #[inline]
154    #[unstable(feature = "new_range_api", issue = "125687")]
155    pub fn is_empty(&self) -> bool {
156        !(self.start < self.end)
157    }
158}
159
160#[unstable(feature = "new_range_api", issue = "125687")]
161impl<T> RangeBounds<T> for Range<T> {
162    fn start_bound(&self) -> Bound<&T> {
163        Included(&self.start)
164    }
165    fn end_bound(&self) -> Bound<&T> {
166        Excluded(&self.end)
167    }
168}
169
170// This impl intentionally does not have `T: ?Sized`;
171// see https://github.com/rust-lang/rust/pull/61584 for discussion of why.
172//
173/// If you need to use this implementation where `T` is unsized,
174/// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound],
175/// i.e. replace `start..end` with `(Bound::Included(start), Bound::Excluded(end))`.
176#[unstable(feature = "new_range_api", issue = "125687")]
177impl<T> RangeBounds<T> for Range<&T> {
178    fn start_bound(&self) -> Bound<&T> {
179        Included(self.start)
180    }
181    fn end_bound(&self) -> Bound<&T> {
182        Excluded(self.end)
183    }
184}
185
186// #[unstable(feature = "range_into_bounds", issue = "136903")]
187#[unstable(feature = "new_range_api", issue = "125687")]
188impl<T> IntoBounds<T> for Range<T> {
189    fn into_bounds(self) -> (Bound<T>, Bound<T>) {
190        (Included(self.start), Excluded(self.end))
191    }
192}
193
194#[unstable(feature = "new_range_api", issue = "125687")]
195#[rustc_const_unstable(feature = "const_index", issue = "143775")]
196impl<T> const From<Range<T>> for legacy::Range<T> {
197    #[inline]
198    fn from(value: Range<T>) -> Self {
199        Self { start: value.start, end: value.end }
200    }
201}
202
203#[unstable(feature = "new_range_api", issue = "125687")]
204#[rustc_const_unstable(feature = "const_index", issue = "143775")]
205impl<T> const From<legacy::Range<T>> for Range<T> {
206    #[inline]
207    fn from(value: legacy::Range<T>) -> Self {
208        Self { start: value.start, end: value.end }
209    }
210}
211
212/// A range bounded inclusively below and above (`start..=end`).
213///
214/// The `RangeInclusive` `start..=end` contains all values with `x >= start`
215/// and `x <= end`. It is empty unless `start <= end`.
216///
217/// # Examples
218///
219/// The `start..=end` syntax is a `RangeInclusive`:
220///
221/// ```
222/// #![feature(new_range_api)]
223/// use core::range::RangeInclusive;
224///
225/// assert_eq!(RangeInclusive::from(3..=5), RangeInclusive { start: 3, end: 5 });
226/// assert_eq!(3 + 4 + 5, RangeInclusive::from(3..=5).into_iter().sum());
227/// ```
228#[lang = "RangeInclusiveCopy"]
229#[derive(Clone, Copy, PartialEq, Eq, Hash)]
230#[unstable(feature = "new_range_api", issue = "125687")]
231pub struct RangeInclusive<Idx> {
232    /// The lower bound of the range (inclusive).
233    #[unstable(feature = "new_range_api", issue = "125687")]
234    pub start: Idx,
235    /// The upper bound of the range (inclusive).
236    #[unstable(feature = "new_range_api", issue = "125687")]
237    pub end: Idx,
238}
239
240#[unstable(feature = "new_range_api", issue = "125687")]
241impl<Idx: fmt::Debug> fmt::Debug for RangeInclusive<Idx> {
242    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
243        self.start.fmt(fmt)?;
244        write!(fmt, "..=")?;
245        self.end.fmt(fmt)?;
246        Ok(())
247    }
248}
249
250impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> {
251    /// Returns `true` if `item` is contained in the range.
252    ///
253    /// # Examples
254    ///
255    /// ```
256    /// #![feature(new_range_api)]
257    /// use core::range::RangeInclusive;
258    ///
259    /// assert!(!RangeInclusive::from(3..=5).contains(&2));
260    /// assert!( RangeInclusive::from(3..=5).contains(&3));
261    /// assert!( RangeInclusive::from(3..=5).contains(&4));
262    /// assert!( RangeInclusive::from(3..=5).contains(&5));
263    /// assert!(!RangeInclusive::from(3..=5).contains(&6));
264    ///
265    /// assert!( RangeInclusive::from(3..=3).contains(&3));
266    /// assert!(!RangeInclusive::from(3..=2).contains(&3));
267    ///
268    /// assert!( RangeInclusive::from(0.0..=1.0).contains(&1.0));
269    /// assert!(!RangeInclusive::from(0.0..=1.0).contains(&f32::NAN));
270    /// assert!(!RangeInclusive::from(0.0..=f32::NAN).contains(&0.0));
271    /// assert!(!RangeInclusive::from(f32::NAN..=1.0).contains(&1.0));
272    /// ```
273    #[inline]
274    #[unstable(feature = "new_range_api", issue = "125687")]
275    pub fn contains<U>(&self, item: &U) -> bool
276    where
277        Idx: PartialOrd<U>,
278        U: ?Sized + PartialOrd<Idx>,
279    {
280        <Self as RangeBounds<Idx>>::contains(self, item)
281    }
282
283    /// Returns `true` if the range contains no items.
284    ///
285    /// # Examples
286    ///
287    /// ```
288    /// #![feature(new_range_api)]
289    /// use core::range::RangeInclusive;
290    ///
291    /// assert!(!RangeInclusive::from(3..=5).is_empty());
292    /// assert!(!RangeInclusive::from(3..=3).is_empty());
293    /// assert!( RangeInclusive::from(3..=2).is_empty());
294    /// ```
295    ///
296    /// The range is empty if either side is incomparable:
297    ///
298    /// ```
299    /// #![feature(new_range_api)]
300    /// use core::range::RangeInclusive;
301    ///
302    /// assert!(!RangeInclusive::from(3.0..=5.0).is_empty());
303    /// assert!( RangeInclusive::from(3.0..=f32::NAN).is_empty());
304    /// assert!( RangeInclusive::from(f32::NAN..=5.0).is_empty());
305    /// ```
306    #[unstable(feature = "new_range_api", issue = "125687")]
307    #[inline]
308    pub fn is_empty(&self) -> bool {
309        !(self.start <= self.end)
310    }
311}
312
313impl<Idx: Step> RangeInclusive<Idx> {
314    /// Creates an iterator over the elements within this range.
315    ///
316    /// Shorthand for `.clone().into_iter()`
317    ///
318    /// # Examples
319    ///
320    /// ```
321    /// #![feature(new_range_api)]
322    /// use core::range::RangeInclusive;
323    ///
324    /// let mut i = RangeInclusive::from(3..=8).iter().map(|n| n*n);
325    /// assert_eq!(i.next(), Some(9));
326    /// assert_eq!(i.next(), Some(16));
327    /// assert_eq!(i.next(), Some(25));
328    /// ```
329    #[unstable(feature = "new_range_api", issue = "125687")]
330    #[inline]
331    pub fn iter(&self) -> IterRangeInclusive<Idx> {
332        self.clone().into_iter()
333    }
334}
335
336impl RangeInclusive<usize> {
337    /// Converts to an exclusive `Range` for `SliceIndex` implementations.
338    /// The caller is responsible for dealing with `end == usize::MAX`.
339    #[inline]
340    pub(crate) const fn into_slice_range(self) -> Range<usize> {
341        Range { start: self.start, end: self.end + 1 }
342    }
343}
344
345#[unstable(feature = "new_range_api", issue = "125687")]
346impl<T> RangeBounds<T> for RangeInclusive<T> {
347    fn start_bound(&self) -> Bound<&T> {
348        Included(&self.start)
349    }
350    fn end_bound(&self) -> Bound<&T> {
351        Included(&self.end)
352    }
353}
354
355// This impl intentionally does not have `T: ?Sized`;
356// see https://github.com/rust-lang/rust/pull/61584 for discussion of why.
357//
358/// If you need to use this implementation where `T` is unsized,
359/// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound],
360/// i.e. replace `start..=end` with `(Bound::Included(start), Bound::Included(end))`.
361#[unstable(feature = "new_range_api", issue = "125687")]
362impl<T> RangeBounds<T> for RangeInclusive<&T> {
363    fn start_bound(&self) -> Bound<&T> {
364        Included(self.start)
365    }
366    fn end_bound(&self) -> Bound<&T> {
367        Included(self.end)
368    }
369}
370
371// #[unstable(feature = "range_into_bounds", issue = "136903")]
372#[unstable(feature = "new_range_api", issue = "125687")]
373impl<T> IntoBounds<T> for RangeInclusive<T> {
374    fn into_bounds(self) -> (Bound<T>, Bound<T>) {
375        (Included(self.start), Included(self.end))
376    }
377}
378
379#[unstable(feature = "new_range_api", issue = "125687")]
380#[rustc_const_unstable(feature = "const_index", issue = "143775")]
381impl<T> const From<RangeInclusive<T>> for legacy::RangeInclusive<T> {
382    #[inline]
383    fn from(value: RangeInclusive<T>) -> Self {
384        Self::new(value.start, value.end)
385    }
386}
387#[unstable(feature = "new_range_api", issue = "125687")]
388impl<T> From<legacy::RangeInclusive<T>> for RangeInclusive<T> {
389    #[inline]
390    fn from(value: legacy::RangeInclusive<T>) -> Self {
391        assert!(
392            !value.exhausted,
393            "attempted to convert from an exhausted `legacy::RangeInclusive` (unspecified behavior)"
394        );
395
396        let (start, end) = value.into_inner();
397        RangeInclusive { start, end }
398    }
399}
400
401/// A range only bounded inclusively below (`start..`).
402///
403/// The `RangeFrom` `start..` contains all values with `x >= start`.
404///
405/// *Note*: Overflow in the [`Iterator`] implementation (when the contained
406/// data type reaches its numerical limit) is allowed to panic, wrap, or
407/// saturate. This behavior is defined by the implementation of the [`Step`]
408/// trait. For primitive integers, this follows the normal rules, and respects
409/// the overflow checks profile (panic in debug, wrap in release). Note also
410/// that overflow happens earlier than you might assume: the overflow happens
411/// in the call to `next` that yields the maximum value, as the range must be
412/// set to a state to yield the next value.
413///
414/// [`Step`]: crate::iter::Step
415///
416/// # Examples
417///
418/// The `start..` syntax is a `RangeFrom`:
419///
420/// ```
421/// #![feature(new_range_api)]
422/// use core::range::RangeFrom;
423///
424/// assert_eq!(RangeFrom::from(2..), core::range::RangeFrom { start: 2 });
425/// assert_eq!(2 + 3 + 4, RangeFrom::from(2..).into_iter().take(3).sum());
426/// ```
427#[lang = "RangeFromCopy"]
428#[derive(Clone, Copy, PartialEq, Eq, Hash)]
429#[unstable(feature = "new_range_api", issue = "125687")]
430pub struct RangeFrom<Idx> {
431    /// The lower bound of the range (inclusive).
432    #[unstable(feature = "new_range_api", issue = "125687")]
433    pub start: Idx,
434}
435
436#[unstable(feature = "new_range_api", issue = "125687")]
437impl<Idx: fmt::Debug> fmt::Debug for RangeFrom<Idx> {
438    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
439        self.start.fmt(fmt)?;
440        write!(fmt, "..")?;
441        Ok(())
442    }
443}
444
445impl<Idx: Step> RangeFrom<Idx> {
446    /// Creates an iterator over the elements within this range.
447    ///
448    /// Shorthand for `.clone().into_iter()`
449    ///
450    /// # Examples
451    ///
452    /// ```
453    /// #![feature(new_range_api)]
454    /// use core::range::RangeFrom;
455    ///
456    /// let mut i = RangeFrom::from(3..).iter().map(|n| n*n);
457    /// assert_eq!(i.next(), Some(9));
458    /// assert_eq!(i.next(), Some(16));
459    /// assert_eq!(i.next(), Some(25));
460    /// ```
461    #[unstable(feature = "new_range_api", issue = "125687")]
462    #[inline]
463    pub fn iter(&self) -> IterRangeFrom<Idx> {
464        self.clone().into_iter()
465    }
466}
467
468impl<Idx: PartialOrd<Idx>> RangeFrom<Idx> {
469    /// Returns `true` if `item` is contained in the range.
470    ///
471    /// # Examples
472    ///
473    /// ```
474    /// #![feature(new_range_api)]
475    /// use core::range::RangeFrom;
476    ///
477    /// assert!(!RangeFrom::from(3..).contains(&2));
478    /// assert!( RangeFrom::from(3..).contains(&3));
479    /// assert!( RangeFrom::from(3..).contains(&1_000_000_000));
480    ///
481    /// assert!( RangeFrom::from(0.0..).contains(&0.5));
482    /// assert!(!RangeFrom::from(0.0..).contains(&f32::NAN));
483    /// assert!(!RangeFrom::from(f32::NAN..).contains(&0.5));
484    /// ```
485    #[inline]
486    #[unstable(feature = "new_range_api", issue = "125687")]
487    pub fn contains<U>(&self, item: &U) -> bool
488    where
489        Idx: PartialOrd<U>,
490        U: ?Sized + PartialOrd<Idx>,
491    {
492        <Self as RangeBounds<Idx>>::contains(self, item)
493    }
494}
495
496#[unstable(feature = "new_range_api", issue = "125687")]
497impl<T> RangeBounds<T> for RangeFrom<T> {
498    fn start_bound(&self) -> Bound<&T> {
499        Included(&self.start)
500    }
501    fn end_bound(&self) -> Bound<&T> {
502        Unbounded
503    }
504}
505
506// This impl intentionally does not have `T: ?Sized`;
507// see https://github.com/rust-lang/rust/pull/61584 for discussion of why.
508//
509/// If you need to use this implementation where `T` is unsized,
510/// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound],
511/// i.e. replace `start..` with `(Bound::Included(start), Bound::Unbounded)`.
512#[unstable(feature = "new_range_api", issue = "125687")]
513impl<T> RangeBounds<T> for RangeFrom<&T> {
514    fn start_bound(&self) -> Bound<&T> {
515        Included(self.start)
516    }
517    fn end_bound(&self) -> Bound<&T> {
518        Unbounded
519    }
520}
521
522// #[unstable(feature = "range_into_bounds", issue = "136903")]
523#[unstable(feature = "new_range_api", issue = "125687")]
524impl<T> IntoBounds<T> for RangeFrom<T> {
525    fn into_bounds(self) -> (Bound<T>, Bound<T>) {
526        (Included(self.start), Unbounded)
527    }
528}
529
530#[unstable(feature = "new_range_api", issue = "125687")]
531#[rustc_const_unstable(feature = "const_index", issue = "143775")]
532impl<T> const From<RangeFrom<T>> for legacy::RangeFrom<T> {
533    #[inline]
534    fn from(value: RangeFrom<T>) -> Self {
535        Self { start: value.start }
536    }
537}
538#[unstable(feature = "new_range_api", issue = "125687")]
539#[rustc_const_unstable(feature = "const_index", issue = "143775")]
540impl<T> const From<legacy::RangeFrom<T>> for RangeFrom<T> {
541    #[inline]
542    fn from(value: legacy::RangeFrom<T>) -> Self {
543        Self { start: value.start }
544    }
545}