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 { /// 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 Try for ControlFlow { type Ok = C; type Error = B; #[inline] fn into_result(self) -> Result { 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 ControlFlow { /// Returns `true` if this is a `Break` variant. #[inline] #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] pub fn is_break(&self) -> bool { matches!(*self, ControlFlow::Break(_)) } /// Returns `true` if this is a `Continue` variant. #[inline] #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] pub fn is_continue(&self) -> bool { matches!(*self, ControlFlow::Continue(_)) } /// 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 { match self { ControlFlow::Continue(..) => None, ControlFlow::Break(x) => Some(x), } } } impl ControlFlow { /// 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, } } } impl ControlFlow { /// It's frequently the case that there's no value needed with `Continue`, /// so this provides a way to avoid typing `(())`, if you prefer it. /// /// # Examples /// /// ``` /// #![feature(control_flow_enum)] /// use std::ops::ControlFlow; /// /// let mut partial_sum = 0; /// let last_used = (1..10).chain(20..25).try_for_each(|x| { /// partial_sum += x; /// if partial_sum > 100 { ControlFlow::Break(x) } /// else { ControlFlow::CONTINUE } /// }); /// assert_eq!(last_used.break_value(), Some(22)); /// ``` #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] pub const CONTINUE: Self = ControlFlow::Continue(()); } impl ControlFlow<(), C> { /// APIs like `try_for_each` don't need values with `Break`, /// so this provides a way to avoid typing `(())`, if you prefer it. /// /// # Examples /// /// ``` /// #![feature(control_flow_enum)] /// use std::ops::ControlFlow; /// /// let mut partial_sum = 0; /// (1..10).chain(20..25).try_for_each(|x| { /// if partial_sum > 100 { ControlFlow::BREAK } /// else { partial_sum += x; ControlFlow::CONTINUE } /// }); /// assert_eq!(partial_sum, 108); /// ``` #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] pub const BREAK: Self = ControlFlow::Break(()); }