Skip to content

Commit b0fc38a

Browse files
authored
Rollup merge of #140267 - jogru0:control_flow, r=dtolnay
implement continue_ok and break_ok for ControlFlow Tracking issue: #140266 r? ``````@dtolnay``````
2 parents 1cd368a + b981b84 commit b0fc38a

File tree

3 files changed

+160
-0
lines changed

3 files changed

+160
-0
lines changed

library/core/src/ops/control_flow.rs

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,80 @@ impl<B, C> ControlFlow<B, C> {
187187
}
188188
}
189189

190+
/// Converts the `ControlFlow` into an `Result` which is `Ok` if the
191+
/// `ControlFlow` was `Break` and `Err` if otherwise.
192+
///
193+
/// # Examples
194+
///
195+
/// ```
196+
/// #![feature(control_flow_ok)]
197+
///
198+
/// use std::ops::ControlFlow;
199+
///
200+
/// struct TreeNode<T> {
201+
/// value: T,
202+
/// left: Option<Box<TreeNode<T>>>,
203+
/// right: Option<Box<TreeNode<T>>>,
204+
/// }
205+
///
206+
/// impl<T> TreeNode<T> {
207+
/// fn find<'a>(&'a self, mut predicate: impl FnMut(&T) -> bool) -> Result<&'a T, ()> {
208+
/// let mut f = |t: &'a T| -> ControlFlow<&'a T> {
209+
/// if predicate(t) {
210+
/// ControlFlow::Break(t)
211+
/// } else {
212+
/// ControlFlow::Continue(())
213+
/// }
214+
/// };
215+
///
216+
/// self.traverse_inorder(&mut f).break_ok()
217+
/// }
218+
///
219+
/// fn traverse_inorder<'a, B>(
220+
/// &'a self,
221+
/// f: &mut impl FnMut(&'a T) -> ControlFlow<B>,
222+
/// ) -> ControlFlow<B> {
223+
/// if let Some(left) = &self.left {
224+
/// left.traverse_inorder(f)?;
225+
/// }
226+
/// f(&self.value)?;
227+
/// if let Some(right) = &self.right {
228+
/// right.traverse_inorder(f)?;
229+
/// }
230+
/// ControlFlow::Continue(())
231+
/// }
232+
///
233+
/// fn leaf(value: T) -> Option<Box<TreeNode<T>>> {
234+
/// Some(Box::new(Self {
235+
/// value,
236+
/// left: None,
237+
/// right: None,
238+
/// }))
239+
/// }
240+
/// }
241+
///
242+
/// let node = TreeNode {
243+
/// value: 0,
244+
/// left: TreeNode::leaf(1),
245+
/// right: Some(Box::new(TreeNode {
246+
/// value: -1,
247+
/// left: TreeNode::leaf(5),
248+
/// right: TreeNode::leaf(2),
249+
/// })),
250+
/// };
251+
///
252+
/// let res = node.find(|val: &i32| *val > 3);
253+
/// assert_eq!(res, Ok(&5));
254+
/// ```
255+
#[inline]
256+
#[unstable(feature = "control_flow_ok", issue = "140266")]
257+
pub fn break_ok(self) -> Result<B, C> {
258+
match self {
259+
ControlFlow::Continue(c) => Err(c),
260+
ControlFlow::Break(b) => Ok(b),
261+
}
262+
}
263+
190264
/// Maps `ControlFlow<B, C>` to `ControlFlow<T, C>` by applying a function
191265
/// to the break value in case it exists.
192266
#[inline]
@@ -218,6 +292,79 @@ impl<B, C> ControlFlow<B, C> {
218292
}
219293
}
220294

