Specialize implementations

Implementations in stdlib are now optimized as they were before.
This commit is contained in:
Jacob Pratt 2021-04-02 00:58:45 -04:00
parent a875876027
commit bc2f0fb5a9
No known key found for this signature in database
GPG Key ID: B80E19E4662B5AA4
17 changed files with 403 additions and 109 deletions

View File

@ -17,6 +17,8 @@
#![feature(iter_zip)] #![feature(iter_zip)]
#![feature(label_break_value)] #![feature(label_break_value)]
#![feature(nll)] #![feature(nll)]
#![feature(min_specialization)]
#![feature(trusted_step)]
#![recursion_limit = "256"] #![recursion_limit = "256"]
#[macro_use] #[macro_use]

View File

@ -7,6 +7,8 @@
#![cfg_attr(bootstrap, feature(extended_key_value_attributes))] #![cfg_attr(bootstrap, feature(extended_key_value_attributes))]
#![feature(in_band_lifetimes)] #![feature(in_band_lifetimes)]
#![feature(once_cell)] #![feature(once_cell)]
#![feature(min_specialization)]
#![feature(trusted_step)]
#![recursion_limit = "256"] #![recursion_limit = "256"]
#[macro_use] #[macro_use]

View File

@ -6,6 +6,7 @@
#![feature(unboxed_closures)] #![feature(unboxed_closures)]
#![feature(test)] #![feature(test)]
#![feature(fn_traits)] #![feature(fn_traits)]
#![feature(trusted_step)]
pub mod bit_set; pub mod bit_set;
pub mod vec; pub mod vec;

View File

