mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Auto merge of #83772 - jhpratt:revamp-step-trait, r=Mark-Simulacrum
Make `Step` trait safe to implement This PR makes a few modifications to the `Step` trait that I believe better position it for stabilization in the short term. In particular, 1. `unsafe trait TrustedStep` is introduced, indicating that the implementation of `Step` for a given type upholds all stated invariants (which have remained unchanged). This is gated behind a new `trusted_step` feature, as stabilization is realistically blocked on min_specialization. 2. The `Step` trait is internally specialized on the `TrustedStep` trait, which avoids a serious performance regression. 3. `TrustedLen` is implemented for `T: TrustedStep` as the latter's invariants subsume the former's. 4. The `Step` trait is no longer `unsafe`, as the invariants must not be relied upon by unsafe code (unless the type implements `TrustedStep`). 5. `TrustedStep` is implemented for all types that implement `Step` in the standard library and compiler. 6. The `step_trait_ext` feature is merged into the `step_trait` feature. I was unable to find any reasoning for the features being split; the `_unchecked` methods need not necessarily be stabilized at the same time, but I think it is useful to have them under the same feature flag. All existing implementations of `Step` will be broken, as it is not possible to `unsafe impl` a safe trait. Given this trait only exists on nightly, I feel this breakage is acceptable. The blanket `impl<T: Step> TrustedLen for T` will likely cause some minor breakage, but this should be covered by the equivalent impl for `TrustedStep`. Hopefully these changes are sufficient to place `Step` in decent position for stabilization, which would allow user-defined types to be used with `a..b` syntax.
This commit is contained in:
commit
9a72afa7dd
@ -17,6 +17,8 @@
|
||||
#![feature(iter_zip)]
|
||||
#![feature(label_break_value)]
|
||||
#![feature(nll)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(trusted_step)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
#[macro_use]
|
||||
|
@ -7,6 +7,8 @@
|
||||
#![cfg_attr(bootstrap, feature(extended_key_value_attributes))]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(once_cell)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(trusted_step)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
#[macro_use]
|
||||
|
@ -6,6 +6,7 @@
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(test)]
|
||||
#![feature(fn_traits)]
|
||||
#![feature(trusted_step)]
|
||||
|
||||
pub mod bit_set;
|
||||
pub mod vec;
|
||||
|
@ -65,7 +65,7 @@ impl Idx for u32 {
|
||||
/// `u32::MAX`. You can also customize things like the `Debug` impl,
|
||||
/// what traits are derived, and so forth via the macro.
|
||||
#[macro_export]
|
||||
#[allow_internal_unstable(step_trait, step_trait_ext, rustc_attrs)]
|
||||
#[allow_internal_unstable(step_trait, rustc_attrs)]
|
||||
macro_rules! newtype_index {
|
||||
// ---- public rules ----
|
||||
|
||||
@ -184,7 +184,7 @@ macro_rules! newtype_index {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl ::std::iter::Step for $type {
|
||||
impl ::std::iter::Step for $type {
|
||||
#[inline]
|
||||
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
|
||||
<usize as ::std::iter::Step>::steps_between(
|
||||
@ -204,6 +204,9 @@ macro_rules! newtype_index {
|
||||
}
|
||||
}
|
||||
|
||||
// Safety: The implementation of `Step` upholds all invariants.
|
||||
unsafe impl ::std::iter::TrustedStep for $type {}
|
||||
|
||||
impl From<$type> for u32 {
|
||||
#[inline]
|
||||
fn from(v: $type) -> u32 {
|
||||
|
@ -22,6 +22,8 @@
|
||||
#![feature(never_type)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(trusted_step)]
|
||||
#![recursion_limit = "512"] // For rustdoc
|
||||
|
||||
#[macro_use]
|
||||
|
@ -50,6 +50,7 @@
|
||||
#![feature(associated_type_defaults)]
|
||||
#![feature(iter_zip)]
|
||||
#![feature(thread_local_const_init)]
|
||||
#![feature(trusted_step)]
|
||||
#![recursion_limit = "512"]
|
||||
|
||||
#[macro_use]
|
||||
|
@ -31,6 +31,7 @@ Rust MIR: a lowered representation of Rust.
|
||||
#![feature(option_get_or_insert_default)]
|
||||
#![feature(once_cell)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(trusted_step)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
#[macro_use]
|
||||
|
@ -10,6 +10,8 @@
|
||||
#![feature(bool_to_option)]
|
||||
#![feature(iter_zip)]
|
||||
#![feature(once_cell)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(trusted_step)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
#[macro_use]
|
||||
|
@ -10,6 +10,8 @@
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(iter_zip)]
|
||||
#![feature(nll)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(trusted_step)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
#[macro_use]
|
||||
|
@ -6,6 +6,7 @@
|
||||
#![feature(iter_zip)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![feature(trusted_step)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate tracing;
|
||||
|
@ -21,6 +21,7 @@
|
||||
#![feature(nll)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(thread_local_const_init)]
|
||||
#![feature(trusted_step)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate rustc_macros;
|
||||
|
@ -14,6 +14,8 @@
|
||||
#![feature(never_type)]
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(exhaustive_patterns)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(trusted_step)]
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
|
@ -1,3 +1,6 @@
|
||||
#![feature(min_specialization)]
|
||||
#![feature(trusted_step)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
#[macro_use]
|
||||
|
@ -384,6 +384,8 @@ pub use self::traits::FusedIterator;
|
||||
pub use self::traits::InPlaceIterable;
|
||||
#[unstable(feature = "trusted_len", issue = "37572")]
|
||||
pub use self::traits::TrustedLen;
|
||||
#[unstable(feature = "trusted_step", issue = "85731")]
|
||||
pub use self::traits::TrustedStep;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use self::traits::{
|
||||
DoubleEndedIterator, ExactSizeIterator, Extend, FromIterator, IntoIterator, Product, Sum,
|
||||
|
@ -3,21 +3,23 @@ use crate::convert::TryFrom;
|
||||
use crate::mem;
|
||||
use crate::ops::{self, Try};
|
||||
|
||||
use super::{FusedIterator, TrustedLen, TrustedRandomAccess};
|
||||
use super::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedStep};
|
||||
|
||||
// Safety: All invariants are upheld.
|
||||
macro_rules! unsafe_impl_trusted_step {
|
||||
($($type:ty)*) => {$(
|
||||
#[unstable(feature = "trusted_step", issue = "85731")]
|
||||
unsafe impl TrustedStep for $type {}
|
||||
)*};
|
||||
}
|
||||
unsafe_impl_trusted_step![char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize];
|
||||
|
||||
/// Objects that have a notion of *successor* and *predecessor* operations.
|
||||
///
|
||||
/// The *successor* operation moves towards values that compare greater.
|
||||
/// The *predecessor* operation moves towards values that compare lesser.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This trait is `unsafe` because its implementation must be correct for
|
||||
/// the safety of `unsafe trait TrustedLen` implementations, and the results
|
||||
/// of using this trait can otherwise be trusted by `unsafe` code to be correct
|
||||
/// and fulfill the listed obligations.
|
||||
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
|
||||
pub unsafe trait Step: Clone + PartialOrd + Sized {
|
||||
pub trait Step: Clone + PartialOrd + Sized {
|
||||
/// Returns the number of *successor* steps required to get from `start` to `end`.
|
||||
///
|
||||
/// Returns `None` if the number of steps would overflow `usize`
|
||||
@ -55,7 +57,6 @@ pub unsafe trait Step: Clone + PartialOrd + Sized {
|
||||
///
|
||||
/// * `Step::forward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::forward_checked(&x, 1))`
|
||||
/// * Corollary: `Step::forward_checked(&a, 0) == Some(a)`
|
||||
#[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
|
||||
fn forward_checked(start: Self, count: usize) -> Option<Self>;
|
||||
|
||||
/// Returns the value that would be obtained by taking the *successor*
|
||||
@ -81,7 +82,6 @@ pub unsafe trait Step: Clone + PartialOrd + Sized {
|
||||
/// * Corollary: `Step::forward(a, 0) == a`
|
||||
/// * `Step::forward(a, n) >= a`
|
||||
/// * `Step::backward(Step::forward(a, n), n) == a`
|
||||
#[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
|
||||
fn forward(start: Self, count: usize) -> Self {
|
||||
Step::forward_checked(start, count).expect("overflow in `Step::forward`")
|
||||
}
|
||||
@ -106,7 +106,6 @@ pub unsafe trait Step: Clone + PartialOrd + Sized {
|
||||
/// For any `a` and `n`, where no overflow occurs:
|
||||
///
|
||||
/// * `Step::forward_unchecked(a, n)` is equivalent to `Step::forward(a, n)`
|
||||
#[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
|
||||
unsafe fn forward_unchecked(start: Self, count: usize) -> Self {
|
||||
Step::forward(start, count)
|
||||
}
|
||||
@ -127,7 +126,6 @@ pub unsafe trait Step: Clone + PartialOrd + Sized {
|
||||
///
|
||||
/// * `Step::backward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::backward_checked(&x, 1))`
|
||||
/// * Corollary: `Step::backward_checked(&a, 0) == Some(a)`
|
||||
#[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
|
||||
fn backward_checked(start: Self, count: usize) -> Option<Self>;
|
||||
|
||||
/// Returns the value that would be obtained by taking the *predecessor*
|
||||
@ -153,7 +151,6 @@ pub unsafe trait Step: Clone + PartialOrd + Sized {
|
||||
/// * Corollary: `Step::backward(a, 0) == a`
|
||||
/// * `Step::backward(a, n) <= a`
|
||||
/// * `Step::forward(Step::backward(a, n), n) == a`
|
||||
#[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
|
||||
fn backward(start: Self, count: usize) -> Self {
|
||||
Step::backward_checked(start, count).expect("overflow in `Step::backward`")
|
||||
}
|
||||
@ -178,7 +175,6 @@ pub unsafe trait Step: Clone + PartialOrd + Sized {
|
||||
/// For any `a` and `n`, where no overflow occurs:
|
||||
///
|
||||
/// * `Step::backward_unchecked(a, n)` is equivalent to `Step::backward(a, n)`
|
||||
#[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
|
||||
unsafe fn backward_unchecked(start: Self, count: usize) -> Self {
|
||||
Step::backward(start, count)
|
||||
}
|
||||
@ -237,7 +233,7 @@ macro_rules! step_integer_impls {
|
||||
$(
|
||||
#[allow(unreachable_patterns)]
|
||||
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
|
||||
unsafe impl Step for $u_narrower {
|
||||
impl Step for $u_narrower {
|
||||
step_identical_methods!();
|
||||
|
||||
#[inline]
|
||||
@ -269,7 +265,7 @@ macro_rules! step_integer_impls {
|
||||
|
||||
#[allow(unreachable_patterns)]
|
||||
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
|
||||
unsafe impl Step for $i_narrower {
|
||||
impl Step for $i_narrower {
|
||||
step_identical_methods!();
|
||||
|
||||
#[inline]
|
||||
@ -333,7 +329,7 @@ macro_rules! step_integer_impls {
|
||||
$(
|
||||
#[allow(unreachable_patterns)]
|
||||
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
|
||||
unsafe impl Step for $u_wider {
|
||||
impl Step for $u_wider {
|
||||
step_identical_methods!();
|
||||
|
||||
#[inline]
|
||||
@ -358,7 +354,7 @@ macro_rules! step_integer_impls {
|
||||
|
||||
#[allow(unreachable_patterns)]
|
||||
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
|
||||
unsafe impl Step for $i_wider {
|
||||
impl Step for $i_wider {
|
||||
step_identical_methods!();
|
||||
|
||||
#[inline]
|
||||
@ -408,7 +404,7 @@ step_integer_impls! {
|
||||
}
|
||||
|
||||
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
|
||||
unsafe impl Step for char {
|
||||
impl Step for char {
|
||||
#[inline]
|
||||
fn steps_between(&start: &char, &end: &char) -> Option<usize> {
|
||||
let start = start as u32;
|
||||
@ -512,12 +508,76 @@ macro_rules! range_incl_exact_iter_impl {
|
||||
)*)
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<A: Step> Iterator for ops::Range<A> {
|
||||
/// Specialization implementations for `Range`.
|
||||
trait RangeIteratorImpl {
|
||||
type Item;
|
||||
|
||||
// Iterator
|
||||
fn spec_next(&mut self) -> Option<Self::Item>;
|
||||
fn spec_nth(&mut self, n: usize) -> Option<Self::Item>;
|
||||
|
||||
// DoubleEndedIterator
|
||||
fn spec_next_back(&mut self) -> Option<Self::Item>;
|
||||
fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item>;
|
||||
}
|
||||
|
||||
impl<A: Step> RangeIteratorImpl for ops::Range<A> {
|
||||
type Item = A;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> {
|
||||
default fn spec_next(&mut self) -> Option<A> {
|
||||
if self.start < self.end {
|
||||
let n =
|
||||
Step::forward_checked(self.start.clone(), 1).expect("`Step` invariants not upheld");
|
||||
Some(mem::replace(&mut self.start, n))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
default fn spec_nth(&mut self, n: usize) -> Option<A> {
|
||||
if let Some(plus_n) = Step::forward_checked(self.start.clone(), n) {
|
||||
if plus_n < self.end {
|
||||
self.start =
|
||||
Step::forward_checked(plus_n.clone(), 1).expect("`Step` invariants not upheld");
|
||||
return Some(plus_n);
|
||||
}
|
||||
}
|
||||
|
||||
self.start = self.end.clone();
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
default fn spec_next_back(&mut self) -> Option<A> {
|
||||
if self.start < self.end {
|
||||
self.end =
|
||||
Step::backward_checked(self.end.clone(), 1).expect("`Step` invariants not upheld");
|
||||
Some(self.end.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
default fn spec_nth_back(&mut self, n: usize) -> Option<A> {
|
||||
if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) {
|
||||
if minus_n > self.start {
|
||||
self.end =
|
||||
Step::backward_checked(minus_n, 1).expect("`Step` invariants not upheld");
|
||||
return Some(self.end.clone());
|
||||
}
|
||||
}
|
||||
|
||||
self.end = self.start.clone();
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> {
|
||||
#[inline]
|
||||
fn spec_next(&mut self) -> Option<T> {
|
||||
if self.start < self.end {
|
||||
// SAFETY: just checked precondition
|
||||
let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) };
|
||||
@ -527,6 +587,55 @@ impl<A: Step> Iterator for ops::Range<A> {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn spec_nth(&mut self, n: usize) -> Option<T> {
|
||||
if let Some(plus_n) = Step::forward_checked(self.start.clone(), n) {
|
||||
if plus_n < self.end {
|
||||
// SAFETY: just checked precondition
|
||||
self.start = unsafe { Step::forward_unchecked(plus_n.clone(), 1) };
|
||||
return Some(plus_n);
|
||||
}
|
||||
}
|
||||
|
||||
self.start = self.end.clone();
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn spec_next_back(&mut self) -> Option<T> {
|
||||
if self.start < self.end {
|
||||
// SAFETY: just checked precondition
|
||||
self.end = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
|
||||
Some(self.end.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn spec_nth_back(&mut self, n: usize) -> Option<T> {
|
||||
if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) {
|
||||
if minus_n > self.start {
|
||||
// SAFETY: just checked precondition
|
||||
self.end = unsafe { Step::backward_unchecked(minus_n, 1) };
|
||||
return Some(self.end.clone());
|
||||
}
|
||||
}
|
||||
|
||||
self.end = self.start.clone();
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<A: Step> Iterator for ops::Range<A> {
|
||||
type Item = A;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> {
|
||||
self.spec_next()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
if self.start < self.end {
|
||||
@ -539,16 +648,7 @@ impl<A: Step> Iterator for ops::Range<A> {
|
||||
|
||||
#[inline]
|
||||
fn nth(&mut self, n: usize) -> Option<A> {
|
||||
if let Some(plus_n) = Step::forward_checked(self.start.clone(), n) {
|
||||
if plus_n < self.end {
|
||||
// SAFETY: just checked precondition
|
||||
self.start = unsafe { Step::forward_unchecked(plus_n.clone(), 1) };
|
||||
return Some(plus_n);
|
||||
}
|
||||
}
|
||||
|
||||
self.start = self.end.clone();
|
||||
None
|
||||
self.spec_nth(n)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -631,32 +731,36 @@ range_incl_exact_iter_impl! {
|
||||
impl<A: Step> DoubleEndedIterator for ops::Range<A> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<A> {
|
||||
if self.start < self.end {
|
||||
// SAFETY: just checked precondition
|
||||
self.end = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
|
||||
Some(self.end.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
self.spec_next_back()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn nth_back(&mut self, n: usize) -> Option<A> {
|
||||
if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) {
|
||||
if minus_n > self.start {
|
||||
// SAFETY: just checked precondition
|
||||
self.end = unsafe { Step::backward_unchecked(minus_n, 1) };
|
||||
return Some(self.end.clone());
|
||||
}
|
||||
}
|
||||
|
||||
self.end = self.start.clone();
|
||||
None
|
||||
self.spec_nth_back(n)
|
||||
}
|
||||
}
|
||||
|
||||
// Safety:
|
||||
// The following invariants for `Step::steps_between` exist:
|
||||
//
|
||||
// > * `steps_between(&a, &b) == Some(n)` only if `a <= b`
|
||||
// > * Note that `a <= b` does _not_ imply `steps_between(&a, &b) != None`;
|
||||
// > this is the case when it would require more than `usize::MAX` steps to
|
||||
// > get to `b`
|
||||
// > * `steps_between(&a, &b) == None` if `a > b`
|
||||
//
|
||||
// The first invariant is what is generally required for `TrustedLen` to be
|
||||
// sound. The note addendum satisfies an additional `TrustedLen` invariant.
|
||||
//
|
||||
// > The upper bound must only be `None` if the actual iterator length is larger
|
||||
// > than `usize::MAX`
|
||||
//
|
||||
// The second invariant logically follows the first so long as the `PartialOrd`
|
||||
// implementation is correct; regardless it is explicitly stated. If `a < b`
|
||||
// then `(0, Some(0))` is returned by `ops::Range<A: Step>::size_hint`. As such
|
||||
// the second invariant is upheld.
|
||||
#[unstable(feature = "trusted_len", issue = "37572")]
|
||||
unsafe impl<A: Step> TrustedLen for ops::Range<A> {}
|
||||
unsafe impl<A: TrustedStep> TrustedLen for ops::Range<A> {}
|
||||
|
||||
#[stable(feature = "fused", since = "1.26.0")]
|
||||
impl<A: Step> FusedIterator for ops::Range<A> {}
|
||||
@ -684,18 +788,130 @@ impl<A: Step> Iterator for ops::RangeFrom<A> {
|
||||
}
|
||||
}
|
||||
|
||||
// Safety: See above implementation for `ops::Range<A>`
|
||||
#[unstable(feature = "trusted_len", issue = "37572")]
|
||||
unsafe impl<A: TrustedStep> TrustedLen for ops::RangeFrom<A> {}
|
||||
|
||||
#[stable(feature = "fused", since = "1.26.0")]
|
||||
impl<A: Step> FusedIterator for ops::RangeFrom<A> {}
|
||||
|
||||
#[unstable(feature = "trusted_len", issue = "37572")]
|
||||
unsafe impl<A: Step> TrustedLen for ops::RangeFrom<A> {}
|
||||
trait RangeInclusiveIteratorImpl {
|
||||
type Item;
|
||||
|
||||
#[stable(feature = "inclusive_range", since = "1.26.0")]
|
||||
impl<A: Step> Iterator for ops::RangeInclusive<A> {
|
||||
// Iterator
|
||||
fn spec_next(&mut self) -> Option<Self::Item>;
|
||||
fn spec_try_fold<B, F, R>(&mut self, init: B, f: F) -> R
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(B, Self::Item) -> R,
|
||||
R: Try<Output = B>;
|
||||
|
||||
// DoubleEndedIterator
|
||||
fn spec_next_back(&mut self) -> Option<Self::Item>;
|
||||
fn spec_try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(B, Self::Item) -> R,
|
||||
R: Try<Output = B>;
|
||||
}
|
||||
|
||||
impl<A: Step> RangeInclusiveIteratorImpl for ops::RangeInclusive<A> {
|
||||
type Item = A;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> {
|
||||
default fn spec_next(&mut self) -> Option<A> {
|
||||
if self.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let is_iterating = self.start < self.end;
|
||||
Some(if is_iterating {
|
||||
let n =
|
||||
Step::forward_checked(self.start.clone(), 1).expect("`Step` invariants not upheld");
|
||||
mem::replace(&mut self.start, n)
|
||||
} else {
|
||||
self.exhausted = true;
|
||||
self.start.clone()
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
default fn spec_try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(B, A) -> R,
|
||||
R: Try<Output = B>,
|
||||
{
|
||||
if self.is_empty() {
|
||||
return try { init };
|
||||
}
|
||||
|
||||
let mut accum = init;
|
||||
|
||||
while self.start < self.end {
|
||||
let n =
|
||||
Step::forward_checked(self.start.clone(), 1).expect("`Step` invariants not upheld");
|
||||
let n = mem::replace(&mut self.start, n);
|
||||
accum = f(accum, n)?;
|
||||
}
|
||||
|
||||
self.exhausted = true;
|
||||
|
||||
if self.start == self.end {
|
||||
accum = f(accum, self.start.clone())?;
|
||||
}
|
||||
|
||||
try { accum }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
default fn spec_next_back(&mut self) -> Option<A> {
|
||||
if self.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let is_iterating = self.start < self.end;
|
||||
Some(if is_iterating {
|
||||
let n =
|
||||
Step::backward_checked(self.end.clone(), 1).expect("`Step` invariants not upheld");
|
||||
mem::replace(&mut self.end, n)
|
||||
} else {
|
||||
self.exhausted = true;
|
||||
self.end.clone()
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
default fn spec_try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(B, A) -> R,
|
||||
R: Try<Output = B>,
|
||||
{
|
||||
if self.is_empty() {
|
||||
return try { init };
|
||||
}
|
||||
|
||||
let mut accum = init;
|
||||
|
||||
while self.start < self.end {
|
||||
let n =
|
||||
Step::backward_checked(self.end.clone(), 1).expect("`Step` invariants not upheld");
|
||||
let n = mem::replace(&mut self.end, n);
|
||||
accum = f(accum, n)?;
|
||||
}
|
||||
|
||||
self.exhausted = true;
|
||||
|
||||
if self.start == self.end {
|
||||
accum = f(accum, self.start.clone())?;
|
||||
}
|
||||
|
||||
try { accum }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TrustedStep> RangeInclusiveIteratorImpl for ops::RangeInclusive<T> {
|
||||
#[inline]
|
||||
fn spec_next(&mut self) -> Option<T> {
|
||||
if self.is_empty() {
|
||||
return None;
|
||||
}
|
||||
@ -710,6 +926,90 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn spec_try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(B, T) -> R,
|
||||
R: Try<Output = B>,
|
||||
{
|
||||
if self.is_empty() {
|
||||
return try { init };
|
||||
}
|
||||
|
||||
let mut accum = init;
|
||||
|
||||
while self.start < self.end {
|
||||
// SAFETY: just checked precondition
|
||||
let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) };
|
||||
let n = mem::replace(&mut self.start, n);
|
||||
accum = f(accum, n)?;
|
||||
}
|
||||
|
||||
self.exhausted = true;
|
||||
|
||||
if self.start == self.end {
|
||||
accum = f(accum, self.start.clone())?;
|
||||
}
|
||||
|
||||
try { accum }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn spec_next_back(&mut self) -> Option<T> {
|
||||
if self.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let is_iterating = self.start < self.end;
|
||||
Some(if is_iterating {
|
||||
// SAFETY: just checked precondition
|
||||
let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
|
||||
mem::replace(&mut self.end, n)
|
||||
} else {
|
||||
self.exhausted = true;
|
||||
self.end.clone()
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn spec_try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(B, T) -> R,
|
||||
R: Try<Output = B>,
|
||||
{
|
||||
if self.is_empty() {
|
||||
return try { init };
|
||||
}
|
||||
|
||||
let mut accum = init;
|
||||
|
||||
while self.start < self.end {
|
||||
// SAFETY: just checked precondition
|
||||
let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
|
||||
let n = mem::replace(&mut self.end, n);
|
||||
accum = f(accum, n)?;
|
||||
}
|
||||
|
||||
self.exhausted = true;
|
||||
|
||||
if self.start == self.end {
|
||||
accum = f(accum, self.start.clone())?;
|
||||
}
|
||||
|
||||
try { accum }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "inclusive_range", since = "1.26.0")]
|
||||
impl<A: Step> Iterator for ops::RangeInclusive<A> {
|
||||
type Item = A;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> {
|
||||
self.spec_next()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
if self.is_empty() {
|
||||
@ -751,32 +1051,13 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
|
||||
fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(B, Self::Item) -> R,
|
||||
R: Try<Output = B>,
|
||||
{
|
||||
if self.is_empty() {
|
||||
return try { init };
|
||||
}
|
||||
|
||||
let mut accum = init;
|
||||
|
||||
while self.start < self.end {
|
||||
// SAFETY: just checked precondition
|
||||
let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) };
|
||||
let n = mem::replace(&mut self.start, n);
|
||||
accum = f(accum, n)?;
|
||||
}
|
||||
|
||||
self.exhausted = true;
|
||||
|
||||
if self.start == self.end {
|
||||
accum = f(accum, self.start.clone())?;
|
||||
}
|
||||
|
||||
try { accum }
|
||||
self.spec_try_fold(init, f)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -813,18 +1094,7 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
|
||||
impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<A> {
|
||||
if self.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let is_iterating = self.start < self.end;
|
||||
Some(if is_iterating {
|
||||
// SAFETY: just checked precondition
|
||||
let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
|
||||
mem::replace(&mut self.end, n)
|
||||
} else {
|
||||
self.exhausted = true;
|
||||
self.end.clone()
|
||||
})
|
||||
self.spec_next_back()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -856,32 +1126,13 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
|
||||
fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(B, Self::Item) -> R,
|
||||
R: Try<Output = B>,
|
||||
{
|
||||
if self.is_empty() {
|
||||
return try { init };
|
||||
}
|
||||
|
||||
let mut accum = init;
|
||||
|
||||
while self.start < self.end {
|
||||
// SAFETY: just checked precondition
|
||||
let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
|
||||
let n = mem::replace(&mut self.end, n);
|
||||
accum = f(accum, n)?;
|
||||
}
|
||||
|
||||
self.exhausted = true;
|
||||
|
||||
if self.start == self.end {
|
||||
accum = f(accum, self.start.clone())?;
|
||||
}
|
||||
|
||||
try { accum }
|
||||
self.spec_try_rfold(init, f)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -899,8 +1150,9 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
|
||||
}
|
||||
}
|
||||
|
||||
// Safety: See above implementation for `ops::Range<A>`
|
||||
#[unstable(feature = "trusted_len", issue = "37572")]
|
||||
unsafe impl<A: Step> TrustedLen for ops::RangeInclusive<A> {}
|
||||
unsafe impl<A: TrustedStep> TrustedLen for ops::RangeInclusive<A> {}
|
||||
|
||||
#[stable(feature = "fused", since = "1.26.0")]
|
||||
impl<A: Step> FusedIterator for ops::RangeInclusive<A> {}
|
||||
|
@ -1,3 +1,5 @@
|
||||
use crate::iter::Step;
|
||||
|
||||
/// An iterator that always continues to yield `None` when exhausted.
|
||||
///
|
||||
/// Calling next on a fused iterator that has returned `None` once is guaranteed
|
||||
@ -55,3 +57,18 @@ unsafe impl<I: TrustedLen + ?Sized> TrustedLen for &mut I {}
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
#[doc(hidden)]
|
||||
pub unsafe trait InPlaceIterable: Iterator {}
|
||||
|
||||
/// A type that upholds all invariants of [`Step`].
|
||||
///
|
||||
/// The invariants of [`Step::steps_between()`] are a superset of the invariants
|
||||
/// of [`TrustedLen`]. As such, [`TrustedLen`] is implemented for all range
|
||||
/// types with the same generic type argument.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The implementation of [`Step`] for the given type must guarantee all
|
||||
/// invariants of all methods are upheld. See the [`Step`] trait's documentation
|
||||
/// for details. Consumers are free to rely on the invariants in unsafe code.
|
||||
#[unstable(feature = "trusted_step", issue = "85731")]
|
||||
#[rustc_specialization_trait]
|
||||
pub unsafe trait TrustedStep: Step {}
|
||||
|
@ -13,5 +13,7 @@ pub use self::exact_size::ExactSizeIterator;
|
||||
pub use self::iterator::Iterator;
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
pub use self::marker::InPlaceIterable;
|
||||
#[unstable(feature = "trusted_step", issue = "85731")]
|
||||
pub use self::marker::TrustedStep;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use self::marker::{FusedIterator, TrustedLen};
|
||||
|
@ -40,7 +40,6 @@
|
||||
#![feature(maybe_uninit_write_slice)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(step_trait)]
|
||||
#![feature(step_trait_ext)]
|
||||
#![feature(str_internals)]
|
||||
#![feature(test)]
|
||||
#![feature(trusted_len)]
|
||||
|
@ -32,6 +32,10 @@
|
||||
scope 5 {
|
||||
debug i => _15; // in scope 5 at $DIR/remove_storage_markers.rs:8:9: 8:10
|
||||
}
|
||||
scope 7 (inlined iter::range::<impl Iterator for std::ops::Range<i32>>::next) { // at $DIR/remove_storage_markers.rs:8:14: 8:19
|
||||
debug self => _9; // in scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
|
||||
let mut _18: &mut std::ops::Range<i32>; // in scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
|
||||
}
|
||||
}
|
||||
}
|
||||
scope 6 (inlined <std::ops::Range<i32> as IntoIterator>::into_iter) { // at $DIR/remove_storage_markers.rs:8:14: 8:19
|
||||
@ -61,19 +65,15 @@
|
||||
- StorageLive(_10); // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
|
||||
_10 = &mut _4; // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
|
||||
_9 = &mut (*_10); // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
|
||||
_8 = <std::ops::Range<i32> as Iterator>::next(move _9) -> bb2; // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
|
||||
- StorageLive(_18); // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
|
||||
_18 = &mut (*_9); // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
|
||||
_8 = <std::ops::Range<i32> as iter::range::RangeIteratorImpl>::spec_next(move _18) -> bb4; // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
|
||||
// mir::Constant
|
||||
// + span: $DIR/remove_storage_markers.rs:8:14: 8:19
|
||||
// + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> std::option::Option<<std::ops::Range<i32> as std::iter::Iterator>::Item> {<std::ops::Range<i32> as std::iter::Iterator>::next}, val: Value(Scalar(<ZST>)) }
|
||||
// + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> std::option::Option<<std::ops::Range<i32> as std::iter::range::RangeIteratorImpl>::Item> {<std::ops::Range<i32> as std::iter::range::RangeIteratorImpl>::spec_next}, val: Value(Scalar(<ZST>)) }
|
||||
}
|
||||
|
||||
bb2: {
|
||||
- StorageDead(_9); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
|
||||
_11 = discriminant(_8); // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
|
||||
switchInt(move _11) -> [0_isize: bb3, otherwise: bb4]; // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
|
||||
}
|
||||
|
||||
bb3: {
|
||||
_0 = const (); // scope 3 at $DIR/remove_storage_markers.rs:8:5: 10:6
|
||||
- StorageDead(_10); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
|
||||
- StorageDead(_8); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
|
||||
@ -85,7 +85,7 @@
|
||||
return; // scope 0 at $DIR/remove_storage_markers.rs:11:2: 11:2
|
||||
}
|
||||
|
||||
bb4: {
|
||||
bb3: {
|
||||
- StorageLive(_12); // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
|
||||
_12 = ((_8 as Some).0: i32); // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
|
||||
- StorageLive(_13); // scope 4 at $DIR/remove_storage_markers.rs:8:9: 8:10
|
||||
@ -111,5 +111,12 @@
|
||||
- StorageDead(_6); // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6
|
||||
goto -> bb1; // scope 2 at $DIR/remove_storage_markers.rs:8:5: 10:6
|
||||
}
|
||||
|
||||
bb4: {
|
||||
- StorageDead(_18); // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
|
||||
- StorageDead(_9); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
|
||||
_11 = discriminant(_8); // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
|
||||
switchInt(move _11) -> [0_isize: bb2, otherwise: bb3]; // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
#![feature(fn_traits,
|
||||
step_trait,
|
||||
step_trait_ext,
|
||||
unboxed_closures,
|
||||
)]
|
||||
|
||||
@ -157,7 +156,7 @@ impl<'a, 'b> std::ops::Add<&'b NaiveDate> for &'a NaiveDate {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl std::iter::Step for NaiveDate {
|
||||
impl std::iter::Step for NaiveDate {
|
||||
fn steps_between(_: &Self, _: &Self) -> Option<usize> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user