295+
/// Converts the `ControlFlow` into an `Result` which is `Ok` if the
296+
/// `ControlFlow` was `Continue` and `Err` if otherwise.
297+
///
298+
/// # Examples
299+
///
300+
/// ```
301+
/// #![feature(control_flow_ok)]
302+
///
303+
/// use std::ops::ControlFlow;
304+
///
305+
/// struct TreeNode<T> {
306+
/// value: T,
307+
/// left: Option<Box<TreeNode<T>>>,
308+
/// right: Option<Box<TreeNode<T>>>,
309+
/// }
310+
///
311+
/// impl<T> TreeNode<T> {
312+
/// fn validate<B>(&self, f: &mut impl FnMut(&T) -> ControlFlow<B>) -> Result<(), B> {
313+
/// self.traverse_inorder(f).continue_ok()
314+
/// }
315+
///
316+
/// fn traverse_inorder<B>(&self, f: &mut impl FnMut(&T) -> ControlFlow<B>) -> ControlFlow<B> {
317+
/// if let Some(left) = &self.left {
318+
/// left.traverse_inorder(f)?;
319+
/// }
320+
/// f(&self.value)?;
321+
/// if let Some(right) = &self.right {
322+
/// right.traverse_inorder(f)?;
323+
/// }
324+
/// ControlFlow::Continue(())
325+
/// }
326+
///
327+
/// fn leaf(value: T) -> Option<Box<TreeNode<T>>> {
328+
/// Some(Box::new(Self {
329+
/// value,
330+
/// left: None,
331+
/// right: None,
332+
/// }))
333+
/// }
334+
/// }
335+
///
336+
/// let node = TreeNode {
337+
/// value: 0,
338+
/// left: TreeNode::leaf(1),
339+
/// right: Some(Box::new(TreeNode {
340+
/// value: -1,
341+
/// left: TreeNode::leaf(5),
342+
/// right: TreeNode::leaf(2),
343+
/// })),
344+
/// };
345+
///
346+
/// let res = node.validate(&mut |val| {
347+
/// if *val < 0 {
348+
/// return ControlFlow::Break("negative value detected");
349+
/// }
350+
///
351+
/// if *val > 4 {
352+
/// return ControlFlow::Break("too big value detected");
353+
/// }
354+
///
355+
/// ControlFlow::Continue(())
356+
/// });
357+
/// assert_eq!(res, Err("too big value detected"));
358+
/// ```
359+
#[inline]
360+
#[unstable(feature = "control_flow_ok", issue = "140266")]
361+
pub fn continue_ok(self) -> Result<C, B> {
362+
match self {
363+
ControlFlow::Continue(c) => Ok(c),
364+
ControlFlow::Break(b) => Err(b),
365+
}
366+
}
367+
221368
/// Maps `ControlFlow<B, C>` to `ControlFlow<B, T>` by applying a function
222369
/// to the continue value in case it exists.
223370
#[inline]

library/coretests/tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#![feature(const_ref_cell)]
2323
#![feature(const_result_trait_fn)]
2424
#![feature(const_trait_impl)]
25+
#![feature(control_flow_ok)]
2526
#![feature(core_float_math)]
2627
#![feature(core_intrinsics)]
2728
#![feature(core_intrinsics_fallbacks)]

library/coretests/tests/ops/control_flow.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,15 @@ fn control_flow_discriminants_match_result() {
1616
discriminant_value(&Result::<i32, i32>::Ok(3)),
1717
);
1818
}
19+
20+
#[test]
21+
fn control_flow_break_ok() {
22+
assert_eq!(ControlFlow::<char, i32>::Break('b').break_ok(), Ok('b'));
23+
assert_eq!(ControlFlow::<char, i32>::Continue(3).break_ok(), Err(3));
24+
}
25+
26+
#[test]
27+
fn control_flow_continue_ok() {
28+
assert_eq!(ControlFlow::<char, i32>::Break('b').continue_ok(), Err('b'));
29+
assert_eq!(ControlFlow::<char, i32>::Continue(3).continue_ok(), Ok(3));
30+
}

0 commit comments

Comments
 (0)