@ -204,6 +204,9 @@ fn backward_checked(start: Self, u: usize) -> Option<Self> {
} }
} }
// Safety: The implementation of `Step` upholds all invariants.
unsafe impl ::std::iter::TrustedStep for $type {}
impl From<$type> for u32 { impl From<$type> for u32 {
#[inline] #[inline]
fn from(v: $type) -> u32 { fn from(v: $type) -> u32 {

View File

@ -22,6 +22,8 @@
#![feature(never_type)] #![feature(never_type)]
#![feature(in_band_lifetimes)] #![feature(in_band_lifetimes)]
#![feature(control_flow_enum)] #![feature(control_flow_enum)]
#![feature(min_specialization)]
#![feature(trusted_step)]
#![recursion_limit = "512"] // For rustdoc #![recursion_limit = "512"] // For rustdoc
#[macro_use] #[macro_use]

View File

@ -50,6 +50,7 @@
#![feature(associated_type_defaults)] #![feature(associated_type_defaults)]
#![feature(iter_zip)] #![feature(iter_zip)]
#![feature(thread_local_const_init)] #![feature(thread_local_const_init)]
#![feature(trusted_step)]
#![recursion_limit = "512"] #![recursion_limit = "512"]
#[macro_use] #[macro_use]

View File

@ -31,6 +31,7 @@
#![feature(option_get_or_insert_default)] #![feature(option_get_or_insert_default)]
#![feature(once_cell)] #![feature(once_cell)]
#![feature(control_flow_enum)] #![feature(control_flow_enum)]
#![feature(trusted_step)]
#![recursion_limit = "256"] #![recursion_limit = "256"]
#[macro_use] #[macro_use]

View File

@ -10,6 +10,8 @@
#![feature(bool_to_option)] #![feature(bool_to_option)]
#![feature(iter_zip)] #![feature(iter_zip)]
#![feature(once_cell)] #![feature(once_cell)]
#![feature(min_specialization)]
#![feature(trusted_step)]
#![recursion_limit = "256"] #![recursion_limit = "256"]
#[macro_use] #[macro_use]

View File

@ -10,6 +10,8 @@
#![feature(in_band_lifetimes)] #![feature(in_band_lifetimes)]
#![feature(iter_zip)] #![feature(iter_zip)]
#![feature(nll)] #![feature(nll)]
#![feature(min_specialization)]
#![feature(trusted_step)]
#![recursion_limit = "256"] #![recursion_limit = "256"]
#[macro_use] #[macro_use]

View File

@ -6,6 +6,7 @@
#![feature(iter_zip)] #![feature(iter_zip)]
#![feature(min_specialization)] #![feature(min_specialization)]
#![feature(stmt_expr_attributes)] #![feature(stmt_expr_attributes)]
#![feature(trusted_step)]
#[macro_use] #[macro_use]
extern crate tracing; extern crate tracing;

View File

@ -21,6 +21,7 @@
#![feature(nll)] #![feature(nll)]
#![feature(min_specialization)] #![feature(min_specialization)]
#![feature(thread_local_const_init)] #![feature(thread_local_const_init)]
#![feature(trusted_step)]
#[macro_use] #[macro_use]
extern crate rustc_macros; extern crate rustc_macros;

View File

@ -14,6 +14,8 @@
#![feature(never_type)] #![feature(never_type)]
#![feature(associated_type_bounds)] #![feature(associated_type_bounds)]
#![feature(exhaustive_patterns)] #![feature(exhaustive_patterns)]
#![feature(min_specialization)]
#![feature(trusted_step)]
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};

View File

@ -1,3 +1,6 @@
#![feature(min_specialization)]
#![feature(trusted_step)]
#[macro_use] #[macro_use]
extern crate bitflags; extern crate bitflags;
#[macro_use] #[macro_use]

View File

@ -384,6 +384,8 @@
pub use self::traits::InPlaceIterable; pub use self::traits::InPlaceIterable;
#[unstable(feature = "trusted_len", issue = "37572")] #[unstable(feature = "trusted_len", issue = "37572")]
pub use self::traits::TrustedLen; pub use self::traits::TrustedLen;
#[unstable(feature = "trusted_step", issue = "85731")]
pub use self::traits::TrustedStep;
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub use self::traits::{ pub use self::traits::{
DoubleEndedIterator, ExactSizeIterator, Extend, FromIterator, IntoIterator, Product, Sum, DoubleEndedIterator, ExactSizeIterator, Extend, FromIterator, IntoIterator, Product, Sum,

View File

@ -3,7 +3,16 @@
use crate::mem; use crate::mem;
use crate::ops::{self, Try}; 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. /// Objects that have a notion of *successor* and *predecessor* operations.
/// ///
@ -505,12 +514,24 @@ impl ExactSizeIterator for ops::RangeInclusive<$t> { }
)*) )*)
} }
#[stable(feature = "rust1", since = "1.0.0")] /// Specialization implementations for `Range`.
impl<A: Step> Iterator for ops::Range<A> { 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; type Item = A;
#[inline] #[inline]
fn next(&mut self) -> Option<A> { default fn spec_next(&mut self) -> Option<A> {
if self.start < self.end { if self.start < self.end {
let n = let n =
Step::forward_checked(self.start.clone(), 1).expect("`Step` invariants not upheld"); Step::forward_checked(self.start.clone(), 1).expect("`Step` invariants not upheld");
@ -520,6 +541,107 @@ fn next(&mut self) -> Option<A> {
} }
} }
#[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) };
Some(mem::replace(&mut self.start, n))
} else {
None
}
}
#[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] #[inline]
fn size_hint(&self) -> (usize, Option<usize>) { fn size_hint(&self) -> (usize, Option<usize>) {
if self.start < self.end { if self.start < self.end {
@ -532,16 +654,7 @@ fn size_hint(&self) -> (usize, Option<usize>) {
#[inline] #[inline]
fn nth(&mut self, n: usize) -> Option<A> { fn nth(&mut self, n: usize) -> Option<A> {
if let Some(plus_n) = Step::forward_checked(self.start.clone(), n) { self.spec_nth(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] #[inline]
@ -624,37 +737,36 @@ unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item
impl<A: Step> DoubleEndedIterator for ops::Range<A> { impl<A: Step> DoubleEndedIterator for ops::Range<A> {
#[inline] #[inline]
fn next_back(&mut self) -> Option<A> { fn next_back(&mut self) -> Option<A> {
if self.start < self.end { self.spec_next_back()
self.end =
Step::backward_checked(self.end.clone(), 1).expect("`Step` invariants not upheld");
Some(self.end.clone())
} else {
None
}
} }
#[inline] #[inline]
fn nth_back(&mut self, n: usize) -> Option<A> { fn nth_back(&mut self, n: usize) -> Option<A> {
if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) { self.spec_nth_back(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
} }
} }
macro_rules! impl_trusted_len_for_range { // Safety:
($($type:ty)*) => {$( // The following invariants for `Step::steps_between` exist:
#[unstable(feature = "trusted_len", issue = "37572")] //
unsafe impl TrustedLen for ops::Range<$type> {} // > * `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
impl_trusted_len_for_range![char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize]; // > 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: TrustedStep> TrustedLen for ops::Range<A> {}
#[stable(feature = "fused", since = "1.26.0")] #[stable(feature = "fused", since = "1.26.0")]
impl<A: Step> FusedIterator for ops::Range<A> {} impl<A: Step> FusedIterator for ops::Range<A> {}
@ -682,23 +794,38 @@ fn nth(&mut self, n: usize) -> Option<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")] #[stable(feature = "fused", since = "1.26.0")]
impl<A: Step> FusedIterator for ops::RangeFrom<A> {} impl<A: Step> FusedIterator for ops::RangeFrom<A> {}
macro_rules! impl_trusted_len_for_range_from { trait RangeInclusiveIteratorImpl {
($($type:ty)*) => {$( type Item;
#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl TrustedLen for ops::RangeFrom<$type> {}
)*}
}
impl_trusted_len_for_range_from![char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize];
#[stable(feature = "inclusive_range", since = "1.26.0")] // Iterator
impl<A: Step> Iterator for ops::RangeInclusive<A> { 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; type Item = A;
#[inline] #[inline]
fn next(&mut self) -> Option<A> { default fn spec_next(&mut self) -> Option<A> {
if self.is_empty() { if self.is_empty() {
return None; return None;
} }
@ -713,6 +840,182 @@ fn next(&mut self) -> Option<A> {
}) })
} }
#[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;
}
let is_iterating = self.start < self.end;
Some(if is_iterating {
// SAFETY: just checked precondition
let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) };
mem::replace(&mut self.start, n)
} else {
self.exhausted = true;
self.start.clone()
})
}
#[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] #[inline]
fn size_hint(&self) -> (usize, Option<usize>) { fn size_hint(&self) -> (usize, Option<usize>) {
if self.is_empty() { if self.is_empty() {
@ -754,32 +1057,13 @@ fn nth(&mut self, n: usize) -> Option<A> {
} }
#[inline] #[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 where
Self: Sized, Self: Sized,
F: FnMut(B, Self::Item) -> R, F: FnMut(B, Self::Item) -> R,
R: Try<Output = B>, R: Try<Output = B>,
{ {
if self.is_empty() { self.spec_try_fold(init, f)
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] #[inline]
@ -816,18 +1100,7 @@ fn max(mut self) -> Option<A> {
impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> { impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
#[inline] #[inline]
fn next_back(&mut self) -> Option<A> { fn next_back(&mut self) -> Option<A> {
if self.is_empty() { self.spec_next_back()
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] #[inline]
@ -859,32 +1132,13 @@ fn nth_back(&mut self, n: usize) -> Option<A> {
} }
#[inline] #[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 where
Self: Sized, Self: Sized,
F: FnMut(B, Self::Item) -> R, F: FnMut(B, Self::Item) -> R,
R: Try<Output = B>, R: Try<Output = B>,
{ {
if self.is_empty() { self.spec_try_rfold(init, f)
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 }
} }
#[inline] #[inline]
@ -902,13 +1156,9 @@ fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
} }
} }
macro_rules! impl_trusted_len_for_range_inclusive { // Safety: See above implementation for `ops::Range<A>`
($($type:ty)*) => {$( #[unstable(feature = "trusted_len", issue = "37572")]
#[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<A: TrustedStep> TrustedLen for ops::RangeInclusive<A> {}
unsafe impl TrustedLen for ops::RangeInclusive<$type> {}
)*}
}
impl_trusted_len_for_range_inclusive![char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize];
#[stable(feature = "fused", since = "1.26.0")] #[stable(feature = "fused", since = "1.26.0")]
impl<A: Step> FusedIterator for ops::RangeInclusive<A> {} impl<A: Step> FusedIterator for ops::RangeInclusive<A> {}

View File

@ -1,3 +1,5 @@
use crate::iter::Step;
/// An iterator that always continues to yield `None` when exhausted. /// An iterator that always continues to yield `None` when exhausted.
/// ///
/// Calling next on a fused iterator that has returned `None` once is guaranteed /// 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")] #[unstable(issue = "none", feature = "inplace_iteration")]
#[doc(hidden)] #[doc(hidden)]
pub unsafe trait InPlaceIterable: Iterator {} 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 {}

View File

@ -13,5 +13,7 @@
pub use self::iterator::Iterator; pub use self::iterator::Iterator;
#[unstable(issue = "none", feature = "inplace_iteration")] #[unstable(issue = "none", feature = "inplace_iteration")]
pub use self::marker::InPlaceIterable; pub use self::marker::InPlaceIterable;
#[unstable(feature = "trusted_step", issue = "85731")]
pub use self::marker::TrustedStep;
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub use self::marker::{FusedIterator, TrustedLen}; pub use self::marker::{FusedIterator, TrustedLen};