core/range.rs
1//! # Replacement range types
2//!
3//! The types within this module are meant to replace the legacy `Range`,
4//! `RangeInclusive`, `RangeToInclusive` and `RangeFrom` types in a future edition.
5//!
6//! ```
7//! use core::range::{Range, RangeFrom, RangeInclusive, RangeToInclusive};
8//!
9//! let arr = [0, 1, 2, 3, 4];
10//! assert_eq!(arr[ .. ], [0, 1, 2, 3, 4]);
11//! assert_eq!(arr[ .. 3 ], [0, 1, 2 ]);
12//! assert_eq!(arr[RangeToInclusive::from( ..=3)], [0, 1, 2, 3 ]);
13//! assert_eq!(arr[ RangeFrom::from(1.. )], [ 1, 2, 3, 4]);
14//! assert_eq!(arr[ Range::from(1..3 )], [ 1, 2 ]);
15//! assert_eq!(arr[ RangeInclusive::from(1..=3)], [ 1, 2, 3 ]);
16//! ```
17
18use crate::fmt;
19use crate::hash::Hash;
20
21mod iter;
22
23#[stable(feature = "new_range_api_legacy", since = "1.98.0")]
24pub mod legacy;
25
26use core::ops::Bound::{self, Excluded, Included, Unbounded};
27
28#[doc(inline)]
29#[stable(feature = "new_range_from_api", since = "1.96.0")]
30pub use iter::RangeFromIter;
31#[doc(inline)]
32#[stable(feature = "new_range_inclusive_api", since = "1.95.0")]
33pub use iter::RangeInclusiveIter;
34#[doc(inline)]
35#[stable(feature = "new_range_api", since = "1.96.0")]
36pub use iter::RangeIter;
37
38use crate::iter::Step;
39// FIXME(one_sided_range): These types should move into this module.
40// FIXME(range_into_bounds): Ditto. Also consider re-exporting `RangeBounds` and related.
41use crate::ops::{IntoBounds, OneSidedRange, OneSidedRangeBound, RangeBounds};
42#[doc(inline)]
43#[stable(feature = "new_range_api_exports", since = "1.98.0")]
44pub use crate::ops::{RangeFull, RangeTo};
45
46/// A (half-open) range bounded inclusively below and exclusively above.
47///
48/// The `Range` contains all values with `start <= x < end`.
49/// It is empty if `start >= end`.
50///
51/// # Examples
52///
53/// ```
54/// use core::range::Range;
55///
56/// assert_eq!(Range::from(3..5), Range { start: 3, end: 5 });
57/// assert_eq!(3 + 4 + 5, Range::from(3..6).into_iter().sum());
58/// ```
59///
60/// # Edition notes
61///
62/// It is planned that the syntax `start..end` will construct this
63/// type in a future edition, but it does not do so today.
64#[lang = "RangeCopy"]
65#[derive(Copy, Hash)]
66#[derive_const(Clone, Default, PartialEq, Eq)]
67#[stable(feature = "new_range_api", since = "1.96.0")]
68pub struct Range<Idx> {
69 /// The lower bound of the range (inclusive).
70 #[stable(feature = "new_range_api", since = "1.96.0")]
71 pub start: Idx,
72 /// The upper bound of the range (exclusive).
73 #[stable(feature = "new_range_api", since = "1.96.0")]
74 pub end: Idx,
75}
76
77#[stable(feature = "new_range_api", since = "1.96.0")]
78impl<Idx: fmt::Debug> fmt::Debug for Range<Idx> {
79 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
80 self.start.fmt(fmt)?;
81 write!(fmt, "..")?;
82 self.end.fmt(fmt)?;
83 Ok(())
84 }
85}
86
87impl<Idx: Step> Range<Idx> {
88 /// Creates an iterator over the elements within this range.
89 ///
90 /// Shorthand for `.clone().into_iter()`
91 ///
92 /// # Examples
93 ///
94 /// ```
95 /// use core::range::Range;
96 ///
97 /// let mut i = Range::from(3..9).iter().map(|n| n*n);
98 /// assert_eq!(i.next(), Some(9));
99 /// assert_eq!(i.next(), Some(16));
100 /// assert_eq!(i.next(), Some(25));
101 /// ```
102 #[stable(feature = "new_range_api", since = "1.96.0")]
103 #[inline]
104 pub fn iter(&self) -> RangeIter<Idx> {
105 self.clone().into_iter()
106 }
107}
108
109impl<Idx: PartialOrd<Idx>> Range<Idx> {
110 /// Returns `true` if `item` is contained in the range.
111 ///
112 /// # Examples
113 ///
114 /// ```
115 /// use core::range::Range;
116 ///
117 /// assert!(!Range::from(3..5).contains(&2));
118 /// assert!( Range::from(3..5).contains(&3));
119 /// assert!( Range::from(3..5).contains(&4));
120 /// assert!(!Range::from(3..5).contains(&5));
121 ///
122 /// assert!(!Range::from(3..3).contains(&3));
123 /// assert!(!Range::from(3..2).contains(&3));
124 ///
125 /// assert!( Range::from(0.0..1.0).contains(&0.5));
126 /// assert!(!Range::from(0.0..1.0).contains(&f32::NAN));
127 /// assert!(!Range::from(0.0..f32::NAN).contains(&0.5));
128 /// assert!(!Range::from(f32::NAN..1.0).contains(&0.5));
129 /// ```
130 #[inline]
131 #[stable(feature = "new_range_api", since = "1.96.0")]
132 #[rustc_const_unstable(feature = "const_range", issue = "none")]
133 pub const fn contains<U>(&self, item: &U) -> bool
134 where
135 Idx: [const] PartialOrd<U>,
136 U: ?Sized + [const] PartialOrd<Idx>,
137 {
138 <Self as RangeBounds<Idx>>::contains(self, item)
139 }
140
141 /// Returns `true` if the range contains no items.
142 ///
143 /// # Examples
144 ///
145 /// ```
146 /// use core::range::Range;
147 ///
148 /// assert!(!Range::from(3..5).is_empty());
149 /// assert!( Range::from(3..3).is_empty());
150 /// assert!( Range::from(3..2).is_empty());
151 /// ```
152 ///
153 /// The range is empty if either side is incomparable:
154 ///
155 /// ```
156 /// use core::range::Range;
157 ///
158 /// assert!(!Range::from(3.0..5.0).is_empty());
159 /// assert!( Range::from(3.0..f32::NAN).is_empty());
160 /// assert!( Range::from(f32::NAN..5.0).is_empty());
161 /// ```
162 #[inline]
163 #[stable(feature = "new_range_api", since = "1.96.0")]
164 #[rustc_const_unstable(feature = "const_range", issue = "none")]
165 #[expect(clippy::neg_cmp_op_on_partial_ord, reason = "incomparable ranges are empty")]
166 pub const fn is_empty(&self) -> bool
167 where
168 Idx: [const] PartialOrd,
169 {
170 !(self.start < self.end)
171 }
172}
173
174#[stable(feature = "new_range_api", since = "1.96.0")]
175#[rustc_const_unstable(feature = "const_range", issue = "none")]
176const impl<T> RangeBounds<T> for Range<T> {
177 fn start_bound(&self) -> Bound<&T> {
178 Included(&self.start)
179 }
180 fn end_bound(&self) -> Bound<&T> {
181 Excluded(&self.end)
182 }
183}
184
185// This impl intentionally does not have `T: ?Sized`;
186// see https://github.com/rust-lang/rust/pull/61584 for discussion of why.
187//
188/// If you need to use this implementation where `T` is unsized,
189/// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound],
190/// i.e. replace `start..end` with `(Bound::Included(start), Bound::Excluded(end))`.
191#[stable(feature = "new_range_api", since = "1.96.0")]
192#[rustc_const_unstable(feature = "const_range", issue = "none")]
193const impl<T> RangeBounds<T> for Range<&T> {
194 fn start_bound(&self) -> Bound<&T> {
195 Included(self.start)
196 }
197 fn end_bound(&self) -> Bound<&T> {
198 Excluded(self.end)
199 }
200}
201
202#[unstable(feature = "range_into_bounds", issue = "136903")]
203#[rustc_const_unstable(feature = "const_range", issue = "none")]
204const impl<T> IntoBounds<T> for Range<T> {
205 fn into_bounds(self) -> (Bound<T>, Bound<T>) {
206 (Included(self.start), Excluded(self.end))
207 }
208}
209
210#[stable(feature = "new_range_api", since = "1.96.0")]
211#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
212const impl<T> From<Range<T>> for legacy::Range<T> {
213 #[inline]
214 fn from(value: Range<T>) -> Self {
215 Self { start: value.start, end: value.end }
216 }
217}
218#[stable(feature = "new_range_api", since = "1.96.0")]
219#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
220const impl<T> From<legacy::Range<T>> for Range<T> {
221 #[inline]
222 fn from(value: legacy::Range<T>) -> Self {
223 Self { start: value.start, end: value.end }
224 }
225}
226
227/// A range bounded inclusively below and above.
228///
229/// The `RangeInclusive` contains all values with `x >= start`
230/// and `x <= last`. It is empty unless `start <= last`.
231///
232/// # Examples
233///
234/// ```
235/// use core::range::RangeInclusive;
236///
237/// assert_eq!(RangeInclusive::from(3..=5), RangeInclusive { start: 3, last: 5 });
238/// assert_eq!(3 + 4 + 5, RangeInclusive::from(3..=5).into_iter().sum());
239/// ```
240///
241/// # Edition notes
242///
243/// It is planned that the syntax `start..=last` will construct this
244/// type in a future edition, but it does not do so today.
245#[lang = "RangeInclusiveCopy"]
246#[derive(Clone, Copy, PartialEq, Eq, Hash)]
247#[stable(feature = "new_range_inclusive_api", since = "1.95.0")]
248pub struct RangeInclusive<Idx> {
249 /// The lower bound of the range (inclusive).
250 #[stable(feature = "new_range_inclusive_api", since = "1.95.0")]
251 pub start: Idx,
252 /// The upper bound of the range (inclusive).
253 #[stable(feature = "new_range_inclusive_api", since = "1.95.0")]
254 pub last: Idx,
255}
256
257#[stable(feature = "new_range_inclusive_api", since = "1.95.0")]
258impl<Idx: fmt::Debug> fmt::Debug for RangeInclusive<Idx> {
259 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
260 self.start.fmt(fmt)?;
261 write!(fmt, "..=")?;
262 self.last.fmt(fmt)?;
263 Ok(())
264 }
265}
266
267impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> {
268 /// Returns `true` if `item` is contained in the range.
269 ///
270 /// # Examples
271 ///
272 /// ```
273 /// use core::range::RangeInclusive;
274 ///
275 /// assert!(!RangeInclusive::from(3..=5).contains(&2));
276 /// assert!( RangeInclusive::from(3..=5).contains(&3));
277 /// assert!( RangeInclusive::from(3..=5).contains(&4));
278 /// assert!( RangeInclusive::from(3..=5).contains(&5));
279 /// assert!(!RangeInclusive::from(3..=5).contains(&6));
280 ///
281 /// assert!( RangeInclusive::from(3..=3).contains(&3));
282 /// assert!(!RangeInclusive::from(3..=2).contains(&3));
283 ///
284 /// assert!( RangeInclusive::from(0.0..=1.0).contains(&1.0));
285 /// assert!(!RangeInclusive::from(0.0..=1.0).contains(&f32::NAN));
286 /// assert!(!RangeInclusive::from(0.0..=f32::NAN).contains(&0.0));
287 /// assert!(!RangeInclusive::from(f32::NAN..=1.0).contains(&1.0));
288 /// ```
289 #[inline]
290 #[stable(feature = "new_range_inclusive_api", since = "1.95.0")]
291 #[rustc_const_unstable(feature = "const_range", issue = "none")]
292 pub const fn contains<U>(&self, item: &U) -> bool
293 where
294 Idx: [const] PartialOrd<U>,
295 U: ?Sized + [const] PartialOrd<Idx>,
296 {
297 <Self as RangeBounds<Idx>>::contains(self, item)
298 }
299
300 /// Returns `true` if the range contains no items.
301 ///
302 /// # Examples
303 ///
304 /// ```
305 /// use core::range::RangeInclusive;
306 ///
307 /// assert!(!RangeInclusive::from(3..=5).is_empty());
308 /// assert!(!RangeInclusive::from(3..=3).is_empty());
309 /// assert!( RangeInclusive::from(3..=2).is_empty());
310 /// ```
311 ///
312 /// The range is empty if either side is incomparable:
313 ///
314 /// ```
315 /// use core::range::RangeInclusive;
316 ///
317 /// assert!(!RangeInclusive::from(3.0..=5.0).is_empty());
318 /// assert!( RangeInclusive::from(3.0..=f32::NAN).is_empty());
319 /// assert!( RangeInclusive::from(f32::NAN..=5.0).is_empty());
320 /// ```
321 #[stable(feature = "new_range_inclusive_api", since = "1.95.0")]
322 #[inline]
323 #[rustc_const_unstable(feature = "const_range", issue = "none")]
324 #[expect(clippy::neg_cmp_op_on_partial_ord, reason = "incomparable ranges are empty")]
325 pub const fn is_empty(&self) -> bool
326 where
327 Idx: [const] PartialOrd,
328 {
329 !(self.start <= self.last)
330 }
331}
332
333impl<Idx: Step> RangeInclusive<Idx> {
334 /// Creates an iterator over the elements within this range.
335 ///
336 /// Shorthand for `.clone().into_iter()`
337 ///
338 /// # Examples
339 ///
340 /// ```
341 /// use core::range::RangeInclusive;
342 ///
343 /// let mut i = RangeInclusive::from(3..=8).iter().map(|n| n*n);
344 /// assert_eq!(i.next(), Some(9));
345 /// assert_eq!(i.next(), Some(16));
346 /// assert_eq!(i.next(), Some(25));
347 /// ```
348 #[stable(feature = "new_range_inclusive_api", since = "1.95.0")]
349 #[inline]
350 pub fn iter(&self) -> RangeInclusiveIter<Idx> {
351 self.clone().into_iter()
352 }
353}
354
355#[stable(feature = "new_range_inclusive_api", since = "1.95.0")]
356#[rustc_const_unstable(feature = "const_range", issue = "none")]
357const impl<T> RangeBounds<T> for RangeInclusive<T> {
358 fn start_bound(&self) -> Bound<&T> {
359 Included(&self.start)
360 }
361 fn end_bound(&self) -> Bound<&T> {
362 Included(&self.last)
363 }
364}
365
366// This impl intentionally does not have `T: ?Sized`;
367// see https://github.com/rust-lang/rust/pull/61584 for discussion of why.
368//
369/// If you need to use this implementation where `T` is unsized,
370/// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound],
371/// i.e. replace `start..=end` with `(Bound::Included(start), Bound::Included(end))`.
372#[stable(feature = "new_range_inclusive_api", since = "1.95.0")]
373#[rustc_const_unstable(feature = "const_range", issue = "none")]
374const impl<T> RangeBounds<T> for RangeInclusive<&T> {
375 fn start_bound(&self) -> Bound<&T> {
376 Included(self.start)
377 }
378 fn end_bound(&self) -> Bound<&T> {
379 Included(self.last)
380 }
381}
382
383// #[stable(feature = "new_range_inclusive_api", since = "1.95.0")]
384#[unstable(feature = "range_into_bounds", issue = "136903")]
385#[rustc_const_unstable(feature = "const_range", issue = "none")]
386const impl<T> IntoBounds<T> for RangeInclusive<T> {
387 fn into_bounds(self) -> (Bound<T>, Bound<T>) {
388 (Included(self.start), Included(self.last))
389 }
390}
391
392#[stable(feature = "new_range_inclusive_api", since = "1.95.0")]
393#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
394const impl<T> From<RangeInclusive<T>> for legacy::RangeInclusive<T> {
395 #[inline]
396 fn from(value: RangeInclusive<T>) -> Self {
397 Self::new(value.start, value.last)
398 }
399}
400#[stable(feature = "new_range_inclusive_api", since = "1.95.0")]
401#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
402const impl<T> From<legacy::RangeInclusive<T>> for RangeInclusive<T> {
403 /// Converts from a legacy range to a non-legacy range, potentially panicking.
404 ///
405 /// # Panics
406 ///
407 /// If the legacy range iterator has been exhausted,
408 /// this function will either panic or return an empty range.
409 ///
410 /// # Examples
411 ///
412 /// ```
413 /// use core::range::legacy;
414 /// use core::range::RangeInclusive;
415 ///
416 /// let single: legacy::RangeInclusive<i32> = 0..=1;
417 /// let single = RangeInclusive::from(single);
418 /// assert_eq!((single.start, single.last), (0, 1));
419 ///
420 /// let empty: legacy::RangeInclusive<i32> = 0..=0;
421 /// let empty = RangeInclusive::from(empty);
422 /// assert_eq!((empty.start, empty.last), (0, 0));
423 /// ```
424 ///
425 /// ```
426 /// # // This test requires unwinding to work.
427 /// # // Disable it when unwinding isn't available.
428 /// # #[cfg(panic = "unwind")]
429 /// # fn main() {
430 /// use core::range::legacy;
431 /// use core::range::RangeInclusive;
432 /// use std::panic::catch_unwind;
433 ///
434 /// let mut exhausted: legacy::RangeInclusive<i32> = 0..=0;
435 /// exhausted.next();
436 /// let result = catch_unwind(|| RangeInclusive::from(exhausted));
437 /// // The `from` call either panicked or returned an empty range.
438 /// assert!(result.is_err() || result.is_ok_and(|range| range.is_empty()));
439 /// # }
440 /// # #[cfg(not(panic = "unwind"))]
441 /// # fn main() {}
442 /// ```
443 #[inline]
444 fn from(value: legacy::RangeInclusive<T>) -> Self {
445 assert!(
446 !value.exhausted,
447 "attempted to convert from an exhausted `legacy::RangeInclusive`"
448 );
449
450 let (start, last) = value.into_inner();
451 RangeInclusive { start, last }
452 }
453}
454
455/// A range only bounded inclusively below.
456///
457/// The `RangeFrom` contains all values with `x >= start`.
458///
459/// *Note*: Overflow in the [`IntoIterator`] implementation (when the contained
460/// data type reaches its numerical limit) is allowed to panic, wrap, or
461/// saturate. This behavior is defined by the implementation of the [`Step`]
462/// trait. For primitive integers, this follows the normal rules, and respects
463/// the overflow checks profile (panic in debug, wrap in release). Unlike
464/// its legacy counterpart, the iterator will only panic after yielding the
465/// maximum value when overflow checks are enabled.
466///
467/// [`Step`]: crate::iter::Step
468///
469/// # Examples
470///
471/// ```
472/// use core::range::RangeFrom;
473///
474/// assert_eq!(RangeFrom::from(2..), core::range::RangeFrom { start: 2 });
475/// assert_eq!(2 + 3 + 4, RangeFrom::from(2..).into_iter().take(3).sum());
476/// ```
477///
478/// # Edition notes
479///
480/// It is planned that the syntax `start..` will construct this
481/// type in a future edition, but it does not do so today.
482#[lang = "RangeFromCopy"]
483#[derive(Copy, Hash)]
484#[derive_const(Clone, PartialEq, Eq)]
485#[stable(feature = "new_range_from_api", since = "1.96.0")]
486pub struct RangeFrom<Idx> {
487 /// The lower bound of the range (inclusive).
488 #[stable(feature = "new_range_from_api", since = "1.96.0")]
489 pub start: Idx,
490}
491
492#[stable(feature = "new_range_from_api", since = "1.96.0")]
493impl<Idx: fmt::Debug> fmt::Debug for RangeFrom<Idx> {
494 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
495 self.start.fmt(fmt)?;
496 write!(fmt, "..")?;
497 Ok(())
498 }
499}
500
501impl<Idx: Step> RangeFrom<Idx> {
502 /// Creates an iterator over the elements within this range.
503 ///
504 /// Shorthand for `.clone().into_iter()`
505 ///
506 /// # Examples
507 ///
508 /// ```
509 /// use core::range::RangeFrom;
510 ///
511 /// let mut i = RangeFrom::from(3..).iter().map(|n| n*n);
512 /// assert_eq!(i.next(), Some(9));
513 /// assert_eq!(i.next(), Some(16));
514 /// assert_eq!(i.next(), Some(25));
515 /// ```
516 #[stable(feature = "new_range_from_api", since = "1.96.0")]
517 #[inline]
518 pub fn iter(&self) -> RangeFromIter<Idx> {
519 self.clone().into_iter()
520 }
521}
522
523impl<Idx: PartialOrd<Idx>> RangeFrom<Idx> {
524 /// Returns `true` if `item` is contained in the range.
525 ///
526 /// # Examples
527 ///
528 /// ```
529 /// use core::range::RangeFrom;
530 ///
531 /// assert!(!RangeFrom::from(3..).contains(&2));
532 /// assert!( RangeFrom::from(3..).contains(&3));
533 /// assert!( RangeFrom::from(3..).contains(&1_000_000_000));
534 ///
535 /// assert!( RangeFrom::from(0.0..).contains(&0.5));
536 /// assert!(!RangeFrom::from(0.0..).contains(&f32::NAN));
537 /// assert!(!RangeFrom::from(f32::NAN..).contains(&0.5));
538 /// ```
539 #[inline]
540 #[stable(feature = "new_range_from_api", since = "1.96.0")]
541 #[rustc_const_unstable(feature = "const_range", issue = "none")]
542 pub const fn contains<U>(&self, item: &U) -> bool
543 where
544 Idx: [const] PartialOrd<U>,
545 U: ?Sized + [const] PartialOrd<Idx>,
546 {
547 <Self as RangeBounds<Idx>>::contains(self, item)
548 }
549}
550
551#[stable(feature = "new_range_from_api", since = "1.96.0")]
552#[rustc_const_unstable(feature = "const_range", issue = "none")]
553const impl<T> RangeBounds<T> for RangeFrom<T> {
554 fn start_bound(&self) -> Bound<&T> {
555 Included(&self.start)
556 }
557 fn end_bound(&self) -> Bound<&T> {
558 Unbounded
559 }
560}
561
562// This impl intentionally does not have `T: ?Sized`;
563// see https://github.com/rust-lang/rust/pull/61584 for discussion of why.
564//
565/// If you need to use this implementation where `T` is unsized,
566/// consider using the `RangeBounds` impl for a 2-tuple of [`Bound<&T>`][Bound],
567/// i.e. replace `start..` with `(Bound::Included(start), Bound::Unbounded)`.
568#[stable(feature = "new_range_from_api", since = "1.96.0")]
569#[rustc_const_unstable(feature = "const_range", issue = "none")]
570const impl<T> RangeBounds<T> for RangeFrom<&T> {
571 fn start_bound(&self) -> Bound<&T> {
572 Included(self.start)
573 }
574 fn end_bound(&self) -> Bound<&T> {
575 Unbounded
576 }
577}
578
579#[unstable(feature = "range_into_bounds", issue = "136903")]
580#[rustc_const_unstable(feature = "const_range", issue = "none")]
581const impl<T> IntoBounds<T> for RangeFrom<T> {
582 fn into_bounds(self) -> (Bound<T>, Bound<T>) {
583 (Included(self.start), Unbounded)
584 }
585}
586
587#[unstable(feature = "one_sided_range", issue = "69780")]
588#[rustc_const_unstable(feature = "const_range", issue = "none")]
589const impl<T> OneSidedRange<T> for RangeFrom<T>
590where
591 Self: RangeBounds<T>,
592{
593 fn bound(self) -> (OneSidedRangeBound, T) {
594 (OneSidedRangeBound::StartInclusive, self.start)
595 }
596}
597
598#[stable(feature = "new_range_from_api", since = "1.96.0")]
599#[rustc_const_unstable(feature = "const_index", issue = "143775")]
600const impl<T> From<RangeFrom<T>> for legacy::RangeFrom<T> {
601 #[inline]
602 fn from(value: RangeFrom<T>) -> Self {
603 Self { start: value.start }
604 }
605}
606#[stable(feature = "new_range_from_api", since = "1.96.0")]
607#[rustc_const_unstable(feature = "const_index", issue = "143775")]
608const impl<T> From<legacy::RangeFrom<T>> for RangeFrom<T> {
609 #[inline]
610 fn from(value: legacy::RangeFrom<T>) -> Self {
611 Self { start: value.start }
612 }
613}
614
615/// A range only bounded inclusively above.
616///
617/// The `RangeToInclusive` contains all values with `x <= last`.
618/// It cannot serve as an [`Iterator`] because it doesn't have a starting point.
619///
620/// # Examples
621///
622/// ```standalone_crate
623/// #![feature(new_range)]
624/// assert_eq!((..=5), std::range::RangeToInclusive { last: 5 });
625/// ```
626///
627/// It does not have an [`IntoIterator`] implementation, so you can't use it in a
628/// `for` loop directly. This won't compile:
629///
630/// ```compile_fail,E0277
631/// // error[E0277]: the trait bound `std::range::RangeToInclusive<{integer}>:
632/// // std::iter::Iterator` is not satisfied
633/// for i in ..=5 {
634/// // ...
635/// }
636/// ```
637///
638/// When used as a [slicing index], `RangeToInclusive` produces a slice of all
639/// array elements up to and including the index indicated by `last`.
640///
641/// ```
642/// let arr = [0, 1, 2, 3, 4];
643/// assert_eq!(arr[ .. ], [0, 1, 2, 3, 4]);
644/// assert_eq!(arr[ .. 3], [0, 1, 2 ]);
645/// assert_eq!(arr[ ..=3], [0, 1, 2, 3 ]); // This is a `RangeToInclusive`
646/// assert_eq!(arr[1.. ], [ 1, 2, 3, 4]);
647/// assert_eq!(arr[1.. 3], [ 1, 2 ]);
648/// assert_eq!(arr[1..=3], [ 1, 2, 3 ]);
649/// ```
650///
651/// [slicing index]: crate::slice::SliceIndex
652///
653/// # Edition notes
654///
655/// It is planned that the syntax `..=last` will construct this
656/// type in a future edition, but it does not do so today.
657#[lang = "RangeToInclusiveCopy"]
658#[doc(alias = "..=")]
659#[derive(Copy, Clone, PartialEq, Eq, Hash)]
660#[stable(feature = "new_range_to_inclusive_api", since = "1.96.0")]
661pub struct RangeToInclusive<Idx> {
662 /// The upper bound of the range (inclusive)
663 #[stable(feature = "new_range_to_inclusive_api", since = "1.96.0")]
664 pub last: Idx,
665}
666
667#[stable(feature = "new_range_to_inclusive_api", since = "1.96.0")]
668impl<Idx: fmt::Debug> fmt::Debug for RangeToInclusive<Idx> {
669 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
670 write!(fmt, "..=")?;
671 self.last.fmt(fmt)?;
672 Ok(())
673 }
674}
675
676impl<Idx: PartialOrd<Idx>> RangeToInclusive<Idx> {
677 /// Returns `true` if `item` is contained in the range.
678 ///
679 /// # Examples
680 ///
681 /// ```
682 /// assert!( (..=5).contains(&-1_000_000_000));
683 /// assert!( (..=5).contains(&5));
684 /// assert!(!(..=5).contains(&6));
685 ///
686 /// assert!( (..=1.0).contains(&1.0));
687 /// assert!(!(..=1.0).contains(&f32::NAN));
688 /// assert!(!(..=f32::NAN).contains(&0.5));
689 /// ```
690 #[inline]
691 #[stable(feature = "new_range_to_inclusive_api", since = "1.96.0")]
692 #[rustc_const_unstable(feature = "const_range", issue = "none")]
693 pub const fn contains<U>(&self, item: &U) -> bool
694 where
695 Idx: [const] PartialOrd<U>,
696 U: ?Sized + [const] PartialOrd<Idx>,
697 {
698 <Self as RangeBounds<Idx>>::contains(self, item)
699 }
700}
701
702#[stable(feature = "new_range_to_inclusive_api", since = "1.96.0")]
703impl<T> From<legacy::RangeToInclusive<T>> for RangeToInclusive<T> {
704 fn from(value: legacy::RangeToInclusive<T>) -> Self {
705 Self { last: value.end }
706 }
707}
708#[stable(feature = "new_range_to_inclusive_api", since = "1.96.0")]
709impl<T> From<RangeToInclusive<T>> for legacy::RangeToInclusive<T> {
710 fn from(value: RangeToInclusive<T>) -> Self {
711 Self { end: value.last }
712 }
713}
714
715// RangeToInclusive<Idx> cannot impl From<RangeTo<Idx>>
716// because underflow would be possible with (..0).into()
717
718#[stable(feature = "new_range_to_inclusive_api", since = "1.96.0")]
719#[rustc_const_unstable(feature = "const_range", issue = "none")]
720const impl<T> RangeBounds<T> for RangeToInclusive<T> {
721 fn start_bound(&self) -> Bound<&T> {
722 Unbounded
723 }
724 fn end_bound(&self) -> Bound<&T> {
725 Included(&self.last)
726 }
727}
728
729#[stable(feature = "new_range_to_inclusive_api", since = "1.96.0")]
730#[rustc_const_unstable(feature = "const_range", issue = "none")]
731const impl<T> RangeBounds<T> for RangeToInclusive<&T> {
732 fn start_bound(&self) -> Bound<&T> {
733 Unbounded
734 }
735 fn end_bound(&self) -> Bound<&T> {
736 Included(self.last)
737 }
738}
739
740#[unstable(feature = "range_into_bounds", issue = "136903")]
741#[rustc_const_unstable(feature = "const_range", issue = "none")]
742const impl<T> IntoBounds<T> for RangeToInclusive<T> {
743 fn into_bounds(self) -> (Bound<T>, Bound<T>) {
744 (Unbounded, Included(self.last))
745 }
746}
747
748#[unstable(feature = "one_sided_range", issue = "69780")]
749#[rustc_const_unstable(feature = "const_range", issue = "none")]
750const impl<T> OneSidedRange<T> for RangeToInclusive<T>
751where
752 Self: RangeBounds<T>,
753{
754 fn bound(self) -> (OneSidedRangeBound, T) {
755 (OneSidedRangeBound::EndInclusive, self.last)
756 }
757}