Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 0cdca2c

Browse files
committedSep 26, 2024·
distinguish overflow and unimplemented in Step::steps_between
1 parent b511753 commit 0cdca2c

File tree

4 files changed

+89
-80
lines changed

4 files changed

+89
-80
lines changed
 

Diff for: ‎compiler/rustc_abi/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,7 @@ impl AddAssign for Size {
624624
#[cfg(feature = "nightly")]
625625
impl Step for Size {
626626
#[inline]
627-
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
627+
fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
628628
u64::steps_between(&start.bytes(), &end.bytes())
629629
}
630630

Diff for: ‎compiler/rustc_index_macros/src/newtype.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ impl Parse for Newtype {
122122
#gate_rustc_only
123123
impl ::std::iter::Step for #name {
124124
#[inline]
125-
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
125+
fn steps_between(start: &Self, end: &Self) -> (usize,Option<usize>) {
126126
<usize as ::std::iter::Step>::steps_between(
127127
&Self::index(*start),
128128
&Self::index(*end),

Diff for: ‎library/core/src/iter/range.rs

+64-66
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,21 @@ unsafe_impl_trusted_step![AsciiChar char i8 i16 i32 i64 i128 isize u8 u16 u32 u6
2222
/// The *predecessor* operation moves towards values that compare lesser.
2323
#[unstable(feature = "step_trait", issue = "42168")]
2424
pub trait Step: Clone + PartialOrd + Sized {
25-
/// Returns the number of *successor* steps required to get from `start` to `end`.
25+
/// Returns the bounds on the number of *successor* steps required to get from `start` to `end`
26+
/// like [`Iterator::size_hint()`][std::iter::Iterator::size_hint()].
2627
///
27-
/// Returns `None` if the number of steps would overflow `usize`
28-
/// (or is infinite, or if `end` would never be reached).
28+
/// Returns `(usize::MAX, None)` if the number of steps would overflow `usize`, or is infinite.
2929
///
3030
/// # Invariants
3131
///
3232
/// For any `a`, `b`, and `n`:
3333
///
34-
/// * `steps_between(&a, &b) == Some(n)` if and only if `Step::forward_checked(&a, n) == Some(b)`
35-
/// * `steps_between(&a, &b) == Some(n)` if and only if `Step::backward_checked(&b, n) == Some(a)`
36-
/// * `steps_between(&a, &b) == Some(n)` only if `a <= b`
37-
/// * Corollary: `steps_between(&a, &b) == Some(0)` if and only if `a == b`
38-
/// * Note that `a <= b` does _not_ imply `steps_between(&a, &b) != None`;
39-
/// this is the case when it would require more than `usize::MAX` steps to get to `b`
40-
/// * `steps_between(&a, &b) == None` if `a > b`
41-
fn steps_between(start: &Self, end: &Self) -> Option<usize>;
34+
/// * `steps_between(&a, &b) == (n, Some(n))` if and only if `Step::forward_checked(&a, n) == Some(b)`
35+
/// * `steps_between(&a, &b) == (n, Some(n))` if and only if `Step::backward_checked(&b, n) == Some(a)`
36+
/// * `steps_between(&a, &b) == (n, Some(n))` only if `a <= b`
37+
/// * Corollary: `steps_between(&a, &b) == (0, Some(0))` if and only if `a == b`
38+
/// * `steps_between(&a, &b) == (0, None)` if `a > b`
39+
fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>);
4240

4341
/// Returns the value that would be obtained by taking the *successor*
4442
/// of `self` `count` times.
@@ -169,7 +167,7 @@ pub trait Step: Clone + PartialOrd + Sized {
169167
/// For any `a`:
170168
///
171169
/// * if there exists `b` such that `b < a`, it is safe to call `Step::backward_unchecked(a, 1)`
172-
/// * if there exists `b`, `n` such that `steps_between(&b, &a) == Some(n)`,
170+
/// * if there exists `b`, `n` such that `steps_between(&b, &a) == (n, Some(n))`,
173171
/// it is safe to call `Step::backward_unchecked(a, m)` for any `m <= n`.
174172
/// * Corollary: `Step::backward_unchecked(a, 0)` is always safe.
175173
///
@@ -261,12 +259,12 @@ macro_rules! step_integer_impls {
261259
step_unsigned_methods!();
262260

263261
#[inline]
264-
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
262+
fn steps_between(start: &Self, end: &Self) -> (usize,Option<usize>) {
265263
if *start <= *end {
266264
// This relies on $u_narrower <= usize
267-
Some((*end - *start) as usize)
265+
((*end-*start) as usize, Some((*end - *start) as usize))
268266
} else {
269-
None
267+
(0,None)
270268
}
271269
}
272270

@@ -294,16 +292,16 @@ macro_rules! step_integer_impls {
294292
step_signed_methods!($u_narrower);
295293

296294
#[inline]
297-
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
295+
fn steps_between(start: &Self, end: &Self) -> (usize,Option<usize>) {
298296
if *start <= *end {
299297
// This relies on $i_narrower <= usize
300298
//
301299
// Casting to isize extends the width but preserves the sign.
302300
// Use wrapping_sub in isize space and cast to usize to compute
303301
// the difference that might not fit inside the range of isize.
304-
Some((*end as isize).wrapping_sub(*start as isize) as usize)
302+
((*end as isize).wrapping_sub(*start as isize) as usize,Some((*end as isize).wrapping_sub(*start as isize) as usize))
305303
} else {
306-
None
304+
(0,None)
307305
}
308306
}
309307

@@ -359,11 +357,15 @@ macro_rules! step_integer_impls {
359357
step_unsigned_methods!();
360358

361359
#[inline]
362-
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
360+
fn steps_between(start: &Self, end: &Self) -> (usize,Option<usize>) {
363361
if *start <= *end {
364-
usize::try_from(*end - *start).ok()
362+
if let Ok(steps) = usize::try_from(*end - *start) {
363+
(steps,Some(steps))
364+
}else{
365+
(usize::MAX,None)
366+
}
365367
} else {
366-
None
368+
(0,None)
367369
}
368370
}
369371

@@ -385,16 +387,22 @@ macro_rules! step_integer_impls {
385387
step_signed_methods!($u_wider);
386388

387389
#[inline]
388-
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
390+
fn steps_between(start: &Self, end: &Self) -> (usize,Option<usize>) {
389391
if *start <= *end {
390392
match end.checked_sub(*start) {
391-
Some(result) => usize::try_from(result).ok(),
393+
Some(result) => {
394+
if let Ok(steps) = usize::try_from(result) {
395+
(steps,Some(steps))
396+
}else{
397+
(usize::MAX, None)
398+
}
399+
}
392400
// If the difference is too big for e.g. i128,
393401
// it's also gonna be too big for usize with fewer bits.
394-
None => None,
402+
None => (usize::MAX, None),
395403
}
396404
} else {
397-
None
405+
(0,None)
398406
}
399407
}
400408

@@ -433,18 +441,26 @@ step_integer_impls! {
433441
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
434442
impl Step for char {
435443
#[inline]
436-
fn steps_between(&start: &char, &end: &char) -> Option<usize> {
444+
fn steps_between(&start: &char, &end: &char) -> (usize, Option<usize>) {
437445
let start = start as u32;
438446
let end = end as u32;
439447
if start <= end {
440448
let count = end - start;
441449
if start < 0xD800 && 0xE000 <= end {
442-
usize::try_from(count - 0x800).ok()
450+
if let Ok(steps) = usize::try_from(count - 0x800) {
451+
(steps, Some(steps))
452+
} else {
453+
(usize::MAX, None)
454+
}
443455
} else {
444-
usize::try_from(count).ok()
456+
if let Ok(steps) = usize::try_from(count) {
457+
(steps, Some(steps))
458+
} else {
459+
(usize::MAX, None)
460+
}
445461
}
446462
} else {
447-
None
463+
(0, None)
448464
}
449465
}
450466

@@ -512,7 +528,7 @@ impl Step for char {
512528
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
513529
impl Step for AsciiChar {
514530
#[inline]
515-
fn steps_between(&start: &AsciiChar, &end: &AsciiChar) -> Option<usize> {
531+
fn steps_between(&start: &AsciiChar, &end: &AsciiChar) -> (usize, Option<usize>) {
516532
Step::steps_between(&start.to_u8(), &end.to_u8())
517533
}
518534

@@ -554,7 +570,7 @@ impl Step for AsciiChar {
554570
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
555571
impl Step for Ipv4Addr {
556572
#[inline]
557-
fn steps_between(&start: &Ipv4Addr, &end: &Ipv4Addr) -> Option<usize> {
573+
fn steps_between(&start: &Ipv4Addr, &end: &Ipv4Addr) -> (usize, Option<usize>) {
558574
u32::steps_between(&start.to_bits(), &end.to_bits())
559575
}
560576

@@ -586,7 +602,7 @@ impl Step for Ipv4Addr {
586602
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
587603
impl Step for Ipv6Addr {
588604
#[inline]
589-
fn steps_between(&start: &Ipv6Addr, &end: &Ipv6Addr) -> Option<usize> {
605+
fn steps_between(&start: &Ipv6Addr, &end: &Ipv6Addr) -> (usize, Option<usize>) {
590606
u128::steps_between(&start.to_bits(), &end.to_bits())
591607
}
592608

@@ -690,11 +706,8 @@ impl<A: Step> RangeIteratorImpl for ops::Range<A> {
690706

691707
#[inline]
692708
default fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
693-
let available = if self.start <= self.end {
694-
Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
695-
} else {
696-
0
697-
};
709+
let steps = Step::steps_between(&self.start, &self.end);
710+
let available = if let Some(steps) = steps.1 { steps } else { steps.0 };
698711

699712
let taken = available.min(n);
700713

@@ -731,11 +744,8 @@ impl<A: Step> RangeIteratorImpl for ops::Range<A> {
731744

732745
#[inline]
733746
default fn spec_advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
734-
let available = if self.start <= self.end {
735-
Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
736-
} else {
737-
0
738-
};
747+
let steps = Step::steps_between(&self.start, &self.end);
748+
let available = if let Some(steps) = steps.1 { steps } else { steps.0 };
739749

740750
let taken = available.min(n);
741751

@@ -775,11 +785,8 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> {
775785

776786
#[inline]
777787
fn spec_advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
778-
let available = if self.start <= self.end {
779-
Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
780-
} else {
781-
0
782-
};
788+
let steps = Step::steps_between(&self.start, &self.end);
789+
let available = if let Some(steps) = steps.1 { steps } else { steps.0 };
783790

784791
let taken = available.min(n);
785792

@@ -819,11 +826,8 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> {
819826

820827
#[inline]
821828
fn spec_advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
822-
let available = if self.start <= self.end {
823-
Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX)
824-
} else {
825-
0
826-
};
829+
let steps = Step::steps_between(&self.start, &self.end);
830+
let available = if let Some(steps) = steps.1 { steps } else { steps.0 };
827831

828832
let taken = available.min(n);
829833

@@ -845,18 +849,13 @@ impl<A: Step> Iterator for ops::Range<A> {
845849

846850
#[inline]
847851
fn size_hint(&self) -> (usize, Option<usize>) {
848-
if self.start < self.end {
849-
let hint = Step::steps_between(&self.start, &self.end);
850-
(hint.unwrap_or(usize::MAX), hint)
851-
} else {
852-
(0, Some(0))
853-
}
852+
Step::steps_between(&self.start, &self.end)
854853
}
855854

856855
#[inline]
857856
fn count(self) -> usize {
858857
if self.start < self.end {
859-
Step::steps_between(&self.start, &self.end).expect("count overflowed usize")
858+
Step::steps_between(&self.start, &self.end).1.expect("count overflowed usize")
860859
} else {
861860
0
862861
}
@@ -980,11 +979,11 @@ impl<A: Step> DoubleEndedIterator for ops::Range<A> {
980979
// Safety:
981980
// The following invariants for `Step::steps_between` exist:
982981
//
983-
// > * `steps_between(&a, &b) == Some(n)` only if `a <= b`
984-
// > * Note that `a <= b` does _not_ imply `steps_between(&a, &b) != None`;
982+
// > * `steps_between(&a, &b) == (n, Some(n))` only if `a <= b`
983+
// > * Note that `a <= b` does _not_ imply `steps_between(&a, &b) != (n, None)`;
985984
// > this is the case when it would require more than `usize::MAX` steps to
986985
// > get to `b`
987-
// > * `steps_between(&a, &b) == None` if `a > b`
986+
// > * `steps_between(&a, &b) == (0, None)` if `a > b`
988987
//
989988
// The first invariant is what is generally required for `TrustedLen` to be
990989
// sound. The note addendum satisfies an additional `TrustedLen` invariant.
@@ -1253,10 +1252,8 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
12531252
return (0, Some(0));
12541253
}
12551254

1256-
match Step::steps_between(&self.start, &self.end) {
1257-
Some(hint) => (hint.saturating_add(1), hint.checked_add(1)),
1258-
None => (usize::MAX, None),
1259-
}
1255+
let hint = Step::steps_between(&self.start, &self.end);
1256+
(hint.0.saturating_add(1), hint.1.and_then(|steps| steps.checked_add(1)))
12601257
}
12611258

12621259
#[inline]
@@ -1266,6 +1263,7 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
12661263
}
12671264

12681265
Step::steps_between(&self.start, &self.end)
1266+
.1
12691267
.and_then(|steps| steps.checked_add(1))
12701268
.expect("count overflowed usize")
12711269
}

Diff for: ‎library/core/tests/iter/traits/step.rs

+23-12
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,37 @@ use core::iter::*;
22

33
#[test]
44
fn test_steps_between() {
5-
assert_eq!(Step::steps_between(&20_u8, &200_u8), Some(180_usize));
6-
assert_eq!(Step::steps_between(&-20_i8, &80_i8), Some(100_usize));
7-
assert_eq!(Step::steps_between(&-120_i8, &80_i8), Some(200_usize));
8-
assert_eq!(Step::steps_between(&20_u32, &4_000_100_u32), Some(4_000_080_usize));
9-
assert_eq!(Step::steps_between(&-20_i32, &80_i32), Some(100_usize));
10-
assert_eq!(Step::steps_between(&-2_000_030_i32, &2_000_050_i32), Some(4_000_080_usize));
5+
assert_eq!(Step::steps_between(&20_u8, &200_u8), (180_usize, Some(180_usize)));
6+
assert_eq!(Step::steps_between(&-20_i8, &80_i8), (100_usize, Some(100_usize)));
7+
assert_eq!(Step::steps_between(&-120_i8, &80_i8), (200_usize, Some(200_usize)));
8+
assert_eq!(
9+
Step::steps_between(&20_u32, &4_000_100_u32),
10+
(4_000_080_usize, Some(4_000_080_usize))
11+
);
12+
assert_eq!(Step::steps_between(&-20_i32, &80_i32), (100_usize, Some(100_usize)));
13+
assert_eq!(
14+
Step::steps_between(&-2_000_030_i32, &2_000_050_i32),
15+
(4_000_080_usize, Some(4_000_080_usize))
16+
);
1117

1218
// Skip u64/i64 to avoid differences with 32-bit vs 64-bit platforms
1319

14-
assert_eq!(Step::steps_between(&20_u128, &200_u128), Some(180_usize));
15-
assert_eq!(Step::steps_between(&-20_i128, &80_i128), Some(100_usize));
20+
assert_eq!(Step::steps_between(&20_u128, &200_u128), (180_usize, Some(180_usize)));
21+
assert_eq!(Step::steps_between(&-20_i128, &80_i128), (100_usize, Some(100_usize)));
1622
if cfg!(target_pointer_width = "64") {
17-
assert_eq!(Step::steps_between(&10_u128, &0x1_0000_0000_0000_0009_u128), Some(usize::MAX));
23+
assert_eq!(
24+
Step::steps_between(&10_u128, &0x1_0000_0000_0000_0009_u128),
25+
(usize::MAX, Some(usize::MAX))
26+
);
1827
}
19-
assert_eq!(Step::steps_between(&10_u128, &0x1_0000_0000_0000_000a_u128), None);
20-
assert_eq!(Step::steps_between(&10_i128, &0x1_0000_0000_0000_000a_i128), None);
28+
assert_eq!(Step::steps_between(&10_u128, &0x1_0000_0000_0000_000a_u128), (usize::MAX, None));
29+
assert_eq!(Step::steps_between(&10_i128, &0x1_0000_0000_0000_000a_i128), (usize::MAX, None));
2130
assert_eq!(
2231
Step::steps_between(&-0x1_0000_0000_0000_0000_i128, &0x1_0000_0000_0000_0000_i128,),
23-
None,
32+
(usize::MAX, None),
2433
);
34+
35+
assert_eq!(Step::steps_between(&100_u32, &10_u32), (0, None));
2536
}
2637

2738
#[test]

0 commit comments

Comments
 (0)
Please sign in to comment.