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:
commit
d059f2619f
6 changed files with 119 additions and 100 deletions
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(()) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
67
library/core/src/ops/control_flow.rs
Normal file
67
library/core/src/ops/control_flow.rs
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue