@@ -22,7 +22,7 @@ unsafe_impl_trusted_step![AsciiChar char i8 i16 i32 i64 i128 isize u8 u16 u32 u6
2222///
2323/// The *successor* operation moves towards values that compare greater.
2424/// The *predecessor* operation moves towards values that compare lesser.
25- #[ unstable( feature = "step_trait" , reason = "recently redesigned" , issue = "42168" ) ]
25+ #[ unstable( feature = "step_trait" , issue = "42168" ) ]
2626pub trait Step : Clone + PartialOrd + Sized {
2727 /// Returns the number of *successor* steps required to get from `start` to `end`.
2828 ///
@@ -52,15 +52,12 @@ pub trait Step: Clone + PartialOrd + Sized {
5252 /// For any `a`, `n`, and `m`:
5353 ///
5454 /// * `Step::forward_checked(a, n).and_then(|x| Step::forward_checked(x, m)) == Step::forward_checked(a, m).and_then(|x| Step::forward_checked(x, n))`
55- ///
56- /// For any `a`, `n`, and `m` where `n + m` does not overflow:
57- ///
58- /// * `Step::forward_checked(a, n).and_then(|x| Step::forward_checked(x, m)) == Step::forward_checked(a, n + m)`
55+ /// * `Step::forward_checked(a, n).and_then(|x| Step::forward_checked(x, m)) == try { Step::forward_checked(a, n.checked_add(m)) }`
5956 ///
6057 /// For any `a` and `n`:
6158 ///
6259 /// * `Step::forward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::forward_checked(&x, 1))`
63- /// * Corollary: `Step::forward_checked(& a, 0) == Some(a)`
60+ /// * Corollary: `Step::forward_checked(a, 0) == Some(a)`
6461 fn forward_checked ( start : Self , count : usize ) -> Option < Self > ;
6562
6663 /// Returns the value that would be obtained by taking the *successor*
@@ -106,6 +103,7 @@ pub trait Step: Clone + PartialOrd + Sized {
106103 /// * if there exists `b` such that `b > a`, it is safe to call `Step::forward_unchecked(a, 1)`
107104 /// * if there exists `b`, `n` such that `steps_between(&a, &b) == Some(n)`,
108105 /// it is safe to call `Step::forward_unchecked(a, m)` for any `m <= n`.
106+ /// * Corollary: `Step::forward_unchecked(a, 0)` is always safe.
109107 ///
110108 /// For any `a` and `n`, where no overflow occurs:
111109 ///
@@ -128,8 +126,8 @@ pub trait Step: Clone + PartialOrd + Sized {
128126 ///
129127 /// For any `a` and `n`:
130128 ///
131- /// * `Step::backward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::backward_checked(& x, 1))`
132- /// * Corollary: `Step::backward_checked(& a, 0) == Some(a)`
129+ /// * `Step::backward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::backward_checked(x, 1))`
130+ /// * Corollary: `Step::backward_checked(a, 0) == Some(a)`
133131 fn backward_checked ( start : Self , count : usize ) -> Option < Self > ;
134132
135133 /// Returns the value that would be obtained by taking the *predecessor*
@@ -175,6 +173,7 @@ pub trait Step: Clone + PartialOrd + Sized {
175173 /// * if there exists `b` such that `b < a`, it is safe to call `Step::backward_unchecked(a, 1)`
176174 /// * if there exists `b`, `n` such that `steps_between(&b, &a) == Some(n)`,
177175 /// it is safe to call `Step::backward_unchecked(a, m)` for any `m <= n`.
176+ /// * Corollary: `Step::backward_unchecked(a, 0)` is always safe.
178177 ///
179178 /// For any `a` and `n`, where no overflow occurs:
180179 ///
@@ -184,8 +183,25 @@ pub trait Step: Clone + PartialOrd + Sized {
184183 }
185184}
186185
187- // These are still macro-generated because the integer literals resolve to different types.
188- macro_rules! step_identical_methods {
186+ // Separate impls for signed ranges because the distance within a signed range can be larger
187+ // than the signed::MAX value. Therefore `as` casting to the signed type would be incorrect.
188+ macro_rules! step_signed_methods {
189+ ( $unsigned: ty) => {
190+ #[ inline]
191+ unsafe fn forward_unchecked( start: Self , n: usize ) -> Self {
192+ // SAFETY: the caller has to guarantee that `start + n` doesn't overflow.
193+ unsafe { start. checked_add_unsigned( n as $unsigned) . unwrap_unchecked( ) }
194+ }
195+
196+ #[ inline]
197+ unsafe fn backward_unchecked( start: Self , n: usize ) -> Self {
198+ // SAFETY: the caller has to guarantee that `start - n` doesn't overflow.
199+ unsafe { start. checked_sub_unsigned( n as $unsigned) . unwrap_unchecked( ) }
200+ }
201+ } ;
202+ }
203+
204+ macro_rules! step_unsigned_methods {
189205 ( ) => {
190206 #[ inline]
191207 unsafe fn forward_unchecked( start: Self , n: usize ) -> Self {
@@ -198,7 +214,12 @@ macro_rules! step_identical_methods {
198214 // SAFETY: the caller has to guarantee that `start - n` doesn't overflow.
199215 unsafe { start. unchecked_sub( n as Self ) }
200216 }
217+ } ;
218+ }
201219
220+ // These are still macro-generated because the integer literals resolve to different types.
221+ macro_rules! step_identical_methods {
222+ ( ) => {
202223 #[ inline]
203224 #[ allow( arithmetic_overflow) ]
204225 #[ rustc_inherit_overflow_checks]
@@ -239,6 +260,7 @@ macro_rules! step_integer_impls {
239260 #[ unstable( feature = "step_trait" , reason = "recently redesigned" , issue = "42168" ) ]
240261 impl Step for $u_narrower {
241262 step_identical_methods!( ) ;
263+ step_unsigned_methods!( ) ;
242264
243265 #[ inline]
244266 fn steps_between( start: & Self , end: & Self ) -> Option <usize > {
@@ -271,6 +293,7 @@ macro_rules! step_integer_impls {
271293 #[ unstable( feature = "step_trait" , reason = "recently redesigned" , issue = "42168" ) ]
272294 impl Step for $i_narrower {
273295 step_identical_methods!( ) ;
296+ step_signed_methods!( $u_narrower) ;
274297
275298 #[ inline]
276299 fn steps_between( start: & Self , end: & Self ) -> Option <usize > {
@@ -335,6 +358,7 @@ macro_rules! step_integer_impls {
335358 #[ unstable( feature = "step_trait" , reason = "recently redesigned" , issue = "42168" ) ]
336359 impl Step for $u_wider {
337360 step_identical_methods!( ) ;
361+ step_unsigned_methods!( ) ;
338362
339363 #[ inline]
340364 fn steps_between( start: & Self , end: & Self ) -> Option <usize > {
@@ -360,6 +384,7 @@ macro_rules! step_integer_impls {
360384 #[ unstable( feature = "step_trait" , reason = "recently redesigned" , issue = "42168" ) ]
361385 impl Step for $i_wider {
362386 step_identical_methods!( ) ;
387+ step_signed_methods!( $u_wider) ;
363388
364389 #[ inline]
365390 fn steps_between( start: & Self , end: & Self ) -> Option <usize > {
0 commit comments