Expand in-place iteration specialization to Flatten, FlatMap and ArrayChunks

This commit is contained in:
The 8472 2023-04-15 12:59:16 +02:00
parent 2a1af898b2
commit 3ca6bb0b44
25 changed files with 391 additions and 63 deletions

View file

@ -145,7 +145,7 @@
use core::alloc::Allocator; use core::alloc::Allocator;
use core::fmt; use core::fmt;
use core::iter::{FusedIterator, InPlaceIterable, SourceIter, TrustedLen}; use core::iter::{FusedIterator, InPlaceIterable, SourceIter, TrustedFused, TrustedLen};
use core::mem::{self, swap, ManuallyDrop}; use core::mem::{self, swap, ManuallyDrop};
use core::num::NonZeroUsize; use core::num::NonZeroUsize;
use core::ops::{Deref, DerefMut}; use core::ops::{Deref, DerefMut};
@ -1540,6 +1540,10 @@ impl<T, A: Allocator> ExactSizeIterator for IntoIter<T, A> {
#[stable(feature = "fused", since = "1.26.0")] #[stable(feature = "fused", since = "1.26.0")]
impl<T, A: Allocator> FusedIterator for IntoIter<T, A> {} impl<T, A: Allocator> FusedIterator for IntoIter<T, A> {}
#[doc(hidden)]
#[unstable(issue = "none", feature = "trusted_fused")]
unsafe impl<T, A: Allocator> TrustedFused for IntoIter<T, A> {}
#[stable(feature = "default_iters", since = "1.70.0")] #[stable(feature = "default_iters", since = "1.70.0")]
impl<T> Default for IntoIter<T> { impl<T> Default for IntoIter<T> {
/// Creates an empty `binary_heap::IntoIter`. /// Creates an empty `binary_heap::IntoIter`.
@ -1569,7 +1573,10 @@ unsafe impl<T, A: Allocator> SourceIter for IntoIter<T, A> {
#[unstable(issue = "none", feature = "inplace_iteration")] #[unstable(issue = "none", feature = "inplace_iteration")]
#[doc(hidden)] #[doc(hidden)]
unsafe impl<I, A: Allocator> InPlaceIterable for IntoIter<I, A> {} unsafe impl<I, A: Allocator> InPlaceIterable for IntoIter<I, A> {
const EXPAND_BY: Option<NonZeroUsize> = NonZeroUsize::new(1);
const MERGE_BY: Option<NonZeroUsize> = NonZeroUsize::new(1);
}
unsafe impl<I> AsVecIntoIter for IntoIter<I> { unsafe impl<I> AsVecIntoIter for IntoIter<I> {
type Item = I; type Item = I;

View file

@ -155,6 +155,7 @@
#![feature(std_internals)] #![feature(std_internals)]
#![feature(str_internals)] #![feature(str_internals)]
#![feature(strict_provenance)] #![feature(strict_provenance)]
#![feature(trusted_fused)]
#![feature(trusted_len)] #![feature(trusted_len)]
#![feature(trusted_random_access)] #![feature(trusted_random_access)]
#![feature(try_trait_v2)] #![feature(try_trait_v2)]

View file

@ -137,44 +137,73 @@
//! } //! }
//! vec.truncate(write_idx); //! vec.truncate(write_idx);
//! ``` //! ```
use crate::alloc::{handle_alloc_error, Global};
use core::alloc::Allocator;
use core::alloc::Layout;
use core::iter::{InPlaceIterable, SourceIter, TrustedRandomAccessNoCoerce}; use core::iter::{InPlaceIterable, SourceIter, TrustedRandomAccessNoCoerce};
use core::mem::{self, ManuallyDrop, SizedTypeProperties}; use core::mem::{self, ManuallyDrop, SizedTypeProperties};
use core::ptr::{self}; use core::num::NonZeroUsize;
use core::ptr::{self, NonNull};
use super::{InPlaceDrop, InPlaceDstBufDrop, SpecFromIter, SpecFromIterNested, Vec}; use super::{InPlaceDrop, InPlaceDstBufDrop, SpecFromIter, SpecFromIterNested, Vec};
/// Specialization marker for collecting an iterator pipeline into a Vec while reusing the const fn in_place_collectible<DEST, SRC>(
/// source allocation, i.e. executing the pipeline in place. step_merge: Option<NonZeroUsize>,
#[rustc_unsafe_specialization_marker] step_expand: Option<NonZeroUsize>,
pub(super) trait InPlaceIterableMarker {} ) -> bool {
if DEST::IS_ZST || mem::align_of::<SRC>() != mem::align_of::<DEST>() {
return false;
}
impl<T> InPlaceIterableMarker for T where T: InPlaceIterable {} match (step_merge, step_expand) {
(Some(step_merge), Some(step_expand)) => {
// At least N merged source items -> at most M expanded destination items
// e.g.
// - 1 x [u8; 4] -> 4x u8, via flatten
// - 4 x u8 -> 1x [u8; 4], via array_chunks
mem::size_of::<SRC>() * step_merge.get() == mem::size_of::<DEST>() * step_expand.get()
}
// Fall back to other from_iter impls if an overflow occured in the step merge/expansion
// tracking.
_ => false,
}
}
/// This provides a shorthand for the source type since local type aliases aren't a thing.
#[rustc_specialization_trait]
trait InPlaceCollect: SourceIter<Source: AsVecIntoIter> + InPlaceIterable {
type Src;
}
impl<T> InPlaceCollect for T
where
T: SourceIter<Source: AsVecIntoIter> + InPlaceIterable,
{
type Src = <<T as SourceIter>::Source as AsVecIntoIter>::Item;
}
impl<T, I> SpecFromIter<T, I> for Vec<T> impl<T, I> SpecFromIter<T, I> for Vec<T>
where where
I: Iterator<Item = T> + SourceIter<Source: AsVecIntoIter> + InPlaceIterableMarker, I: Iterator<Item = T> + InPlaceCollect,
<I as SourceIter>::Source: AsVecIntoIter,
{ {
default fn from_iter(mut iterator: I) -> Self { default fn from_iter(mut iterator: I) -> Self {
// See "Layout constraints" section in the module documentation. We rely on const // See "Layout constraints" section in the module documentation. We rely on const
// optimization here since these conditions currently cannot be expressed as trait bounds // optimization here since these conditions currently cannot be expressed as trait bounds
if T::IS_ZST if const { !in_place_collectible::<T, I::Src>(I::MERGE_BY, I::EXPAND_BY) } {
|| mem::size_of::<T>()
!= mem::size_of::<<<I as SourceIter>::Source as AsVecIntoIter>::Item>()
|| mem::align_of::<T>()
!= mem::align_of::<<<I as SourceIter>::Source as AsVecIntoIter>::Item>()
{
// fallback to more generic implementations // fallback to more generic implementations
return SpecFromIterNested::from_iter(iterator); return SpecFromIterNested::from_iter(iterator);
} }
let (src_buf, src_ptr, dst_buf, dst_end, cap) = unsafe { let (src_buf, src_ptr, src_cap, mut dst_buf, dst_end, dst_cap) = unsafe {
let inner = iterator.as_inner().as_into_iter(); let inner = iterator.as_inner().as_into_iter();
( (
inner.buf.as_ptr(), inner.buf.as_ptr(),
inner.ptr, inner.ptr,
inner.cap,
inner.buf.as_ptr() as *mut T, inner.buf.as_ptr() as *mut T,
inner.end as *const T, inner.end as *const T,
inner.cap, inner.cap * mem::size_of::<I::Src>() / mem::size_of::<T>(),
) )
}; };
@ -203,11 +232,31 @@ where
// Note: This access to the source wouldn't be allowed by the TrustedRandomIteratorNoCoerce // Note: This access to the source wouldn't be allowed by the TrustedRandomIteratorNoCoerce
// contract (used by SpecInPlaceCollect below). But see the "O(1) collect" section in the // contract (used by SpecInPlaceCollect below). But see the "O(1) collect" section in the
// module documentation why this is ok anyway. // module documentation why this is ok anyway.
let dst_guard = InPlaceDstBufDrop { ptr: dst_buf, len, cap }; let dst_guard = InPlaceDstBufDrop { ptr: dst_buf, len, cap: dst_cap };
src.forget_allocation_drop_remaining(); src.forget_allocation_drop_remaining();
mem::forget(dst_guard); mem::forget(dst_guard);
let vec = unsafe { Vec::from_raw_parts(dst_buf, len, cap) }; // Adjust the allocation size if the source had a capacity in bytes that wasn't a multiple
// of the destination type size.
// Since the discrepancy should generally be small this should only result in some
// bookkeeping updates and no memmove.
if const { mem::size_of::<T>() > mem::size_of::<I::Src>() }
&& src_cap * mem::size_of::<I::Src>() != dst_cap * mem::size_of::<T>()
{
let alloc = Global;
unsafe {
let new_layout = Layout::array::<T>(dst_cap).unwrap();
let result = alloc.shrink(
NonNull::new_unchecked(dst_buf as *mut u8),
Layout::array::<I::Src>(src_cap).unwrap(),
new_layout,
);
let Ok(reallocated) = result else { handle_alloc_error(new_layout) };
dst_buf = reallocated.as_ptr() as *mut T;
}
}
let vec = unsafe { Vec::from_raw_parts(dst_buf, len, dst_cap) };
vec vec
} }

View file

@ -7,7 +7,8 @@ use crate::raw_vec::RawVec;
use core::array; use core::array;
use core::fmt; use core::fmt;
use core::iter::{ use core::iter::{
FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccessNoCoerce, FusedIterator, InPlaceIterable, SourceIter, TrustedFused, TrustedLen,
TrustedRandomAccessNoCoerce,
}; };
use core::marker::PhantomData; use core::marker::PhantomData;
use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties}; use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
@ -339,6 +340,10 @@ impl<T, A: Allocator> ExactSizeIterator for IntoIter<T, A> {
#[stable(feature = "fused", since = "1.26.0")] #[stable(feature = "fused", since = "1.26.0")]
impl<T, A: Allocator> FusedIterator for IntoIter<T, A> {} impl<T, A: Allocator> FusedIterator for IntoIter<T, A> {}
#[doc(hidden)]
#[unstable(issue = "none", feature = "trusted_fused")]
unsafe impl<T, A: Allocator> TrustedFused for IntoIter<T, A> {}
#[unstable(feature = "trusted_len", issue = "37572")] #[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<T, A: Allocator> TrustedLen for IntoIter<T, A> {} unsafe impl<T, A: Allocator> TrustedLen for IntoIter<T, A> {}
@ -423,7 +428,10 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for IntoIter<T, A> {
// also refer to the vec::in_place_collect module documentation to get an overview // also refer to the vec::in_place_collect module documentation to get an overview
#[unstable(issue = "none", feature = "inplace_iteration")] #[unstable(issue = "none", feature = "inplace_iteration")]
#[doc(hidden)] #[doc(hidden)]
unsafe impl<T, A: Allocator> InPlaceIterable for IntoIter<T, A> {} unsafe impl<T, A: Allocator> InPlaceIterable for IntoIter<T, A> {
const EXPAND_BY: Option<NonZeroUsize> = NonZeroUsize::new(1);
const MERGE_BY: Option<NonZeroUsize> = NonZeroUsize::new(1);
}
#[unstable(issue = "none", feature = "inplace_iteration")] #[unstable(issue = "none", feature = "inplace_iteration")]
#[doc(hidden)] #[doc(hidden)]

View file

@ -1,5 +1,6 @@
#![feature(allocator_api)] #![feature(allocator_api)]
#![feature(alloc_layout_extra)] #![feature(alloc_layout_extra)]
#![feature(iter_array_chunks)]
#![feature(assert_matches)] #![feature(assert_matches)]
#![feature(btree_extract_if)] #![feature(btree_extract_if)]
#![feature(cow_is_borrowed)] #![feature(cow_is_borrowed)]

View file

@ -1,6 +1,7 @@
use alloc::vec::Vec;
use core::alloc::{Allocator, Layout}; use core::alloc::{Allocator, Layout};
use core::assert_eq; use core::{assert_eq, assert_ne};
use core::iter::IntoIterator; use core::iter::{IntoIterator, Iterator};
use core::num::NonZeroUsize; use core::num::NonZeroUsize;
use core::ptr::NonNull; use core::ptr::NonNull;
use std::alloc::System; use std::alloc::System;
@ -1184,6 +1185,35 @@ fn test_from_iter_specialization_with_iterator_adapters() {
assert_eq!(srcptr, sinkptr as *const usize); assert_eq!(srcptr, sinkptr as *const usize);
} }
#[test]
fn test_in_place_specialization_step_up_down() {
fn assert_in_place_trait<T: InPlaceIterable>(_: &T) {}
let src = vec![[0u8; 4]; 256];
let srcptr = src.as_ptr();
let src_cap = src.capacity();
let iter = src.into_iter().flatten();
assert_in_place_trait(&iter);
let sink = iter.collect::<Vec<_>>();
let sinkptr = sink.as_ptr();
assert_eq!(srcptr as *const u8, sinkptr);
assert_eq!(src_cap * 4, sink.capacity());
let iter = sink.into_iter().array_chunks::<4>();
assert_in_place_trait(&iter);
let sink = iter.collect::<Vec<_>>();
let sinkptr = sink.as_ptr();
assert_eq!(srcptr, sinkptr);
assert_eq!(src_cap, sink.capacity());
let mut src: Vec<u8> = Vec::with_capacity(17);
let src_bytes = src.capacity();
src.resize(8, 0u8);
let sink: Vec<[u8; 4]> = src.into_iter().array_chunks::<4>().collect();
let sink_bytes = sink.capacity() * 4;
assert_ne!(src_bytes, sink_bytes);
assert_eq!(sink.len(), 2);
}
#[test] #[test]
fn test_from_iter_specialization_head_tail_drop() { fn test_from_iter_specialization_head_tail_drop() {
let drop_count: Vec<_> = (0..=2).map(|_| Rc::new(())).collect(); let drop_count: Vec<_> = (0..=2).map(|_| Rc::new(())).collect();

View file

@ -1,5 +1,9 @@
use crate::array; use crate::array;
use crate::iter::{ByRefSized, FusedIterator, Iterator, TrustedRandomAccessNoCoerce}; use crate::iter::adapters::SourceIter;
use crate::iter::{
ByRefSized, FusedIterator, InPlaceIterable, Iterator, TrustedFused, TrustedRandomAccessNoCoerce,
};
use crate::num::NonZeroUsize;
use crate::ops::{ControlFlow, NeverShortCircuit, Try}; use crate::ops::{ControlFlow, NeverShortCircuit, Try};
/// An iterator over `N` elements of the iterator at a time. /// An iterator over `N` elements of the iterator at a time.
@ -159,6 +163,9 @@ where
#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
impl<I, const N: usize> FusedIterator for ArrayChunks<I, N> where I: FusedIterator {} impl<I, const N: usize> FusedIterator for ArrayChunks<I, N> where I: FusedIterator {}
#[unstable(issue = "none", feature = "trusted_fused")]
unsafe impl<I, const N: usize> TrustedFused for ArrayChunks<I, N> where I: TrustedFused + Iterator {}
#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
impl<I, const N: usize> ExactSizeIterator for ArrayChunks<I, N> impl<I, const N: usize> ExactSizeIterator for ArrayChunks<I, N>
where where
@ -229,3 +236,28 @@ where
accum accum
} }
} }
#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I, const N: usize> SourceIter for ArrayChunks<I, N>
where
I: SourceIter + Iterator,
{
type Source = I::Source;
#[inline]
unsafe fn as_inner(&mut self) -> &mut I::Source {
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
unsafe { SourceIter::as_inner(&mut self.iter) }
}
}
#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I: InPlaceIterable + Iterator, const N: usize> InPlaceIterable for ArrayChunks<I, N> {
const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
const MERGE_BY: Option<NonZeroUsize> = const {
match (I::MERGE_BY, NonZeroUsize::new(N)) {
(Some(m), Some(n)) => m.checked_mul(n),
_ => None,
}
};
}

View file

@ -1,7 +1,7 @@
use crate::iter::adapters::{ use crate::iter::adapters::{
zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce, zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce,
}; };
use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen}; use crate::iter::{FusedIterator, InPlaceIterable, TrustedFused, TrustedLen};
use crate::num::NonZeroUsize; use crate::num::NonZeroUsize;
use crate::ops::Try; use crate::ops::Try;
@ -243,6 +243,9 @@ where
#[stable(feature = "fused", since = "1.26.0")] #[stable(feature = "fused", since = "1.26.0")]
impl<I> FusedIterator for Enumerate<I> where I: FusedIterator {} impl<I> FusedIterator for Enumerate<I> where I: FusedIterator {}
#[unstable(issue = "none", feature = "trusted_fused")]
unsafe impl<I: TrustedFused> TrustedFused for Enumerate<I> {}
#[unstable(feature = "trusted_len", issue = "37572")] #[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<I> TrustedLen for Enumerate<I> where I: TrustedLen {} unsafe impl<I> TrustedLen for Enumerate<I> where I: TrustedLen {}
@ -261,7 +264,10 @@ where
} }
#[unstable(issue = "none", feature = "inplace_iteration")] #[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I: InPlaceIterable> InPlaceIterable for Enumerate<I> {} unsafe impl<I: InPlaceIterable> InPlaceIterable for Enumerate<I> {
const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
}
#[stable(feature = "default_iters", since = "1.70.0")] #[stable(feature = "default_iters", since = "1.70.0")]
impl<I: Default> Default for Enumerate<I> { impl<I: Default> Default for Enumerate<I> {

View file

@ -1,5 +1,6 @@
use crate::fmt; use crate::fmt;
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedFused};
use crate::num::NonZeroUsize;
use crate::ops::Try; use crate::ops::Try;
use core::array; use core::array;
use core::mem::{ManuallyDrop, MaybeUninit}; use core::mem::{ManuallyDrop, MaybeUninit};
@ -189,6 +190,9 @@ where
#[stable(feature = "fused", since = "1.26.0")] #[stable(feature = "fused", since = "1.26.0")]
impl<I: FusedIterator, P> FusedIterator for Filter<I, P> where P: FnMut(&I::Item) -> bool {} impl<I: FusedIterator, P> FusedIterator for Filter<I, P> where P: FnMut(&I::Item) -> bool {}
#[unstable(issue = "none", feature = "trusted_fused")]
unsafe impl<I: TrustedFused, F> TrustedFused for Filter<I, F> {}
#[unstable(issue = "none", feature = "inplace_iteration")] #[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<P, I> SourceIter for Filter<I, P> unsafe impl<P, I> SourceIter for Filter<I, P>
where where
@ -204,4 +208,7 @@ where
} }
#[unstable(issue = "none", feature = "inplace_iteration")] #[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I: InPlaceIterable, P> InPlaceIterable for Filter<I, P> where P: FnMut(&I::Item) -> bool {} unsafe impl<I: InPlaceIterable, P> InPlaceIterable for Filter<I, P> {
const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
}

