Skip to content

Commit 0c292c9

Browse files
committed
Auto merge of #93572 - scottmcm:generic-iter-process, r=yaahc
Change `ResultShunt` to be generic over `Try` Just a refactor (and rename) for now, so it's not `Result`-specific. This could be used for a future `Iterator::try_collect`, or similar, but anything like that is left for a future PR.
2 parents 775e480 + 413945e commit 0c292c9

File tree

6 files changed

+54
-48
lines changed

6 files changed

+54
-48
lines changed

library/core/src/iter/adapters/mod.rs

+38-40
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::iter::{InPlaceIterable, Iterator};
2-
use crate::ops::{ControlFlow, Try};
2+
use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, NeverShortCircuit, Residual, Try};
33

44
mod chain;
55
mod cloned;
@@ -128,59 +128,62 @@ pub unsafe trait SourceIter {
128128
}
129129

130130
/// An iterator adapter that produces output as long as the underlying
131-
/// iterator produces `Result::Ok` values.
131+
/// iterator produces values where `Try::branch` says to `ControlFlow::Continue`.
132132
///
133-
/// If an error is encountered, the iterator stops and the error is
134-
/// stored.
135-
pub(crate) struct ResultShunt<'a, I, E> {
133+
/// If a `ControlFlow::Break` is encountered, the iterator stops and the
134+
/// residual is stored.
135+
pub(crate) struct GenericShunt<'a, I, R> {
136136
iter: I,
137-
error: &'a mut Result<(), E>,
137+
residual: &'a mut Option<R>,
138138
}
139139

140-
/// Process the given iterator as if it yielded a `T` instead of a
141-
/// `Result<T, _>`. Any errors will stop the inner iterator and
142-
/// the overall result will be an error.
143-
pub(crate) fn process_results<I, T, E, F, U>(iter: I, mut f: F) -> Result<U, E>
140+
/// Process the given iterator as if it yielded a the item's `Try::Output`
141+
/// type instead. Any `Try::Residual`s encountered will stop the inner iterator
142+
/// and be propagated back to the overall result.
143+
pub(crate) fn try_process<I, T, R, F, U>(iter: I, mut f: F) -> ChangeOutputType<I::Item, U>
144144
where
145-
I: Iterator<Item = Result<T, E>>,
146-
for<'a> F: FnMut(ResultShunt<'a, I, E>) -> U,
145+
I: Iterator<Item: Try<Output = T, Residual = R>>,
146+
for<'a> F: FnMut(GenericShunt<'a, I, R>) -> U,
147+
R: Residual<U>,
147148
{
148-
let mut error = Ok(());
149-
let shunt = ResultShunt { iter, error: &mut error };
149+
let mut residual = None;
150+
let shunt = GenericShunt { iter, residual: &mut residual };
150151
let value = f(shunt);
151-
error.map(|()| value)
152+
match residual {
153+
Some(r) => FromResidual::from_residual(r),
154+
None => Try::from_output(value),
155+
}
152156
}
153157

