Rollup merge of #76204 - NoraCodes:nora/control_flow_enum, r=scottmcm

Rename and expose LoopState as ControlFlow

Basic PR for #75744. Addresses everything there except for documentation; lots of examples are probably a good idea.
This commit is contained in:
Dylan DPC 2020-09-03 02:22:07 +02:00 committed by GitHub
commit d059f2619f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 119 additions and 100 deletions

View file

@ -1,9 +1,9 @@
use crate::cmp;
use crate::fmt;
use crate::intrinsics;
use crate::ops::{Add, AddAssign, Try};
use crate::ops::{Add, AddAssign, ControlFlow, Try};
use super::{from_fn, LoopState};
use super::from_fn;
use super::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator, TrustedLen};
mod chain;
@ -1164,10 +1164,10 @@ where
#[inline]
fn find<T, B>(
f: &mut impl FnMut(T) -> Option<B>,
) -> impl FnMut((), T) -> LoopState<(), B> + '_ {
) -> impl FnMut((), T) -> ControlFlow<(), B> + '_ {
move |(), x| match f(x) {
Some(x) => LoopState::Break(x),
None => LoopState::Continue(()),
Some(x) => ControlFlow::Break(x),
None => ControlFlow::Continue(()),
}
}
@ -1864,13 +1864,13 @@ where
flag: &'a mut bool,
p: &'a mut impl FnMut(&T) -> bool,
mut fold: impl FnMut(Acc, T) -> R + 'a,
) -> impl FnMut(Acc, T) -> LoopState<Acc, R> + 'a {
) -> impl FnMut(Acc, T) -> ControlFlow<Acc, R> + 'a {
move |acc, x| {
if p(&x) {
LoopState::from_try(fold(acc, x))
ControlFlow::from_try(fold(acc, x))
} else {
*flag = true;
LoopState::Break(Try::from_ok(acc))
ControlFlow::Break(Try::from_ok(acc))
}
}
}
@ -1963,8 +1963,8 @@ where
{
let Self { iter, predicate } = self;
iter.try_fold(init, |acc, x| match predicate(x) {
Some(item) => LoopState::from_try(fold(acc, item)),
None => LoopState::Break(Try::from_ok(acc)),
Some(item) => ControlFlow::from_try(fold(acc, item)),
None => ControlFlow::Break(Try::from_ok(acc)),
})
.into_try()
}
@ -2135,11 +2135,11 @@ where
fn check<T, Acc, R: Try<Ok = Acc>>(
mut n: usize,
mut fold: impl FnMut(Acc, T) -> R,
) -> impl FnMut(Acc, T) -> LoopState<Acc, R> {
) -> impl FnMut(Acc, T) -> ControlFlow<Acc, R> {
move |acc, x| {
n -= 1;
let r = fold(acc, x);
if n == 0 { LoopState::Break(r) } else { LoopState::from_try(r) }
if n == 0 { ControlFlow::Break(r) } else { ControlFlow::from_try(r) }
}
}
@ -2246,11 +2246,11 @@ where
fn check<'a, T, Acc, R: Try<Ok = Acc>>(
n: &'a mut usize,
mut fold: impl FnMut(Acc, T) -> R + 'a,
) -> impl FnMut(Acc, T) -> LoopState<Acc, R> + 'a {
) -> impl FnMut(Acc, T) -> ControlFlow<Acc, R> + 'a {
move |acc, x| {
*n -= 1;
let r = fold(acc, x);
if *n == 0 { LoopState::Break(r) } else { LoopState::from_try(r) }
if *n == 0 { ControlFlow::Break(r) } else { ControlFlow::from_try(r) }
}
}
@ -2414,10 +2414,10 @@ where
state: &'a mut St,
f: &'a mut impl FnMut(&mut St, T) -> Option<B>,
mut fold: impl FnMut(Acc, B) -> R + 'a,
) -> impl FnMut(Acc, T) -> LoopState<Acc, R> + 'a {
) -> impl FnMut(Acc, T) -> ControlFlow<Acc, R> + 'a {
move |acc, x| match f(state, x) {
None => LoopState::Break(Try::from_ok(acc)),
Some(x) => LoopState::from_try(fold(acc, x)),
None => ControlFlow::Break(Try::from_ok(acc)),
Some(x) => ControlFlow::from_try(fold(acc, x)),
}
}
@ -2638,10 +2638,10 @@ where
let error = &mut *self.error;
self.iter
.try_fold(init, |acc, x| match x {
Ok(x) => LoopState::from_try(f(acc, x)),
Ok(x) => ControlFlow::from_try(f(acc, x)),
Err(e) => {
*error = Err(e);
LoopState::Break(Try::from_ok(acc))
ControlFlow::Break(Try::from_ok(acc))
}
})
.into_try()