View file

@ -1,5 +1,6 @@
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedFused};
use crate::mem::{ManuallyDrop, MaybeUninit}; use crate::mem::{ManuallyDrop, MaybeUninit};
use crate::num::NonZeroUsize;
use crate::ops::{ControlFlow, Try}; use crate::ops::{ControlFlow, Try};
use crate::{array, fmt}; use crate::{array, fmt};
@ -188,6 +189,9 @@ where
#[stable(feature = "fused", since = "1.26.0")] #[stable(feature = "fused", since = "1.26.0")]
impl<B, I: FusedIterator, F> FusedIterator for FilterMap<I, F> where F: FnMut(I::Item) -> Option<B> {} impl<B, I: FusedIterator, F> FusedIterator for FilterMap<I, F> where F: FnMut(I::Item) -> Option<B> {}
#[unstable(issue = "none", feature = "trusted_fused")]
unsafe impl<I: TrustedFused, F> TrustedFused for FilterMap<I, F> {}
#[unstable(issue = "none", feature = "inplace_iteration")] #[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I, F> SourceIter for FilterMap<I, F> unsafe impl<I, F> SourceIter for FilterMap<I, F>
where where
@ -203,7 +207,7 @@ where
} }
#[unstable(issue = "none", feature = "inplace_iteration")] #[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<B, I: InPlaceIterable, F> InPlaceIterable for FilterMap<I, F> where unsafe impl<I: InPlaceIterable, F> InPlaceIterable for FilterMap<I, F> {
F: FnMut(I::Item) -> Option<B> const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
{ const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
} }

View file

@ -1,7 +1,12 @@
use crate::fmt; use crate::iter::adapters::SourceIter;
use crate::iter::{DoubleEndedIterator, Fuse, FusedIterator, Iterator, Map, TrustedLen}; use crate::iter::{
DoubleEndedIterator, Fuse, FusedIterator, InPlaceIterable, Iterator, Map, TrustedFused,
TrustedLen,
};
use crate::num::NonZeroUsize; use crate::num::NonZeroUsize;
use crate::ops::{ControlFlow, Try}; use crate::ops::{ControlFlow, Try};
use crate::{fmt, option};
use core::iter::Once;
/// An iterator that maps each element to an iterator, and yields the elements /// An iterator that maps each element to an iterator, and yields the elements
/// of the produced iterators. /// of the produced iterators.
@ -145,6 +150,48 @@ where
{ {
} }
#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I, U, F> InPlaceIterable for FlatMap<I, U, F>
where
I: InPlaceIterable,
U: KnownExpansionFactor + IntoIterator,
{
const EXPAND_BY: Option<NonZeroUsize> = const {
match (I::EXPAND_BY, U::FACTOR) {
(Some(m), Some(n)) => m.checked_mul(n),
_ => None,
}
};
const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
}
#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I, U, F> SourceIter for FlatMap<I, U, F>
where
I: SourceIter + TrustedFused,
U: IntoIterator,
{
type Source = I::Source;
#[inline]
unsafe fn as_inner(&mut self) -> &mut I::Source {
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
unsafe { SourceIter::as_inner(&mut self.inner.iter) }
}
}
#[rustc_specialization_trait]
trait KnownExpansionFactor {
const FACTOR: Option<NonZeroUsize> = NonZeroUsize::new(1);
}
impl<T> KnownExpansionFactor for Option<T> {}
impl<T> KnownExpansionFactor for option::IntoIter<T> {}
impl<T> KnownExpansionFactor for Once<T> {}
impl<T, const N: usize> KnownExpansionFactor for [T; N] {
const FACTOR: Option<NonZeroUsize> = NonZeroUsize::new(N);
}
/// An iterator that flattens one level of nesting in an iterator of things /// An iterator that flattens one level of nesting in an iterator of things
/// that can be turned into iterators. /// that can be turned into iterators.
/// ///
@ -289,6 +336,36 @@ where
{ {
} }
#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I> InPlaceIterable for Flatten<I>
where
I: InPlaceIterable + Iterator,
<I as Iterator>::Item: IntoIterator + KnownExpansionFactor,
{
const EXPAND_BY: Option<NonZeroUsize> = const {
match (I::EXPAND_BY, I::Item::FACTOR) {
(Some(m), Some(n)) => m.checked_mul(n),
_ => None,
}
};
const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
}
#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I> SourceIter for Flatten<I>
where
I: SourceIter + TrustedFused + Iterator,
<I as Iterator>::Item: IntoIterator,
{
type Source = I::Source;
#[inline]
unsafe fn as_inner(&mut self) -> &mut I::Source {
// SAFETY: unsafe function forwarding to unsafe function with the same requirements
unsafe { SourceIter::as_inner(&mut self.inner.iter) }
}
}
#[stable(feature = "default_iters", since = "1.70.0")] #[stable(feature = "default_iters", since = "1.70.0")]
impl<I> Default for Flatten<I> impl<I> Default for Flatten<I>
where where

