diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index 26661b20c12d6..7489a8bb6e74b 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -187,6 +187,80 @@ impl ControlFlow { } } + /// Converts the `ControlFlow` into an `Result` which is `Ok` if the + /// `ControlFlow` was `Break` and `Err` if otherwise. + /// + /// # Examples + /// + /// ``` + /// #![feature(control_flow_ok)] + /// + /// use std::ops::ControlFlow; + /// + /// struct TreeNode { + /// value: T, + /// left: Option>>, + /// right: Option>>, + /// } + /// + /// impl TreeNode { + /// fn find<'a>(&'a self, mut predicate: impl FnMut(&T) -> bool) -> Result<&'a T, ()> { + /// let mut f = |t: &'a T| -> ControlFlow<&'a T> { + /// if predicate(t) { + /// ControlFlow::Break(t) + /// } else { + /// ControlFlow::Continue(()) + /// } + /// }; + /// + /// self.traverse_inorder(&mut f).break_ok() + /// } + /// + /// fn traverse_inorder<'a, B>( + /// &'a self, + /// f: &mut impl FnMut(&'a T) -> ControlFlow, + /// ) -> ControlFlow { + /// if let Some(left) = &self.left { + /// left.traverse_inorder(f)?; + /// } + /// f(&self.value)?; + /// if let Some(right) = &self.right { + /// right.traverse_inorder(f)?; + /// } + /// ControlFlow::Continue(()) + /// } + /// + /// fn leaf(value: T) -> Option>> { + /// Some(Box::new(Self { + /// value, + /// left: None, + /// right: None, + /// })) + /// } + /// } + /// + /// let node = TreeNode { + /// value: 0, + /// left: TreeNode::leaf(1), + /// right: Some(Box::new(TreeNode { + /// value: -1, + /// left: TreeNode::leaf(5), + /// right: TreeNode::leaf(2), + /// })), + /// }; + /// + /// let res = node.find(|val: &i32| *val > 3); + /// assert_eq!(res, Ok(&5)); + /// ``` + #[inline] + #[unstable(feature = "control_flow_ok", issue = "140266")] + pub fn break_ok(self) -> Result { + match self { + ControlFlow::Continue(c) => Err(c), + ControlFlow::Break(b) => Ok(b), + } + } + /// Maps `ControlFlow` to `ControlFlow` by applying a function /// to the break value in case it exists. #[inline] @@ -218,6 +292,79 @@ impl ControlFlow { } } + /// Converts the `ControlFlow` into an `Result` which is `Ok` if the + /// `ControlFlow` was `Continue` and `Err` if otherwise. + /// + /// # Examples + /// + /// ``` + /// #![feature(control_flow_ok)] + /// + /// use std::ops::ControlFlow; + /// + /// struct TreeNode { + /// value: T, + /// left: Option>>, + /// right: Option>>, + /// } + /// + /// impl TreeNode { + /// fn validate(&self, f: &mut impl FnMut(&T) -> ControlFlow) -> Result<(), B> { + /// self.traverse_inorder(f).continue_ok() + /// } + /// + /// fn traverse_inorder(&self, f: &mut impl FnMut(&T) -> ControlFlow) -> ControlFlow { + /// if let Some(left) = &self.left { + /// left.traverse_inorder(f)?; + /// } + /// f(&self.value)?; + /// if let Some(right) = &self.right { + /// right.traverse_inorder(f)?; + /// } + /// ControlFlow::Continue(()) + /// } + /// + /// fn leaf(value: T) -> Option>> { + /// Some(Box::new(Self { + /// value, + /// left: None, + /// right: None, + /// })) + /// } + /// } + /// + /// let node = TreeNode { + /// value: 0, + /// left: TreeNode::leaf(1), + /// right: Some(Box::new(TreeNode { + /// value: -1, + /// left: TreeNode::leaf(5), + /// right: TreeNode::leaf(2), + /// })), + /// }; + /// + /// let res = node.validate(&mut |val| { + /// if *val < 0 { + /// return ControlFlow::Break("negative value detected"); + /// } + /// + /// if *val > 4 { + /// return ControlFlow::Break("too big value detected"); + /// } + /// + /// ControlFlow::Continue(()) + /// }); + /// assert_eq!(res, Err("too big value detected")); + /// ``` + #[inline] + #[unstable(feature = "control_flow_ok", issue = "140266")] + pub fn continue_ok(self) -> Result { + match self { + ControlFlow::Continue(c) => Ok(c), + ControlFlow::Break(b) => Err(b), + } + } + /// Maps `ControlFlow` to `ControlFlow` by applying a function /// to the continue value in case it exists. #[inline] diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 0a9c0c61c9584..a0c594d2d5961 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -22,6 +22,7 @@ #![feature(const_ref_cell)] #![feature(const_result_trait_fn)] #![feature(const_trait_impl)] +#![feature(control_flow_ok)] #![feature(core_float_math)] #![feature(core_intrinsics)] #![feature(core_intrinsics_fallbacks)] diff --git a/library/coretests/tests/ops/control_flow.rs b/library/coretests/tests/ops/control_flow.rs index eacfd63a6c48f..1df6599ac4a5a 100644 --- a/library/coretests/tests/ops/control_flow.rs +++ b/library/coretests/tests/ops/control_flow.rs @@ -16,3 +16,15 @@ fn control_flow_discriminants_match_result() { discriminant_value(&Result::::Ok(3)), ); } + +#[test] +fn control_flow_break_ok() { + assert_eq!(ControlFlow::::Break('b').break_ok(), Ok('b')); + assert_eq!(ControlFlow::::Continue(3).break_ok(), Err(3)); +} + +#[test] +fn control_flow_continue_ok() { + assert_eq!(ControlFlow::::Break('b').continue_ok(), Err('b')); + assert_eq!(ControlFlow::::Continue(3).continue_ok(), Ok(3)); +}