diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index f8a975cc8d4..6bbf776fb8f 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -34,6 +34,13 @@ pub trait Step: Clone + PartialOrd + Sized { /// Adds a `usize`, returning `None` on overflow. fn add_usize(&self, n: usize) -> Option; + + /// Subtracts a `usize`, returning `None` on underflow. + fn sub_usize(&self, n: usize) -> Option { + // this default implementation makes the addition of `sub_usize` a non-breaking change + let _ = n; + unimplemented!() + } } // These are still macro-generated because the integer literals resolve to different types. @@ -85,6 +92,15 @@ macro_rules! step_impl_unsigned { } } + #[inline] + #[allow(unreachable_patterns)] + fn sub_usize(&self, n: usize) -> Option { + match <$t>::try_from(n) { + Ok(n_as_t) => self.checked_sub(n_as_t), + Err(_) => None, + } + } + step_identical_methods!(); } )*) @@ -125,6 +141,25 @@ macro_rules! step_impl_signed { } } + #[inline] + #[allow(unreachable_patterns)] + fn sub_usize(&self, n: usize) -> Option { + match <$unsigned>::try_from(n) { + Ok(n_as_unsigned) => { + // Wrapping in unsigned space handles cases like + // `80_i8.sub_usize(200) == Some(-120_i8)`, + // even though 200_usize is out of range for i8. + let wrapped = (*self as $unsigned).wrapping_sub(n_as_unsigned) as $t; + if wrapped <= *self { + Some(wrapped) + } else { + None // Subtraction underflowed + } + } + Err(_) => None, + } + } + step_identical_methods!(); } )*) diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index 359b89f683d..c7f6e54c3d5 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -212,6 +212,11 @@ macro_rules! newtype_index { fn add_usize(&self, u: usize) -> Option { Idx::index(*self).checked_add(u).map(Self::new) } + + #[inline] + fn sub_usize(&self, u: usize) -> Option { + Idx::index(*self).checked_sub(u).map(Self::new) + } } impl From<$type> for u32 { diff --git a/src/test/run-pass/impl-trait/example-calendar.rs b/src/test/run-pass/impl-trait/example-calendar.rs index 968e9b7d34a..f1b1656745e 100644 --- a/src/test/run-pass/impl-trait/example-calendar.rs +++ b/src/test/run-pass/impl-trait/example-calendar.rs @@ -180,6 +180,10 @@ impl std::iter::Step for NaiveDate { fn add_usize(&self, _: usize) -> Option { unimplemented!() } + + fn sub_usize(&self, _: usize) -> Option { + unimplemented!() + } } #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]