View file

@ -1,8 +1,9 @@
use crate::intrinsics; use crate::intrinsics;
use crate::iter::adapters::zip::try_get_unchecked; use crate::iter::adapters::zip::try_get_unchecked;
use crate::iter::adapters::SourceIter;
use crate::iter::{ use crate::iter::{
DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedLen, TrustedRandomAccess, DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedFused, TrustedLen,
TrustedRandomAccessNoCoerce, TrustedRandomAccess, TrustedRandomAccessNoCoerce,
}; };
use crate::ops::Try; use crate::ops::Try;
@ -29,6 +30,9 @@ impl<I> Fuse<I> {
#[stable(feature = "fused", since = "1.26.0")] #[stable(feature = "fused", since = "1.26.0")]
impl<I> FusedIterator for Fuse<I> where I: Iterator {} impl<I> FusedIterator for Fuse<I> where I: Iterator {}
#[unstable(issue = "none", feature = "trusted_fused")]
unsafe impl<I> TrustedFused for Fuse<I> where I: TrustedFused {}
// Any specialized implementation here is made internal // Any specialized implementation here is made internal
// to avoid exposing default fns outside this trait. // to avoid exposing default fns outside this trait.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
@ -418,6 +422,23 @@ where
} }
} }
// This is used by Flatten's SourceIter impl
#[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I> SourceIter for Fuse<I>
where
I: SourceIter + TrustedFused,
{
type Source = I::Source;
#[inline]
unsafe fn as_inner(&mut self) -> &mut I::Source {
// SAFETY: unsafe function forwarding to unsafe function with the same requirements.
// TrustedFused guarantees that we'll never encounter a case where `self.iter` would
// be set to None.
unsafe { SourceIter::as_inner(self.iter.as_mut().unwrap_unchecked()) }
}
}
#[inline] #[inline]
fn and_then_or_clear<T, U>(opt: &mut Option<T>, f: impl FnOnce(&mut T) -> Option<U>) -> Option<U> { fn and_then_or_clear<T, U>(opt: &mut Option<T>, f: impl FnOnce(&mut T) -> Option<U>) -> Option<U> {
let x = f(opt.as_mut()?); let x = f(opt.as_mut()?);

View file

@ -1,5 +1,6 @@
use crate::fmt; use crate::fmt;
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedFused};
use crate::num::NonZeroUsize;
use crate::ops::Try; use crate::ops::Try;
/// An iterator that calls a function with a reference to each element before /// An iterator that calls a function with a reference to each element before
@ -148,6 +149,9 @@ where
#[stable(feature = "fused", since = "1.26.0")] #[stable(feature = "fused", since = "1.26.0")]
impl<I: FusedIterator, F> FusedIterator for Inspect<I, F> where F: FnMut(&I::Item) {} impl<I: FusedIterator, F> FusedIterator for Inspect<I, F> where F: FnMut(&I::Item) {}
#[unstable(issue = "none", feature = "trusted_fused")]
unsafe impl<I: TrustedFused, F> TrustedFused for Inspect<I, F> {}
#[unstable(issue = "none", feature = "inplace_iteration")] #[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I, F> SourceIter for Inspect<I, F> unsafe impl<I, F> SourceIter for Inspect<I, F>
where where
@ -163,4 +167,7 @@ where
} }
#[unstable(issue = "none", feature = "inplace_iteration")] #[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I: InPlaceIterable, F> InPlaceIterable for Inspect<I, F> where F: FnMut(&I::Item) {} unsafe impl<I: InPlaceIterable, F> InPlaceIterable for Inspect<I, F> {
const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
}

