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_convert", issue = "143773")]
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_convert", issue = "143773")]
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_convert", issue = "143773")]
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")]
388#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
389impl<T> const From<legacy::RangeInclusive<T>> for RangeInclusive<T> {
390 #[inline]
391 fn from(value: legacy::RangeInclusive<T>) -> Self {
392 assert!(
393 !value.exhausted,
394 "attempted to convert from an exhausted `legacy::RangeInclusive` (unspecified behavior)"
395 );
396
397 let (start, end) = value.into_inner();
398 RangeInclusive { start, end }
399 }
400}
401
402/// A range only bounded inclusively below (`start..`).
403///
404/// The `RangeFrom` `start..` contains all values with `x >= start`.
405///
406/// *Note*: Overflow in the [`Iterator`] implementation (when the contained
407/// data type reaches its numerical limit) is allowed to panic, wrap, or
408/// saturate. This behavior is defined by the implementation of the [`Step`]
409/// trait. For primitive integers, this follows the normal rules, and respects
410/// the overflow checks profile (panic in debug, wrap in release). Note also
411/// that overflow happens earlier than you might assume: the overflow happens
412/// in the call to `next` that yields the maximum value, as the range must be
413/// set to a state to yield the next value.
414///
415/// [`Step`]: crate::iter::Step
416///
417/// # Examples
418///
419/// The `start..` syntax is a `RangeFrom`:
420///
421/// ```
422/// #![feature(new_range_api)]
423/// use core::range::RangeFrom;
424///
425/// assert_eq!(RangeFrom::from(2..), core::range::RangeFrom { start: 2 });
426/// assert_eq!(2 + 3 + 4, RangeFrom::from(2..).into_iter().take(3).sum());
427/// ```
428#[lang = "RangeFromCopy"]
429#[derive(Clone, Copy, PartialEq, Eq, Hash)]
430#[unstable(feature = "new_range_api", issue = "125687")]
431pub struct RangeFrom<Idx> {
432 /// The lower bound of the range (inclusive).
433 #[unstable(feature = "new_range_api", issue = "125687")]
434 pub start: Idx,
435}
436
437#[unstable(feature = "new_range_api", issue = "125687")]
438impl<Idx: fmt::Debug> fmt::Debug for RangeFrom<Idx> {
439 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
440 self.start.fmt(fmt)?;
441 write!(fmt, "..")?;
442 Ok(())
443 }
444}
445
446impl<Idx: Step> RangeFrom<Idx> {
447 /// Creates an iterator over the elements within this range.
448 ///
449 /// Shorthand for `.clone().into_iter()`
450 ///
451 /// # Examples
452 ///
453 /// ```
454 /// #![feature(new_range_api)]
455 /// use core::range::RangeFrom;
456 ///
457 /// let mut i = RangeFrom::from(3..).iter().map(|n| n*n);
458 /// assert_eq!(i.next(), Some(9));
459 /// assert_eq!(i.next(), Some(16));
460 /// assert_eq!(i.next(), Some(25));
461 /// ```
462 #[unstable(feature = "new_range_api", issue = "125687")]
463 #[inline]
464 pub fn iter(&self) -> IterRangeFrom<Idx> {
465 self.clone().into_iter()
466 }
467}
468
469impl<Idx: PartialOrd<Idx>> RangeFrom<Idx> {
470 /// Returns `true` if `item` is contained in the range.
471 ///
472 /// # Examples
473 ///
474 /// ```
475 /// #![feature(new_range_api)]
476 /// use core::range::RangeFrom;
477 ///
478 /// assert!(!RangeFrom::from(3..).contains(&2));
479 /// assert!( RangeFrom::from(3..).contains(&3));
480 /// assert!( RangeFrom::from(3..).contains(&1_000_000_000));
481 ///
482 /// assert!( RangeFrom::from(0.0..).contains(&0.5));
483 /// assert!(!RangeFrom::from(0.0..).contains(&f32::NAN));
484 /// assert!(!RangeFrom::from(f32::NAN..).contains(&0.5));
485 /// ```
486 #[inline]
487 #[unstable(feature = "new_range_api", issue = "125687")]
488 pub fn contains<U>(&self, item: &U) -> bool
489 where
490 Idx: PartialOrd<U>,
491 U: ?Sized + PartialOrd<Idx>,
492 {
493 <Self as RangeBounds<Idx>>::contains(self, item)
494 }
495}
496
497#[unstable(feature = "new_range_api", issue = "125687")]
498impl<T> RangeBounds<T> for RangeFrom<T> {
499 fn start_bound(&self) -> Bound<&T> {
500 Included(&self.start)
501 }
502 fn end_bound(&self) -> Bound<&T> {
503 Unbounded
504 }
505}
506
507// This impl intentionally does not have `T: ?Sized`;
508// see https://github.com/rust-lang/rust/pull/61584 for discussion of why.
509//
510/// If you need to use this implementation where `T` is unsized,
511/// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound],
512/// i.e. replace `start..` with `(Bound::Included(start), Bound::Unbounded)`.
513#[unstable(feature = "new_range_api", issue = "125687")]
514impl<T> RangeBounds<T> for RangeFrom<&T> {
515 fn start_bound(&self) -> Bound<&T> {
516 Included(self.start)
517 }
518 fn end_bound(&self) -> Bound<&T> {
519 Unbounded
520 }
521}
522
523// #[unstable(feature = "range_into_bounds", issue = "136903")]
524#[unstable(feature = "new_range_api", issue = "125687")]
525impl<T> IntoBounds<T> for RangeFrom<T> {
526 fn into_bounds(self) -> (Bound<T>, Bound<T>) {
527 (Included(self.start), Unbounded)
528 }
529}
530
531#[unstable(feature = "new_range_api", issue = "125687")]
532#[rustc_const_unstable(feature = "const_index", issue = "143775")]
533impl<T> const From<RangeFrom<T>> for legacy::RangeFrom<T> {
534 #[inline]
535 fn from(value: RangeFrom<T>) -> Self {
536 Self { start: value.start }
537 }
538}
539#[unstable(feature = "new_range_api", issue = "125687")]
540#[rustc_const_unstable(feature = "const_index", issue = "143775")]
541impl<T> const From<legacy::RangeFrom<T>> for RangeFrom<T> {
542 #[inline]
543 fn from(value: legacy::RangeFrom<T>) -> Self {
544 Self { start: value.start }
545 }
546}