View file

@ -308,8 +308,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
use crate::ops::Try;
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::traits::Iterator;
@ -367,57 +365,3 @@ mod adapters;
mod range;
mod sources;
mod traits;
/// Used to make try_fold closures more like normal loops
#[derive(PartialEq)]
enum LoopState<C, B> {
Continue(C),
Break(B),
}
impl<C, B> Try for LoopState<C, B> {
type Ok = C;
type Error = B;
#[inline]
fn into_result(self) -> Result<Self::Ok, Self::Error> {
match self {
LoopState::Continue(y) => Ok(y),
LoopState::Break(x) => Err(x),
}
}
#[inline]
fn from_error(v: Self::Error) -> Self {
LoopState::Break(v)
}
#[inline]
fn from_ok(v: Self::Ok) -> Self {
LoopState::Continue(v)
}
}
impl<C, B> LoopState<C, B> {
#[inline]
fn break_value(self) -> Option<B> {
match self {
LoopState::Continue(..) => None,
LoopState::Break(x) => Some(x),
}
}
}
impl<R: Try> LoopState<R::Ok, R> {
#[inline]
fn from_try(r: R) -> Self {
match Try::into_result(r) {
Ok(v) => LoopState::Continue(v),
Err(v) => LoopState::Break(Try::from_error(v)),
}
}
#[inline]
fn into_try(self) -> R {
match self {
LoopState::Continue(v) => Try::from_ok(v),
LoopState::Break(v) => v,
}
}
}

View file

@ -1,5 +1,4 @@
use crate::iter::LoopState;
use crate::ops::Try;
use crate::ops::{ControlFlow, Try};
/// An iterator able to yield elements from both ends.
///
@ -309,9 +308,9 @@ pub trait DoubleEndedIterator: Iterator {
#[inline]
fn check<T>(
mut predicate: impl FnMut(&T) -> bool,
) -> impl FnMut((), T) -> LoopState<(), T> {
) -> impl FnMut((), T) -> ControlFlow<(), T> {
move |(), x| {
if predicate(&x) { LoopState::Break(x) } else { LoopState::Continue(()) }
if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::Continue(()) }
}
}

View file