View file

@ -2,7 +2,8 @@ use crate::fmt;
use crate::iter::adapters::{ use crate::iter::adapters::{
zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce, zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce,
}; };
use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen, UncheckedIterator}; use crate::iter::{FusedIterator, InPlaceIterable, TrustedFused, TrustedLen, UncheckedIterator};
use crate::num::NonZeroUsize;
use crate::ops::Try; use crate::ops::Try;
/// An iterator that maps the values of `iter` with `f`. /// An iterator that maps the values of `iter` with `f`.
@ -179,6 +180,9 @@ where
#[stable(feature = "fused", since = "1.26.0")] #[stable(feature = "fused", since = "1.26.0")]
impl<B, I: FusedIterator, F> FusedIterator for Map<I, F> where F: FnMut(I::Item) -> B {} impl<B, I: FusedIterator, F> FusedIterator for Map<I, F> where F: FnMut(I::Item) -> B {}
#[unstable(issue = "none", feature = "trusted_fused")]
unsafe impl<I: TrustedFused, F> TrustedFused for Map<I, F> {}
#[unstable(feature = "trusted_len", issue = "37572")] #[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<B, I, F> TrustedLen for Map<I, F> unsafe impl<B, I, F> TrustedLen for Map<I, F>
where where
@ -228,4 +232,7 @@ where
} }
#[unstable(issue = "none", feature = "inplace_iteration")] #[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<B, I: InPlaceIterable, F> InPlaceIterable for Map<I, F> where F: FnMut(I::Item) -> B {} unsafe impl<I: InPlaceIterable, F> InPlaceIterable for Map<I, F> {
const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
}

View file

@ -1,5 +1,6 @@
use crate::fmt; use crate::fmt;
use crate::iter::{adapters::SourceIter, InPlaceIterable}; use crate::iter::{adapters::SourceIter, InPlaceIterable};
use crate::num::NonZeroUsize;
use crate::ops::{ControlFlow, Try}; use crate::ops::{ControlFlow, Try};
/// An iterator that only accepts elements while `predicate` returns `Some(_)`. /// An iterator that only accepts elements while `predicate` returns `Some(_)`.
@ -82,7 +83,7 @@ where
} }
#[unstable(issue = "none", feature = "inplace_iteration")] #[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<B, I: InPlaceIterable, P> InPlaceIterable for MapWhile<I, P> where unsafe impl<I: InPlaceIterable, P> InPlaceIterable for MapWhile<I, P> {
P: FnMut(I::Item) -> Option<B> const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
{ const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
} }

View file

@ -1,4 +1,5 @@
use crate::iter::{InPlaceIterable, Iterator}; use crate::iter::{InPlaceIterable, Iterator};
use crate::num::NonZeroUsize;
use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try}; use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try};
mod array_chunks; mod array_chunks;
@ -119,8 +120,9 @@ pub unsafe trait SourceIter {
/// ///
/// # Safety /// # Safety
/// ///
/// Implementations of must return the same mutable reference for their lifetime, unless /// Implementations must return the same mutable reference for their lifetime, unless
/// replaced by a caller. /// replaced by a caller.
///
/// Callers may only replace the reference when they stopped iteration and drop the /// Callers may only replace the reference when they stopped iteration and drop the
/// iterator pipeline after extracting the source. /// iterator pipeline after extracting the source.
/// ///
@ -228,7 +230,10 @@ where
// in order to return `Some(_)`. Since `iter` has type `I: InPlaceIterable` it's // in order to return `Some(_)`. Since `iter` has type `I: InPlaceIterable` it's
// guaranteed that at least one item will be moved out from the underlying source. // guaranteed that at least one item will be moved out from the underlying source.
#[unstable(issue = "none", feature = "inplace_iteration")] #[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I, T, R> InPlaceIterable for GenericShunt<'_, I, R> where unsafe impl<I, R> InPlaceIterable for GenericShunt<'_, I, R>
I: Iterator<Item: Try<Output = T, Residual = R>> + InPlaceIterable where
I: InPlaceIterable,
{ {
const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
} }

View file

@ -1,5 +1,6 @@
use crate::fmt; use crate::fmt;
use crate::iter::{adapters::SourceIter, InPlaceIterable}; use crate::iter::{adapters::SourceIter, InPlaceIterable};
use crate::num::NonZeroUsize;
use crate::ops::{ControlFlow, Try}; use crate::ops::{ControlFlow, Try};
/// An iterator to maintain state while iterating another iterator. /// An iterator to maintain state while iterating another iterator.
@ -92,7 +93,7 @@ where
} }
#[unstable(issue = "none", feature = "inplace_iteration")] #[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<St, F, B, I: InPlaceIterable> InPlaceIterable for Scan<I, St, F> where unsafe impl<St, F, I: InPlaceIterable> InPlaceIterable for Scan<I, St, F> {
F: FnMut(&mut St, I::Item) -> Option<B> const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
{ const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
} }

