Auto merge of #110353 - the8472:in-place-flatten-chunks, r=cuviper
Expand in-place iteration specialization to Flatten, FlatMap and ArrayChunks This enables the following cases to collect in-place: ```rust let v = vec![[0u8; 4]; 1024] let v: Vec<_> = v.into_iter().flatten().collect(); let v: Vec<Option<NonZeroUsize>> = vec![NonZeroUsize::new(0); 1024]; let v: Vec<_> = v.into_iter().flatten().collect(); let v = vec![u8; 4096]; let v: Vec<_> = v.into_iter().array_chunks::<4>().collect(); ``` Especially the nicheful-option-flattening should be useful in real code.
This commit is contained in:
commit
df0295f071
25 changed files with 488 additions and 71 deletions
|
|
@ -145,7 +145,7 @@
|
|||
|
||||
use core::alloc::Allocator;
|
||||
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::num::NonZeroUsize;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
|
|
@ -1542,6 +1542,10 @@ impl<T, A: Allocator> ExactSizeIterator for IntoIter<T, A> {
|
|||
#[stable(feature = "fused", since = "1.26.0")]
|
||||
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")]
|
||||
impl<T> Default for IntoIter<T> {
|
||||
/// Creates an empty `binary_heap::IntoIter`.
|
||||
|
|
@ -1571,7 +1575,10 @@ unsafe impl<T, A: Allocator> SourceIter for IntoIter<T, A> {
|
|||
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
#[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> {
|
||||
type Item = I;
|
||||
|
|
|
|||
|
|
@ -154,6 +154,7 @@
|
|||
#![feature(std_internals)]
|
||||
#![feature(str_internals)]
|
||||
#![feature(strict_provenance)]
|
||||
#![feature(trusted_fused)]
|
||||
#![feature(trusted_len)]
|
||||
#![feature(trusted_random_access)]
|
||||
#![feature(try_trait_v2)]
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@
|
|||
//! The specialization in this module applies to iterators in the shape of
|
||||
//! `source.adapter().adapter().adapter().collect::<Vec<U>>()`
|
||||
//! where `source` is an owning iterator obtained from [`Vec<T>`], [`Box<[T]>`][box] (by conversion to `Vec`)
|
||||
//! or [`BinaryHeap<T>`], the adapters each consume one or more items per step
|
||||
//! (represented by [`InPlaceIterable`]), provide transitive access to `source` (via [`SourceIter`])
|
||||
//! and thus the underlying allocation. And finally the layouts of `T` and `U` must
|
||||
//! have the same size and alignment, this is currently ensured via const eval instead of trait bounds
|
||||
//! in the specialized [`SpecFromIter`] implementation.
|
||||
//! or [`BinaryHeap<T>`], the adapters guarantee to consume enough items per step to make room
|
||||
//! for the results (represented by [`InPlaceIterable`]), provide transitive access to `source`
|
||||
//! (via [`SourceIter`]) and thus the underlying allocation.
|
||||
//! And finally there are alignment and size constriants to consider, this is currently ensured via
|
||||
//! const eval instead of trait bounds in the specialized [`SpecFromIter`] implementation.
|
||||
//!
|
||||
//! [`BinaryHeap<T>`]: crate::collections::BinaryHeap
|
||||
//! [box]: crate::boxed::Box
|
||||
|
|
@ -35,11 +35,28 @@
|
|||
//! the step of reading a value and getting a reference to write to. Instead raw pointers must be
|
||||
//! used on the reader and writer side.
|
||||
//!
|
||||
//! That writes never clobber a yet-to-be-read item is ensured by the [`InPlaceIterable`] requirements.
|
||||
//! That writes never clobber a yet-to-be-read items is ensured by the [`InPlaceIterable`] requirements.
|
||||
//!
|
||||
//! # Layout constraints
|
||||
//!
|
||||
//! [`Allocator`] requires that `allocate()` and `deallocate()` have matching alignment and size.
|
||||
//! When recycling an allocation between different types we must uphold the [`Allocator`] contract
|
||||
//! which means that the input and output Layouts have to "fit".
|
||||
//!
|
||||
//! To complicate things further `InPlaceIterable` supports splitting or merging items into smaller/
|
||||
//! larger ones to enable (de)aggregation of arrays.
|
||||
//!
|
||||
//! Ultimately each step of the iterator must free up enough *bytes* in the source to make room
|
||||
//! for the next output item.
|
||||
//! If `T` and `U` have the same size no fixup is needed.
|
||||
//! If `T`'s size is a multiple of `U`'s we can compensate by multiplying the capacity accordingly.
|
||||
//! Otherwise the input capacity (and thus layout) in bytes may not be representable by the output
|
||||
//! `Vec<U>`. In that case `alloc.shrink()` is used to update the allocation's layout.
|
||||
//!
|
||||
//! Alignments of `T` must be the same or larger than `U`. Since alignments are always a power
|
||||
//! of two _larger_ implies _is a multiple of_.
|
||||
//!
|
||||
//! See `in_place_collectible()` for the current conditions.
|
||||
//!
|
||||
//! Additionally this specialization doesn't make sense for ZSTs as there is no reallocation to
|
||||
//! avoid and it would make pointer arithmetic more difficult.
|
||||
//!
|
||||
|
|
@ -137,44 +154,73 @@
|
|||
//! }
|
||||
//! 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::mem::{self, ManuallyDrop, SizedTypeProperties};
|
||||
use core::ptr::{self};
|
||||
use core::num::NonZeroUsize;
|
||||
use core::ptr::{self, NonNull};
|
||||
|
||||
use super::{InPlaceDrop, InPlaceDstBufDrop, SpecFromIter, SpecFromIterNested, Vec};
|
||||
|
||||
/// Specialization marker for collecting an iterator pipeline into a Vec while reusing the
|
||||
/// source allocation, i.e. executing the pipeline in place.
|
||||
#[rustc_unsafe_specialization_marker]
|
||||
pub(super) trait InPlaceIterableMarker {}
|
||||
const fn in_place_collectible<DEST, SRC>(
|
||||
step_merge: Option<NonZeroUsize>,
|
||||
step_expand: Option<NonZeroUsize>,
|
||||
) -> 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 occurred 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>
|
||||
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 {
|
||||
// See "Layout constraints" section in the module documentation. We rely on const
|
||||
// optimization here since these conditions currently cannot be expressed as trait bounds
|
||||
if T::IS_ZST
|
||||
|| 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>()
|
||||
{
|
||||
if const { !in_place_collectible::<T, I::Src>(I::MERGE_BY, I::EXPAND_BY) } {
|
||||
// fallback to more generic implementations
|
||||
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();
|
||||
(
|
||||
inner.buf.as_ptr(),
|
||||
inner.ptr,
|
||||
inner.cap,
|
||||
inner.buf.as_ptr() as *mut T,
|
||||
inner.end as *const T,
|
||||
inner.cap,
|
||||
inner.cap * mem::size_of::<I::Src>() / mem::size_of::<T>(),
|
||||
)
|
||||
};
|
||||
|
||||
|
|
@ -196,18 +242,55 @@ where
|
|||
}
|
||||
|
||||
// The ownership of the allocation and the new `T` values is temporarily moved into `dst_guard`.
|
||||
// This is safe because `forget_allocation_drop_remaining` immediately forgets the allocation
|
||||
// This is safe because
|
||||
// * `forget_allocation_drop_remaining` immediately forgets the allocation
|
||||
// before any panic can occur in order to avoid any double free, and then proceeds to drop
|
||||
// any remaining values at the tail of the source.
|
||||
// * the shrink either panics without invalidating the allocation, aborts or
|
||||
// succeeds. In the last case we disarm the guard.
|
||||
//
|
||||
// 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
|
||||
// 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();
|
||||
|
||||
// Adjust the allocation if the alignment didn't match or 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 {
|
||||
let src_sz = mem::size_of::<I::Src>();
|
||||
src_sz > 0 && mem::size_of::<T>() % src_sz != 0
|
||||
} && src_cap * mem::size_of::<I::Src>() != dst_cap * mem::size_of::<T>())
|
||||
|| const { mem::align_of::<T>() != mem::align_of::<I::Src>() }
|
||||
{
|
||||
let alloc = Global;
|
||||
unsafe {
|
||||
// The old allocation exists, therefore it must have a valid layout.
|
||||
let src_align = mem::align_of::<I::Src>();
|
||||
let src_size = mem::size_of::<I::Src>().unchecked_mul(src_cap);
|
||||
let old_layout = Layout::from_size_align_unchecked(src_size, src_align);
|
||||
|
||||
// The must be equal or smaller for in-place iteration to be possible
|
||||
// therefore the new layout must be ≤ the old one and therefore valid.
|
||||
let dst_align = mem::align_of::<T>();
|
||||
let dst_size = mem::size_of::<T>().unchecked_mul(dst_cap);
|
||||
let new_layout = Layout::from_size_align_unchecked(dst_size, dst_align);
|
||||
|
||||
let result = alloc.shrink(
|
||||
NonNull::new_unchecked(dst_buf as *mut u8),
|
||||
old_layout,
|
||||
new_layout,
|
||||
);
|
||||
let Ok(reallocated) = result else { handle_alloc_error(new_layout) };
|
||||
dst_buf = reallocated.as_ptr() as *mut T;
|
||||
}
|
||||
}
|
||||
|
||||
mem::forget(dst_guard);
|
||||
|
||||
let vec = unsafe { Vec::from_raw_parts(dst_buf, len, cap) };
|
||||
let vec = unsafe { Vec::from_raw_parts(dst_buf, len, dst_cap) };
|
||||
|
||||
vec
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ use crate::raw_vec::RawVec;
|
|||
use core::array;
|
||||
use core::fmt;
|
||||
use core::iter::{
|
||||
FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccessNoCoerce,
|
||||
FusedIterator, InPlaceIterable, SourceIter, TrustedFused, TrustedLen,
|
||||
TrustedRandomAccessNoCoerce,
|
||||
};
|
||||
use core::marker::PhantomData;
|
||||
use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
|
||||
|
|
@ -337,6 +338,10 @@ impl<T, A: Allocator> ExactSizeIterator for IntoIter<T, A> {
|
|||
#[stable(feature = "fused", since = "1.26.0")]
|
||||
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")]
|
||||
unsafe impl<T, A: Allocator> TrustedLen for IntoIter<T, A> {}
|
||||
|
||||
|
|
@ -421,7 +426,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
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
#[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")]
|
||||
#[doc(hidden)]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#![feature(allocator_api)]
|
||||
#![feature(alloc_layout_extra)]
|
||||
#![feature(iter_array_chunks)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(btree_extract_if)]
|
||||
#![feature(cow_is_borrowed)]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use alloc::vec::Vec;
|
||||
use core::alloc::{Allocator, Layout};
|
||||
use core::assert_eq;
|
||||
use core::iter::IntoIterator;
|
||||
use core::{assert_eq, assert_ne};
|
||||
use core::iter::{IntoIterator, Iterator};
|
||||
use core::num::NonZeroUsize;
|
||||
use core::ptr::NonNull;
|
||||
use std::alloc::System;
|
||||
|
|
@ -1184,6 +1185,46 @@ fn test_from_iter_specialization_with_iterator_adapters() {
|
|||
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);
|
||||
|
||||
let src = vec![[0u8; 4]; 256];
|
||||
let srcptr = src.as_ptr();
|
||||
let iter = src
|
||||
.into_iter()
|
||||
.flat_map(|a| {
|
||||
a.into_iter().map(|b| b.wrapping_add(1))
|
||||
});
|
||||
assert_in_place_trait(&iter);
|
||||
let sink = iter.collect::<Vec<_>>();
|
||||
assert_eq!(srcptr as *const u8, sink.as_ptr());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_iter_specialization_head_tail_drop() {
|
||||
let drop_count: Vec<_> = (0..=2).map(|_| Rc::new(())).collect();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
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};
|
||||
|
||||
/// 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")]
|
||||
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")]
|
||||
impl<I, const N: usize> ExactSizeIterator for ArrayChunks<I, N>
|
||||
where
|
||||
|
|
@ -229,3 +236,28 @@ where
|
|||
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,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::iter::adapters::{
|
||||
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::ops::Try;
|
||||
|
||||
|
|
@ -243,6 +243,9 @@ where
|
|||
#[stable(feature = "fused", since = "1.26.0")]
|
||||
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")]
|
||||
unsafe impl<I> TrustedLen for Enumerate<I> where I: TrustedLen {}
|
||||
|
||||
|
|
@ -261,7 +264,10 @@ where
|
|||
}
|
||||
|
||||
#[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")]
|
||||
impl<I: Default> Default for Enumerate<I> {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
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 core::array;
|
||||
use core::mem::{ManuallyDrop, MaybeUninit};
|
||||
|
|
@ -189,6 +190,9 @@ where
|
|||
#[stable(feature = "fused", since = "1.26.0")]
|
||||
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")]
|
||||
unsafe impl<P, I> SourceIter for Filter<I, P>
|
||||
where
|
||||
|
|
@ -204,4 +208,7 @@ where
|
|||
}
|
||||
|
||||
#[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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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::num::NonZeroUsize;
|
||||
use crate::ops::{ControlFlow, Try};
|
||||
use crate::{array, fmt};
|
||||
|
||||
|
|
@ -190,6 +191,9 @@ where
|
|||
#[stable(feature = "fused", since = "1.26.0")]
|
||||
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")]
|
||||
unsafe impl<I, F> SourceIter for FilterMap<I, F>
|
||||
where
|
||||
|
|
@ -205,7 +209,7 @@ where
|
|||
}
|
||||
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<B, I: InPlaceIterable, F> InPlaceIterable for FilterMap<I, F> where
|
||||
F: FnMut(I::Item) -> Option<B>
|
||||
{
|
||||
unsafe impl<I: InPlaceIterable, F> InPlaceIterable for FilterMap<I, F> {
|
||||
const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
|
||||
const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
use crate::fmt;
|
||||
use crate::iter::{DoubleEndedIterator, Fuse, FusedIterator, Iterator, Map, TrustedLen};
|
||||
use crate::iter::adapters::SourceIter;
|
||||
use crate::iter::{
|
||||
Cloned, Copied, DoubleEndedIterator, Filter, FilterMap, Fuse, FusedIterator, InPlaceIterable,
|
||||
Iterator, Map, TrustedFused, TrustedLen,
|
||||
};
|
||||
use crate::iter::{Once, OnceWith};
|
||||
use crate::num::NonZeroUsize;
|
||||
use crate::ops::{ControlFlow, Try};
|
||||
use crate::result;
|
||||
use crate::{array, fmt, option};
|
||||
|
||||
/// An iterator that maps each element to an iterator, and yields the elements
|
||||
/// of the produced iterators.
|
||||
|
|
@ -145,6 +151,91 @@ where
|
|||
{
|
||||
}
|
||||
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<I, U, F> InPlaceIterable for FlatMap<I, U, F>
|
||||
where
|
||||
I: InPlaceIterable,
|
||||
U: BoundedSize + IntoIterator,
|
||||
{
|
||||
const EXPAND_BY: Option<NonZeroUsize> = const {
|
||||
match (I::EXPAND_BY, U::UPPER_BOUND) {
|
||||
(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) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Marker trait for iterators/iterables which have a statically known upper
|
||||
/// bound of the number of items they can produce.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Implementations must not yield more elements than indicated by UPPER_BOUND if it is `Some`.
|
||||
/// Used in specializations. Implementations must not be conditional on lifetimes or
|
||||
/// user-implementable traits.
|
||||
#[rustc_specialization_trait]
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe trait BoundedSize {
|
||||
const UPPER_BOUND: Option<NonZeroUsize> = NonZeroUsize::new(1);
|
||||
}
|
||||
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<T> BoundedSize for Option<T> {}
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<T> BoundedSize for option::IntoIter<T> {}
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<T, U> BoundedSize for Result<T, U> {}
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<T> BoundedSize for result::IntoIter<T> {}
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<T> BoundedSize for Once<T> {}
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<T> BoundedSize for OnceWith<T> {}
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<T, const N: usize> BoundedSize for [T; N] {
|
||||
const UPPER_BOUND: Option<NonZeroUsize> = NonZeroUsize::new(N);
|
||||
}
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<T, const N: usize> BoundedSize for array::IntoIter<T, N> {
|
||||
const UPPER_BOUND: Option<NonZeroUsize> = NonZeroUsize::new(N);
|
||||
}
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<I: BoundedSize, P> BoundedSize for Filter<I, P> {
|
||||
const UPPER_BOUND: Option<NonZeroUsize> = I::UPPER_BOUND;
|
||||
}
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<I: BoundedSize, P> BoundedSize for FilterMap<I, P> {
|
||||
const UPPER_BOUND: Option<NonZeroUsize> = I::UPPER_BOUND;
|
||||
}
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<I: BoundedSize, F> BoundedSize for Map<I, F> {
|
||||
const UPPER_BOUND: Option<NonZeroUsize> = I::UPPER_BOUND;
|
||||
}
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<I: BoundedSize> BoundedSize for Copied<I> {
|
||||
const UPPER_BOUND: Option<NonZeroUsize> = I::UPPER_BOUND;
|
||||
}
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<I: BoundedSize> BoundedSize for Cloned<I> {
|
||||
const UPPER_BOUND: Option<NonZeroUsize> = I::UPPER_BOUND;
|
||||
}
|
||||
|
||||
/// An iterator that flattens one level of nesting in an iterator of things
|
||||
/// that can be turned into iterators.
|
||||
///
|
||||
|
|
@ -289,6 +380,36 @@ where
|
|||
{
|
||||
}
|
||||
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<I> InPlaceIterable for Flatten<I>
|
||||
where
|
||||
I: InPlaceIterable + Iterator,
|
||||
<I as Iterator>::Item: IntoIterator + BoundedSize,
|
||||
{
|
||||
const EXPAND_BY: Option<NonZeroUsize> = const {
|
||||
match (I::EXPAND_BY, I::Item::UPPER_BOUND) {
|
||||
(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")]
|
||||
impl<I> Default for Flatten<I>
|
||||
where
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
use crate::intrinsics;
|
||||
use crate::iter::adapters::zip::try_get_unchecked;
|
||||
use crate::iter::adapters::SourceIter;
|
||||
use crate::iter::{
|
||||
DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedLen, TrustedRandomAccess,
|
||||
TrustedRandomAccessNoCoerce,
|
||||
DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedFused, TrustedLen,
|
||||
TrustedRandomAccess, TrustedRandomAccessNoCoerce,
|
||||
};
|
||||
use crate::ops::Try;
|
||||
|
||||
|
|
@ -29,6 +30,9 @@ impl<I> Fuse<I> {
|
|||
#[stable(feature = "fused", since = "1.26.0")]
|
||||
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
|
||||
// to avoid exposing default fns outside this trait.
|
||||
#[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]
|
||||
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()?);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
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;
|
||||
|
||||
/// 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")]
|
||||
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")]
|
||||
unsafe impl<I, F> SourceIter for Inspect<I, F>
|
||||
where
|
||||
|
|
@ -163,4 +167,7 @@ where
|
|||
}
|
||||
|
||||
#[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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ use crate::fmt;
|
|||
use crate::iter::adapters::{
|
||||
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;
|
||||
|
||||
/// An iterator that maps the values of `iter` with `f`.
|
||||
|
|
@ -179,6 +180,9 @@ where
|
|||
#[stable(feature = "fused", since = "1.26.0")]
|
||||
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")]
|
||||
unsafe impl<B, I, F> TrustedLen for Map<I, F>
|
||||
where
|
||||
|
|
@ -228,4 +232,7 @@ where
|
|||
}
|
||||
|
||||
#[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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use crate::fmt;
|
||||
use crate::iter::{adapters::SourceIter, InPlaceIterable};
|
||||
use crate::num::NonZeroUsize;
|
||||
use crate::ops::{ControlFlow, Try};
|
||||
|
||||
/// An iterator that only accepts elements while `predicate` returns `Some(_)`.
|
||||
|
|
@ -82,7 +83,7 @@ where
|
|||
}
|
||||
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<B, I: InPlaceIterable, P> InPlaceIterable for MapWhile<I, P> where
|
||||
P: FnMut(I::Item) -> Option<B>
|
||||
{
|
||||
unsafe impl<I: InPlaceIterable, P> InPlaceIterable for MapWhile<I, P> {
|
||||
const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
|
||||
const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use crate::iter::{InPlaceIterable, Iterator};
|
||||
use crate::num::NonZeroUsize;
|
||||
use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try};
|
||||
|
||||
mod array_chunks;
|
||||
|
|
@ -119,8 +120,9 @@ pub unsafe trait SourceIter {
|
|||
///
|
||||
/// # 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.
|
||||
///
|
||||
/// Callers may only replace the reference when they stopped iteration and drop the
|
||||
/// iterator pipeline after extracting the source.
|
||||
///
|
||||
|
|
@ -228,7 +230,10 @@ where
|
|||
// 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.
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<I, T, R> InPlaceIterable for GenericShunt<'_, I, R> where
|
||||
I: Iterator<Item: Try<Output = T, Residual = R>> + InPlaceIterable
|
||||
unsafe impl<I, R> InPlaceIterable for GenericShunt<'_, I, R>
|
||||
where
|
||||
I: InPlaceIterable,
|
||||
{
|
||||
const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
|
||||
const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use crate::fmt;
|
||||
use crate::iter::{adapters::SourceIter, InPlaceIterable};
|
||||
use crate::num::NonZeroUsize;
|
||||
use crate::ops::{ControlFlow, Try};
|
||||
|
||||
/// An iterator to maintain state while iterating another iterator.
|
||||
|
|
@ -92,7 +93,7 @@ where
|
|||
}
|
||||
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<St, F, B, I: InPlaceIterable> InPlaceIterable for Scan<I, St, F> where
|
||||
F: FnMut(&mut St, I::Item) -> Option<B>
|
||||
{
|
||||
unsafe impl<St, F, I: InPlaceIterable> InPlaceIterable for Scan<I, St, F> {
|
||||
const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
|
||||
const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use crate::intrinsics::unlikely;
|
||||
use crate::iter::TrustedFused;
|
||||
use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable};
|
||||
use crate::num::NonZeroUsize;
|
||||
use crate::ops::{ControlFlow, Try};
|
||||
|
|
@ -214,6 +215,9 @@ where
|
|||
#[stable(feature = "fused", since = "1.26.0")]
|
||||
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")]
|
||||
unsafe impl<I> SourceIter for Skip<I>
|
||||
where
|
||||
|
|
@ -229,4 +233,7 @@ where
|
|||
}
|
||||
|
||||
#[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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
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;
|
||||
|
||||
/// 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")]
|
||||
unsafe impl<P, I> SourceIter for SkipWhile<I, P>
|
||||
where
|
||||
|
|
@ -119,7 +123,7 @@ where
|
|||
}
|
||||
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<I: InPlaceIterable, F> InPlaceIterable for SkipWhile<I, F> where
|
||||
F: FnMut(&I::Item) -> bool
|
||||
{
|
||||
unsafe impl<I: InPlaceIterable, F> InPlaceIterable for SkipWhile<I, F> {
|
||||
const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
|
||||
const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use crate::cmp;
|
||||
use crate::iter::{
|
||||
adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen, TrustedRandomAccess,
|
||||
adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedFused, TrustedLen,
|
||||
TrustedRandomAccess,
|
||||
};
|
||||
use crate::num::NonZeroUsize;
|
||||
use crate::ops::{ControlFlow, Try};
|
||||
|
|
@ -143,7 +144,10 @@ where
|
|||
}
|
||||
|
||||
#[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")]
|
||||
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")]
|
||||
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")]
|
||||
unsafe impl<I: TrustedLen> TrustedLen for Take<I> {}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
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};
|
||||
|
||||
/// 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")]
|
||||
unsafe impl<P, I> SourceIter for TakeWhile<I, P>
|
||||
where
|
||||
|
|
@ -120,7 +124,7 @@ where
|
|||
}
|
||||
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
unsafe impl<I: InPlaceIterable, F> InPlaceIterable for TakeWhile<I, F> where
|
||||
F: FnMut(&I::Item) -> bool
|
||||
{
|
||||
unsafe impl<I: InPlaceIterable, F> InPlaceIterable for TakeWhile<I, F> {
|
||||
const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY;
|
||||
const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use crate::cmp;
|
||||
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::num::NonZeroUsize;
|
||||
|
||||
/// An iterator that iterates two other iterators simultaneously.
|
||||
///
|
||||
|
|
@ -446,6 +447,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")]
|
||||
unsafe impl<A, B> TrustedLen for Zip<A, B>
|
||||
where
|
||||
|
|
@ -479,7 +488,10 @@ where
|
|||
|
||||
// Since SourceIter forwards the left hand side we do the same here
|
||||
#[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")]
|
||||
impl<A: Debug, B: Debug> Debug for Zip<A, B> {
|
||||
|
|
|
|||
|
|
@ -417,6 +417,8 @@ pub use self::sources::{successors, Successors};
|
|||
pub use self::traits::FusedIterator;
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
pub use self::traits::InPlaceIterable;
|
||||
#[unstable(issue = "none", feature = "trusted_fused")]
|
||||
pub use self::traits::TrustedFused;
|
||||
#[unstable(feature = "trusted_len", issue = "37572")]
|
||||
pub use self::traits::TrustedLen;
|
||||
#[unstable(feature = "trusted_step", issue = "85731")]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,16 @@
|
|||
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.
|
||||
///
|
||||
|
|
@ -14,6 +26,8 @@ use crate::iter::Step;
|
|||
/// [`Fuse`]: crate::iter::Fuse
|
||||
#[stable(feature = "fused", since = "1.26.0")]
|
||||
#[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 {}
|
||||
|
||||
#[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
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
#[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`].
|
||||
///
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ pub use self::{
|
|||
|
||||
#[unstable(issue = "none", feature = "inplace_iteration")]
|
||||
pub use self::marker::InPlaceIterable;
|
||||
#[unstable(issue = "none", feature = "trusted_fused")]
|
||||
pub use self::marker::TrustedFused;
|
||||
#[unstable(feature = "trusted_step", issue = "85731")]
|
||||
pub use self::marker::TrustedStep;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue