core/iter/adapters/
mod.rs

1#[cfg(not(feature = "ferrocene_subset"))]
2use crate::iter::InPlaceIterable;
3#[cfg(not(feature = "ferrocene_subset"))]
4use crate::num::NonZero;
5#[cfg(not(feature = "ferrocene_subset"))]
6use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try};
7
8#[cfg(not(feature = "ferrocene_subset"))]
9mod array_chunks;
10#[cfg(not(feature = "ferrocene_subset"))]
11mod by_ref_sized;
12mod chain;
13mod cloned;
14mod copied;
15#[cfg(not(feature = "ferrocene_subset"))]
16mod cycle;
17mod enumerate;
18mod filter;
19#[cfg(not(feature = "ferrocene_subset"))]
20mod filter_map;
21#[cfg(not(feature = "ferrocene_subset"))]
22mod flatten;
23#[cfg(not(feature = "ferrocene_subset"))]
24mod fuse;
25#[cfg(not(feature = "ferrocene_subset"))]
26mod inspect;
27#[cfg(not(feature = "ferrocene_subset"))]
28mod intersperse;
29mod map;
30#[cfg(not(feature = "ferrocene_subset"))]
31mod map_while;
32#[cfg(not(feature = "ferrocene_subset"))]
33mod map_windows;
34#[cfg(not(feature = "ferrocene_subset"))]
35mod peekable;
36mod rev;
37#[cfg(not(feature = "ferrocene_subset"))]
38mod scan;
39mod skip;
40#[cfg(not(feature = "ferrocene_subset"))]
41mod skip_while;
42mod step_by;
43mod take;
44#[cfg(not(feature = "ferrocene_subset"))]
45mod take_while;
46mod zip;
47
48#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
49#[cfg(not(feature = "ferrocene_subset"))]
50pub use self::array_chunks::ArrayChunks;
51#[unstable(feature = "std_internals", issue = "none")]
52#[cfg(not(feature = "ferrocene_subset"))]
53pub use self::by_ref_sized::ByRefSized;
54#[stable(feature = "iter_chain", since = "1.91.0")]
55#[cfg(not(feature = "ferrocene_subset"))]
56pub use self::chain::chain;
57#[stable(feature = "iter_cloned", since = "1.1.0")]
58pub use self::cloned::Cloned;
59#[stable(feature = "iter_copied", since = "1.36.0")]
60pub use self::copied::Copied;
61#[stable(feature = "iterator_flatten", since = "1.29.0")]
62#[cfg(not(feature = "ferrocene_subset"))]
63pub use self::flatten::Flatten;
64#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
65#[cfg(not(feature = "ferrocene_subset"))]
66pub use self::intersperse::{Intersperse, IntersperseWith};
67#[stable(feature = "iter_map_while", since = "1.57.0")]
68#[cfg(not(feature = "ferrocene_subset"))]
69pub use self::map_while::MapWhile;
70#[unstable(feature = "iter_map_windows", reason = "recently added", issue = "87155")]
71#[cfg(not(feature = "ferrocene_subset"))]
72pub use self::map_windows::MapWindows;
73#[stable(feature = "iterator_step_by", since = "1.28.0")]
74#[cfg(not(feature = "ferrocene_subset"))]
75pub use self::step_by::StepBy;
76#[unstable(feature = "trusted_random_access", issue = "none")]
77#[cfg(not(feature = "ferrocene_subset"))]
78pub use self::zip::TrustedRandomAccess;
79#[unstable(feature = "trusted_random_access", issue = "none")]
80#[cfg(not(feature = "ferrocene_subset"))]
81pub use self::zip::TrustedRandomAccessNoCoerce;
82#[stable(feature = "iter_zip", since = "1.59.0")]
83pub use self::zip::zip;
84#[stable(feature = "rust1", since = "1.0.0")]
85#[cfg(not(feature = "ferrocene_subset"))]
86pub use self::{
87    chain::Chain, cycle::Cycle, enumerate::Enumerate, filter::Filter, filter_map::FilterMap,
88    flatten::FlatMap, fuse::Fuse, inspect::Inspect, map::Map, peekable::Peekable, rev::Rev,
89    scan::Scan, skip::Skip, skip_while::SkipWhile, take::Take, take_while::TakeWhile, zip::Zip,
90};
91
92// Ferrocene addition: imports for certified subset
93#[stable(feature = "rust1", since = "1.0.0")]
94#[cfg(feature = "ferrocene_subset")]
95#[rustfmt::skip]
96pub use self::{
97    chain::Chain, enumerate::Enumerate, filter::Filter, map::Map, rev::Rev, skip::Skip,
98    step_by::StepBy, take::Take, zip::Zip,
99};
100
101/// This trait provides transitive access to source-stage in an iterator-adapter pipeline
102/// under the conditions that
103/// * the iterator source `S` itself implements `SourceIter<Source = S>`
104/// * there is a delegating implementation of this trait for each adapter in the pipeline between
105///   the source and the pipeline consumer.
106///
107/// When the source is an owning iterator struct (commonly called `IntoIter`) then
108/// this can be useful for specializing [`FromIterator`] implementations or recovering the
109/// remaining elements after an iterator has been partially exhausted.
110///
111/// Note that implementations do not necessarily have to provide access to the innermost
112/// source of a pipeline. A stateful intermediate adapter might eagerly evaluate a part
113/// of the pipeline and expose its internal storage as source.
114///
115/// The trait is unsafe because implementers must uphold additional safety properties.
116/// See [`as_inner`] for details.
117///
118/// The primary use of this trait is in-place iteration. Refer to the [`vec::in_place_collect`]
119/// module documentation for more information.
120///
121/// [`vec::in_place_collect`]: ../../../../alloc/vec/in_place_collect/index.html
122///
123/// # Examples
124///
125/// Retrieving a partially consumed source:
126///
127/// ```
128/// # #![feature(inplace_iteration)]
129/// # use std::iter::SourceIter;
130///
131/// let mut iter = vec![9, 9, 9].into_iter().map(|i| i * i);
132/// let _ = iter.next();
133/// let mut remainder = std::mem::replace(unsafe { iter.as_inner() }, Vec::new().into_iter());
134/// println!("n = {} elements remaining", remainder.len());
135/// ```
136///
137/// [`FromIterator`]: crate::iter::FromIterator
138/// [`as_inner`]: SourceIter::as_inner
139#[unstable(issue = "none", feature = "inplace_iteration")]
140#[doc(hidden)]
141#[rustc_specialization_trait]
142#[cfg(not(feature = "ferrocene_subset"))]
143pub unsafe trait SourceIter {
144    /// A source stage in an iterator pipeline.
145    type Source;
146
147    /// Retrieve the source of an iterator pipeline.
148    ///
149    /// # Safety
150    ///
151    /// Implementations must return the same mutable reference for their lifetime, unless
152    /// replaced by a caller.
153    ///
154    /// Callers may only replace the reference when they stopped iteration and drop the
155    /// iterator pipeline after extracting the source.
156    ///
157    /// This means iterator adapters can rely on the source not changing during
158    /// iteration but they cannot rely on it in their Drop implementations.
159    ///
160    /// Implementing this method means adapters relinquish private-only access to their
161    /// source and can only rely on guarantees made based on method receiver types.
162    /// The lack of restricted access also requires that adapters must uphold the source's
163    /// public API even when they have access to its internals.
164    ///
165    /// Callers in turn must expect the source to be in any state that is consistent with
166    /// its public API since adapters sitting between it and the source have the same
167    /// access. In particular an adapter may have consumed more elements than strictly necessary.
168    ///
169    /// The overall goal of these requirements is to let the consumer of a pipeline use
170    /// * whatever remains in the source after iteration has stopped
171    /// * the memory that has become unused by advancing a consuming iterator
172    ///
173    /// [`next()`]: Iterator::next()
174    unsafe fn as_inner(&mut self) -> &mut Self::Source;
175}
176
177/// An iterator adapter that produces output as long as the underlying
178/// iterator produces values where `Try::branch` says to `ControlFlow::Continue`.
179///
180/// If a `ControlFlow::Break` is encountered, the iterator stops and the
181/// residual is stored.
182#[cfg(not(feature = "ferrocene_subset"))]
183pub(crate) struct GenericShunt<'a, I, R> {
184    iter: I,
185    residual: &'a mut Option<R>,
186}
187
188/// Process the given iterator as if it yielded the item's `Try::Output`
189/// type instead. Any `Try::Residual`s encountered will stop the inner iterator
190/// and be propagated back to the overall result.
191#[cfg(not(feature = "ferrocene_subset"))]
192pub(crate) fn try_process<I, T, R, F, U>(iter: I, mut f: F) -> ChangeOutputType<I::Item, U>
193where
194    I: Iterator<Item: Try<Output = T, Residual = R>>,
195    for<'a> F: FnMut(GenericShunt<'a, I, R>) -> U,
196    R: Residual<U>,
197{
198    let mut residual = None;
199    let shunt = GenericShunt { iter, residual: &mut residual };
200    let value = f(shunt);
201    match residual {
202        Some(r) => FromResidual::from_residual(r),
203        None => Try::from_output(value),
204    }
205}
206
207#[cfg(not(feature = "ferrocene_subset"))]
208impl<I, R> Iterator for GenericShunt<'_, I, R>
209where
210    I: Iterator<Item: Try<Residual = R>>,
211{
212    type Item = <I::Item as Try>::Output;
213
214    fn next(&mut self) -> Option<Self::Item> {
215        self.try_for_each(ControlFlow::Break).break_value()
216    }
217
218    fn size_hint(&self) -> (usize, Option<usize>) {
219        if self.residual.is_some() {
220            (0, Some(0))
221        } else {
222            let (_, upper) = self.iter.size_hint();
223            (0, upper)
224        }
225    }
226
227    fn try_fold<B, F, T>(&mut self, init: B, mut f: F) -> T
228    where
229        F: FnMut(B, Self::Item) -> T,
230        T: Try<Output = B>,
231    {
232        self.iter
233            .try_fold(init, |acc, x| match Try::branch(x) {
234                ControlFlow::Continue(x) => ControlFlow::from_try(f(acc, x)),
235                ControlFlow::Break(r) => {
236                    *self.residual = Some(r);
237                    ControlFlow::Break(try { acc })
238                }
239            })
240            .into_try()
241    }
242
243    impl_fold_via_try_fold! { fold -> try_fold }
244}
245
246#[unstable(issue = "none", feature = "inplace_iteration")]
247#[cfg(not(feature = "ferrocene_subset"))]
248unsafe impl<I, R> SourceIter for GenericShunt<'_, I, R>
249where
250    I: SourceIter,
251{
252    type Source = I::Source;
253
254    #[inline]
255    unsafe fn as_inner(&mut self) -> &mut Self::Source {
256        // SAFETY: unsafe function forwarding to unsafe function with the same requirements
257        unsafe { SourceIter::as_inner(&mut self.iter) }
258    }
259}
260
261// SAFETY: GenericShunt::next calls `I::try_for_each`, which has to advance `iter`
262// in order to return `Some(_)`. Since `iter` has type `I: InPlaceIterable` it's
263// guaranteed that at least one item will be moved out from the underlying source.
264#[unstable(issue = "none", feature = "inplace_iteration")]
265#[cfg(not(feature = "ferrocene_subset"))]
266unsafe impl<I, R> InPlaceIterable for GenericShunt<'_, I, R>
267where
268    I: InPlaceIterable,
269{
270    const EXPAND_BY: Option<NonZero<usize>> = I::EXPAND_BY;
271    const MERGE_BY: Option<NonZero<usize>> = I::MERGE_BY;
272}