View file

@ -1,4 +1,5 @@
use crate::intrinsics::unlikely; use crate::intrinsics::unlikely;
use crate::iter::TrustedFused;
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable};
use crate::num::NonZeroUsize; use crate::num::NonZeroUsize;
use crate::ops::{ControlFlow, Try}; use crate::ops::{ControlFlow, Try};
@ -214,6 +215,9 @@ where
#[stable(feature = "fused", since = "1.26.0")] #[stable(feature = "fused", since = "1.26.0")]
impl<I> FusedIterator for Skip<I> where I: FusedIterator {} impl<I> FusedIterator for Skip<I> where I: FusedIterator {}
#[unstable(issue = "none", feature = "trusted_fused")]
unsafe impl<I: TrustedFused> TrustedFused for Skip<I> {}
#[unstable(issue = "none", feature = "inplace_iteration")] #[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I> SourceIter for Skip<I> unsafe impl<I> SourceIter for Skip<I>
where where
@ -229,4 +233,7 @@ where
} }
#[unstable(issue = "none", feature = "inplace_iteration")] #[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I: InPlaceIterable> InPlaceIterable for Skip<I> {} unsafe impl<I: InPlaceIterable> InPlaceIterable for Skip<I> {
const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
}

View file

@ -1,5 +1,6 @@
use crate::fmt; use crate::fmt;
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedFused};
use crate::num::NonZeroUsize;
use crate::ops::Try; use crate::ops::Try;
/// An iterator that rejects elements while `predicate` returns `true`. /// An iterator that rejects elements while `predicate` returns `true`.
@ -104,6 +105,9 @@ where
{ {
} }
#[unstable(issue = "none", feature = "trusted_fused")]
unsafe impl<I: TrustedFused, P> TrustedFused for SkipWhile<I, P> {}
#[unstable(issue = "none", feature = "inplace_iteration")] #[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<P, I> SourceIter for SkipWhile<I, P> unsafe impl<P, I> SourceIter for SkipWhile<I, P>
where where
@ -119,7 +123,7 @@ where
} }
#[unstable(issue = "none", feature = "inplace_iteration")] #[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I: InPlaceIterable, F> InPlaceIterable for SkipWhile<I, F> where unsafe impl<I: InPlaceIterable, F> InPlaceIterable for SkipWhile<I, F> {
F: FnMut(&I::Item) -> bool const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
{ const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
} }

View file

@ -1,6 +1,7 @@
use crate::cmp; use crate::cmp;
use crate::iter::{ use crate::iter::{
adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen, TrustedRandomAccess, adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedFused, TrustedLen,
TrustedRandomAccess,
}; };
use crate::num::NonZeroUsize; use crate::num::NonZeroUsize;
use crate::ops::{ControlFlow, Try}; use crate::ops::{ControlFlow, Try};
@ -143,7 +144,10 @@ where
} }
#[unstable(issue = "none", feature = "inplace_iteration")] #[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I: InPlaceIterable> InPlaceIterable for Take<I> {} unsafe impl<I: InPlaceIterable> InPlaceIterable for Take<I> {
const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
}
#[stable(feature = "double_ended_take_iterator", since = "1.38.0")] #[stable(feature = "double_ended_take_iterator", since = "1.38.0")]
impl<I> DoubleEndedIterator for Take<I> impl<I> DoubleEndedIterator for Take<I>
@ -241,6 +245,9 @@ impl<I> ExactSizeIterator for Take<I> where I: ExactSizeIterator {}
#[stable(feature = "fused", since = "1.26.0")] #[stable(feature = "fused", since = "1.26.0")]
impl<I> FusedIterator for Take<I> where I: FusedIterator {} impl<I> FusedIterator for Take<I> where I: FusedIterator {}
#[unstable(issue = "none", feature = "trusted_fused")]
unsafe impl<I: TrustedFused> TrustedFused for Take<I> {}
#[unstable(feature = "trusted_len", issue = "37572")] #[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<I: TrustedLen> TrustedLen for Take<I> {} unsafe impl<I: TrustedLen> TrustedLen for Take<I> {}

View file

@ -1,5 +1,6 @@
use crate::fmt; use crate::fmt;
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedFused};
use crate::num::NonZeroUsize;
use crate::ops::{ControlFlow, Try}; use crate::ops::{ControlFlow, Try};
/// An iterator that only accepts elements while `predicate` returns `true`. /// An iterator that only accepts elements while `predicate` returns `true`.
@ -105,6 +106,9 @@ where
{ {
} }
#[unstable(issue = "none", feature = "trusted_fused")]
unsafe impl<I: TrustedFused, P> TrustedFused for TakeWhile<I, P> {}
#[unstable(issue = "none", feature = "inplace_iteration")] #[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<P, I> SourceIter for TakeWhile<I, P> unsafe impl<P, I> SourceIter for TakeWhile<I, P>
where where
@ -120,7 +124,7 @@ where
} }
#[unstable(issue = "none", feature = "inplace_iteration")] #[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<I: InPlaceIterable, F> InPlaceIterable for TakeWhile<I, F> where unsafe impl<I: InPlaceIterable, F> InPlaceIterable for TakeWhile<I, F> {
F: FnMut(&I::Item) -> bool const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
{ const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
} }

View file