@ -3,9 +3,8 @@
// can't split that into multiple files.
use crate::cmp::{self, Ordering};
use crate::ops::{Add, Try};
use crate::ops::{Add, ControlFlow, Try};
use super::super::LoopState;
use super::super::TrustedRandomAccess;
use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse};
use super::super::{FlatMap, Flatten};
@ -2088,12 +2087,12 @@ pub trait Iterator {
F: FnMut(Self::Item) -> bool,
{
#[inline]
fn check<T>(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> LoopState<(), ()> {
fn check<T>(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<(), ()> {
move |(), x| {
if f(x) { LoopState::Continue(()) } else { LoopState::Break(()) }
if f(x) { ControlFlow::Continue(()) } else { ControlFlow::Break(()) }
}
}
self.try_fold((), check(f)) == LoopState::Continue(())
self.try_fold((), check(f)) == ControlFlow::Continue(())
}
/// Tests if any element of the iterator matches a predicate.
@ -2141,13 +2140,13 @@ pub trait Iterator {
F: FnMut(Self::Item) -> bool,
{
#[inline]
fn check<T>(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> LoopState<(), ()> {
fn check<T>(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<(), ()> {
move |(), x| {
if f(x) { LoopState::Break(()) } else { LoopState::Continue(()) }
if f(x) { ControlFlow::Break(()) } else { ControlFlow::Continue(()) }
}
}
self.try_fold((), check(f)) == LoopState::Break(())
self.try_fold((), check(f)) == ControlFlow::Break(())
}
/// Searches for an element of an iterator that satisfies a predicate.
@ -2203,9 +2202,9 @@ pub trait Iterator {
#[inline]
fn check<T>(
mut predicate: impl FnMut(&T) -> bool,
) -> impl FnMut((), T) -> LoopState<(), T> {
) -> impl FnMut((), T) -> ControlFlow<(), T> {
move |(), x| {
if predicate(&x) { LoopState::Break(x) } else { LoopState::Continue(()) }
if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::Continue(()) }
}
}
@ -2235,10 +2234,12 @@ pub trait Iterator {
F: FnMut(Self::Item) -> Option<B>,
{
#[inline]
fn check<T, B>(mut f: impl FnMut(T) -> Option<B>) -> impl FnMut((), T) -> LoopState<(), B> {
fn check<T, B>(
mut f: impl FnMut(T) -> Option<B>,
) -> impl FnMut((), T) -> ControlFlow<(), B> {
move |(), x| match f(x) {
Some(x) => LoopState::Break(x),
None => LoopState::Continue(()),
Some(x) => ControlFlow::Break(x),
None => ControlFlow::Continue(()),
}
}
@ -2274,15 +2275,15 @@ pub trait Iterator {
R: Try<Ok = bool>,
{
#[inline]
fn check<F, T, R>(mut f: F) -> impl FnMut((), T) -> LoopState<(), Result<T, R::Error>>
fn check<F, T, R>(mut f: F) -> impl FnMut((), T) -> ControlFlow<(), Result<T, R::Error>>
where
F: FnMut(&T) -> R,
R: Try<Ok = bool>,
{
move |(), x| match f(&x).into_result() {
Ok(false) => LoopState::Continue(()),
Ok(true) => LoopState::Break(Ok(x)),
Err(x) => LoopState::Break(Err(x)),
Ok(false) => ControlFlow::Continue(()),
Ok(true) => ControlFlow::Break(Ok(x)),
Err(x) => ControlFlow::Break(Err(x)),
}
}
@ -2352,10 +2353,14 @@ pub trait Iterator {
#[inline]
fn check<T>(
mut predicate: impl FnMut(T) -> bool,
) -> impl FnMut(usize, T) -> LoopState<usize, usize> {
) -> impl FnMut(usize, T) -> ControlFlow<usize, usize> {
// The addition might panic on overflow
move |i, x| {
if predicate(x) { LoopState::Break(i) } else { LoopState::Continue(Add::add(i, 1)) }
if predicate(x) {
ControlFlow::Break(i)
} else {
ControlFlow::Continue(Add::add(i, 1))
}
}
}
@ -2411,10 +2416,10 @@ pub trait Iterator {
#[inline]
fn check<T>(
mut predicate: impl FnMut(T) -> bool,
) -> impl FnMut(usize, T) -> LoopState<usize, usize> {
) -> impl FnMut(usize, T) -> ControlFlow<usize, usize> {
move |i, x| {
let i = i - 1;
if predicate(x) { LoopState::Break(i) } else { LoopState::Continue(i) }
if predicate(x) { ControlFlow::Break(i) } else { ControlFlow::Continue(i) }
}
}

View file

@ -0,0 +1,67 @@
use crate::ops::Try;
/// Used to make try_fold closures more like normal loops
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ControlFlow<C, B> {
/// Continue in the loop, using the given value for the next iteration
Continue(C),
/// Exit the loop, yielding the given value
Break(B),
}
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
impl<C, B> Try for ControlFlow<C, B> {
type Ok = C;
type Error = B;
#[inline]
fn into_result(self) -> Result<Self::Ok, Self::Error> {
match self {
ControlFlow::Continue(y) => Ok(y),
ControlFlow::Break(x) => Err(x),
}
}
#[inline]
fn from_error(v: Self::Error) -> Self {
ControlFlow::Break(v)
}
#[inline]
fn from_ok(v: Self::Ok) -> Self {
ControlFlow::Continue(v)
}
}
impl<C, B> ControlFlow<C, B> {
/// Converts the `ControlFlow` into an `Option` which is `Some` if the
/// `ControlFlow` was `Break` and `None` otherwise.
#[inline]
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
pub fn break_value(self) -> Option<B> {
match self {
ControlFlow::Continue(..) => None,
ControlFlow::Break(x) => Some(x),
}
}
}
impl<R: Try> ControlFlow<R::Ok, R> {
/// Create a `ControlFlow` from any type implementing `Try`.
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
#[inline]
pub fn from_try(r: R) -> Self {
match Try::into_result(r) {
Ok(v) => ControlFlow::Continue(v),
Err(v) => ControlFlow::Break(Try::from_error(v)),
}
}
/// Convert a `ControlFlow` into any type implementing `Try`;
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
#[inline]
pub fn into_try(self) -> R {
match self {
ControlFlow::Continue(v) => Try::from_ok(v),
ControlFlow::Break(v) => v,
}
}
}

View file

@ -140,6 +140,7 @@
mod arith;
mod bit;
mod control_flow;
mod deref;
mod drop;
mod function;
@ -191,3 +192,6 @@ pub use self::unsize::CoerceUnsized;
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
pub use self::unsize::DispatchFromDyn;
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
pub use self::control_flow::ControlFlow;