154-
impl<I, T, E> Iterator for ResultShunt<'_, I, E>
158+
impl<I, R> Iterator for GenericShunt<'_, I, R>
155159
where
156-
I: Iterator<Item = Result<T, E>>,
160+
I: Iterator<Item: Try<Residual = R>>,
157161
{
158-
type Item = T;
162+
type Item = <I::Item as Try>::Output;
159163

160164
fn next(&mut self) -> Option<Self::Item> {
161-
self.find(|_| true)
165+
self.try_for_each(ControlFlow::Break).break_value()
162166
}
163167

164168
fn size_hint(&self) -> (usize, Option<usize>) {
165-
if self.error.is_err() {
169+
if self.residual.is_some() {
166170
(0, Some(0))
167171
} else {
168172
let (_, upper) = self.iter.size_hint();
169173
(0, upper)
170174
}
171175
}
172176

173-
fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
177+
fn try_fold<B, F, T>(&mut self, init: B, mut f: F) -> T
174178
where
175-
F: FnMut(B, Self::Item) -> R,
176-
R: Try<Output = B>,
179+
F: FnMut(B, Self::Item) -> T,
180+
T: Try<Output = B>,
177181
{
178-
let error = &mut *self.error;
179182
self.iter
180-
.try_fold(init, |acc, x| match x {
181-
Ok(x) => ControlFlow::from_try(f(acc, x)),
182-
Err(e) => {
183-
*error = Err(e);
183+
.try_fold(init, |acc, x| match Try::branch(x) {
184+
ControlFlow::Continue(x) => ControlFlow::from_try(f(acc, x)),
185+
ControlFlow::Break(r) => {
186+
*self.residual = Some(r);
184187
ControlFlow::Break(try { acc })
185188
}
186189
})
@@ -192,17 +195,12 @@ where
192195
Self: Sized,
193196
F: FnMut(B, Self::Item) -> B,
194197
{
195-
#[inline]
196-
fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
197-
move |acc, x| Ok(f(acc, x))
198-
}
199-
200-
self.try_fold(init, ok(fold)).unwrap()
198+
self.try_fold(init, NeverShortCircuit::wrap_mut_2(fold)).0
201199
}
202200
}
203201

204202
#[unstable(issue = "none", feature = "inplace_iteration")]
205-
unsafe impl<I, E> SourceIter for ResultShunt<'_, I, E>
203+
unsafe impl<I, R> SourceIter for GenericShunt<'_, I, R>
206204
where
207205
I: SourceIter,
208206
{
@@ -215,11 +213,11 @@ where
215213
}
216214
}
217215

218-
// SAFETY: ResultShunt::next calls I::find, which has to advance `iter` in order to
219-
// return `Some(_)`. Since `iter` has type `I: InPlaceIterable` it's guaranteed that
220-
// at least one item will be moved out from the underlying source.
216+
// SAFETY: GenericShunt::next calls `I::try_for_each`, which has to advance `iter`
217+
// in order to return `Some(_)`. Since `iter` has type `I: InPlaceIterable` it's
218+
// guaranteed that at least one item will be moved out from the underlying source.
221219
#[unstable(issue = "none", feature = "inplace_iteration")]
222-
unsafe impl<I, T, E> InPlaceIterable for ResultShunt<'_, I, E> where
223-
I: Iterator<Item = Result<T, E>> + InPlaceIterable
220+
unsafe impl<I, T, R> InPlaceIterable for GenericShunt<'_, I, R> where
221+
I: Iterator<Item: Try<Output = T, Residual = R>> + InPlaceIterable
224222
{
225223
}

library/core/src/iter/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,7 @@ pub use self::adapters::{
417417
#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
418418
pub use self::adapters::{Intersperse, IntersperseWith};
419419

420-
pub(crate) use self::adapters::process_results;
420+
pub(crate) use self::adapters::try_process;
421421

422422
mod adapters;
423423
mod range;

library/core/src/iter/traits/accum.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ where
167167
where
168168
I: Iterator<Item = Result<U, E>>,
169169
{
170-
iter::process_results(iter, |i| i.sum())
170+
iter::try_process(iter, |i| i.sum())
171171
}
172172
}
173173

@@ -183,7 +183,7 @@ where
183183
where
184184
I: Iterator<Item = Result<U, E>>,
185185
{
186-
iter::process_results(iter, |i| i.product())
186+
iter::try_process(iter, |i| i.product())
187187
}
188188
}
189189

@@ -210,7 +210,7 @@ where
210210
where
211211
I: Iterator<Item = Option<U>>,
212212
{
213-
iter.map(|x| x.ok_or(())).sum::<Result<_, _>>().ok()
213+
iter::try_process(iter, |i| i.sum())
214214
}
215215
}
216216

@@ -226,6 +226,6 @@ where
226226
where
227227
I: Iterator<Item = Option<U>>,
228228
{
229-
iter.map(|x| x.ok_or(())).product::<Result<_, _>>().ok()
229+
iter::try_process(iter, |i| i.product())
230230
}
231231
}

library/core/src/ops/try_trait.rs

+8
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,14 @@ pub(crate) type ChangeOutputType<T, V> = <<T as Try>::Residual as Residual<V>>::
359359
#[repr(transparent)]
360360
pub(crate) struct NeverShortCircuit<T>(pub T);
361361

362+
impl<T> NeverShortCircuit<T> {
363+
/// Wrap a binary `FnMut` to return its result wrapped in a `NeverShortCircuit`.
364+
#[inline]
365+
pub fn wrap_mut_2<A, B>(mut f: impl FnMut(A, B) -> T) -> impl FnMut(A, B) -> Self {
366+
move |a, b| NeverShortCircuit(f(a, b))
367+
}
368+
}
369+
362370
pub(crate) enum NeverShortCircuitResidual {}
363371

364372
impl<T> Try for NeverShortCircuit<T> {

library/core/src/option.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,7 @@
500500
501501
#![stable(feature = "rust1", since = "1.0.0")]
502502

503-
use crate::iter::{FromIterator, FusedIterator, TrustedLen};
503+
use crate::iter::{self, FromIterator, FusedIterator, TrustedLen};
504504
use crate::panicking::{panic, panic_str};
505505
use crate::pin::Pin;
506506
use crate::{
@@ -2233,7 +2233,7 @@ impl<A, V: FromIterator<A>> FromIterator<Option<A>> for Option<V> {
22332233
// FIXME(#11084): This could be replaced with Iterator::scan when this
22342234
// performance bug is closed.
22352235

2236-
iter.into_iter().map(|x| x.ok_or(())).collect::<Result<_, _>>().ok()
2236+
iter::try_process(iter.into_iter(), |i| i.collect())
22372237
}
22382238
}
22392239

library/core/src/result.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2016,7 +2016,7 @@ impl<A, E, V: FromIterator<A>> FromIterator<Result<A, E>> for Result<V, E> {
20162016
// FIXME(#11084): This could be replaced with Iterator::scan when this
20172017
// performance bug is closed.
20182018

2019-
iter::process_results(iter.into_iter(), |i| i.collect())
2019+
iter::try_process(iter.into_iter(), |i| i.collect())
20202020
}
20212021
}
20222022

0 commit comments

Comments
 (0)