@ -1,7 +1,8 @@
use crate::cmp; use crate::cmp;
use crate::fmt::{self, Debug}; use crate::fmt::{self, Debug};
use crate::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator}; use crate::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator, TrustedFused};
use crate::iter::{InPlaceIterable, SourceIter, TrustedLen, UncheckedIterator}; use crate::iter::{InPlaceIterable, SourceIter, TrustedLen, UncheckedIterator};
use crate::num::NonZeroUsize;
/// An iterator that iterates two other iterators simultaneously. /// An iterator that iterates two other iterators simultaneously.
/// ///
@ -409,6 +410,14 @@ where
{ {
} }
#[unstable(issue = "none", feature = "trusted_fused")]
unsafe impl<A, B> TrustedFused for Zip<A, B>
where
A: TrustedFused,
B: TrustedFused,
{
}
#[unstable(feature = "trusted_len", issue = "37572")] #[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<A, B> TrustedLen for Zip<A, B> unsafe impl<A, B> TrustedLen for Zip<A, B>
where where
@ -442,7 +451,10 @@ where
// Since SourceIter forwards the left hand side we do the same here // Since SourceIter forwards the left hand side we do the same here
#[unstable(issue = "none", feature = "inplace_iteration")] #[unstable(issue = "none", feature = "inplace_iteration")]
unsafe impl<A: InPlaceIterable, B: Iterator> InPlaceIterable for Zip<A, B> {} unsafe impl<A: InPlaceIterable, B> InPlaceIterable for Zip<A, B> {
const EXPAND_BY: Option<NonZeroUsize> = A::EXPAND_BY;
const MERGE_BY: Option<NonZeroUsize> = A::MERGE_BY;
}
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<A: Debug, B: Debug> Debug for Zip<A, B> { impl<A: Debug, B: Debug> Debug for Zip<A, B> {

View file

@ -417,6 +417,8 @@ pub use self::sources::{successors, Successors};
pub use self::traits::FusedIterator; pub use self::traits::FusedIterator;
#[unstable(issue = "none", feature = "inplace_iteration")] #[unstable(issue = "none", feature = "inplace_iteration")]
pub use self::traits::InPlaceIterable; pub use self::traits::InPlaceIterable;
#[unstable(issue = "none", feature = "trusted_fused")]
pub use self::traits::TrustedFused;
#[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")] #[unstable(feature = "trusted_step", issue = "85731")]

View file

@ -1,4 +1,16 @@
use crate::iter::Step; use crate::iter::Step;
use crate::num::NonZeroUsize;
/// Same as FusedIterator
///
/// # Safety
///
/// This is used for specialization. Therefore implementations must not
/// be lifetime-dependent.
#[unstable(issue = "none", feature = "trusted_fused")]
#[doc(hidden)]
#[rustc_specialization_trait]
pub unsafe trait TrustedFused {}
/// An iterator that always continues to yield `None` when exhausted. /// An iterator that always continues to yield `None` when exhausted.
/// ///
@ -14,6 +26,8 @@ use crate::iter::Step;
/// [`Fuse`]: crate::iter::Fuse /// [`Fuse`]: crate::iter::Fuse
#[stable(feature = "fused", since = "1.26.0")] #[stable(feature = "fused", since = "1.26.0")]
#[rustc_unsafe_specialization_marker] #[rustc_unsafe_specialization_marker]
// FIXME: this should be a #[marker] and have another blanket impl for T: TrustedFused
// but that ICEs iter::Fuse specializations.
pub trait FusedIterator: Iterator {} pub trait FusedIterator: Iterator {}
#[stable(feature = "fused", since = "1.26.0")] #[stable(feature = "fused", since = "1.26.0")]
@ -71,7 +85,19 @@ unsafe impl<I: TrustedLen + ?Sized> TrustedLen for &mut I {}
/// [`try_fold()`]: Iterator::try_fold /// [`try_fold()`]: Iterator::try_fold
#[unstable(issue = "none", feature = "inplace_iteration")] #[unstable(issue = "none", feature = "inplace_iteration")]
#[doc(hidden)] #[doc(hidden)]
pub unsafe trait InPlaceIterable: Iterator {} #[rustc_specialization_trait]
pub unsafe trait InPlaceIterable {
/// The product of one-to-many item expansions that happen throughout the iterator pipeline.
/// E.g. [[u8; 4]; 4].iter().flatten().flatten() would have a `EXPAND_BY` of 16.
/// This is an upper bound, i.e. the transformations will produce at most this many items per
/// input. It's meant for layout calculations.
const EXPAND_BY: Option<NonZeroUsize>;
/// The product of many-to-one item reductions that happen throughout the iterator pipeline.
/// E.g. [u8].iter().array_chunks::<4>().array_chunks::<4>() would have a `MERGE_BY` of 16.
/// This is a lower bound, i.e. the transformations will consume at least this many items per
/// output.
const MERGE_BY: Option<NonZeroUsize>;
}
/// A type that upholds all invariants of [`Step`]. /// A type that upholds all invariants of [`Step`].
/// ///

View file

@ -18,6 +18,8 @@ pub use self::{
#[unstable(issue = "none", feature = "inplace_iteration")] #[unstable(issue = "none", feature = "inplace_iteration")]
pub use self::marker::InPlaceIterable; pub use self::marker::InPlaceIterable;
#[unstable(issue = "none", feature = "trusted_fused")]
pub use self::marker::TrustedFused;
#[unstable(feature = "trusted_step", issue = "85731")] #[unstable(feature = "trusted_step", issue = "85731")]
pub use self::marker::TrustedStep; pub use self::marker::TrustedStep;