1
use crate::{convert, ops};
2

            
3
/// Used to tell an operation whether it should exit early or go on as usual.
4
///
5
/// This is used when exposing things (like graph traversals or visitors) where
6
/// you want the user to be able to choose whether to exit early.
7
/// Having the enum makes it clearer -- no more wondering "wait, what did `false`
8
/// mean again?" -- and allows including a value.
9
///
10
/// Similar to [`Option`] and [`Result`], this enum can be used with the `?` operator
11
/// to return immediately if the [`Break`] variant is present or otherwise continue normally
12
/// with the value inside the [`Continue`] variant.
13
///
14
/// # Examples
15
///
16
/// Early-exiting from [`Iterator::try_for_each`]:
17
/// ```
18
/// use std::ops::ControlFlow;
19
///
20
/// let r = (2..100).try_for_each(|x| {
21
///     if 403 % x == 0 {
22
///         return ControlFlow::Break(x)
23
///     }
24
///
25
///     ControlFlow::Continue(())
26
/// });
27
/// assert_eq!(r, ControlFlow::Break(13));
28
/// ```
29
///
30
/// A basic tree traversal:
31
/// ```
32
/// use std::ops::ControlFlow;
33
///
34
/// pub struct TreeNode<T> {
35
///     value: T,
36
///     left: Option<Box<TreeNode<T>>>,
37
///     right: Option<Box<TreeNode<T>>>,
38
/// }
39
///
40
/// impl<T> TreeNode<T> {
41
///     pub fn traverse_inorder<B>(&self, f: &mut impl FnMut(&T) -> ControlFlow<B>) -> ControlFlow<B> {
42
///         if let Some(left) = &self.left {
43
///             left.traverse_inorder(f)?;
44
///         }
45
///         f(&self.value)?;
46
///         if let Some(right) = &self.right {
47
///             right.traverse_inorder(f)?;
48
///         }
49
///         ControlFlow::Continue(())
50
///     }
51
///     fn leaf(value: T) -> Option<Box<TreeNode<T>>> {
52
///         Some(Box::new(Self { value, left: None, right: None }))
53
///     }
54
/// }
55
///
56
/// let node = TreeNode {
57
///     value: 0,
58
///     left: TreeNode::leaf(1),
59
///     right: Some(Box::new(TreeNode {
60
///         value: -1,
61
///         left: TreeNode::leaf(5),
62
///         right: TreeNode::leaf(2),
63
///     }))
64
/// };
65
/// let mut sum = 0;
66
///
67
/// let res = node.traverse_inorder(&mut |val| {
68
///     if *val < 0 {
69
///         ControlFlow::Break(*val)
70
///     } else {
71
///         sum += *val;
72
///         ControlFlow::Continue(())
73
///     }
74
/// });
75
/// assert_eq!(res, ControlFlow::Break(-1));
76
/// assert_eq!(sum, 6);
77
/// ```
78
///
79
/// [`Break`]: ControlFlow::Break
80
/// [`Continue`]: ControlFlow::Continue
81
#[stable(feature = "control_flow_enum_type", since = "1.55.0")]
82
#[rustc_diagnostic_item = "ControlFlow"]
83
#[must_use]
84
// ControlFlow should not implement PartialOrd or Ord, per RFC 3058:
85
// https://rust-lang.github.io/rfcs/3058-try-trait-v2.html#traits-for-controlflow
86
#[cfg_attr(not(feature = "ferrocene_certified"), derive(Debug, Clone, Copy, PartialEq, Eq, Hash))]
87
pub enum ControlFlow<B, C = ()> {
88
    /// Move on to the next phase of the operation as normal.
89
    #[stable(feature = "control_flow_enum_type", since = "1.55.0")]
90
    #[lang = "Continue"]
91
    Continue(C),
92
    /// Exit the operation without running subsequent phases.
93
    #[stable(feature = "control_flow_enum_type", since = "1.55.0")]
94
    #[lang = "Break"]
95
    Break(B),
96
    // Yes, the order of the variants doesn't match the type parameters.
97
    // They're in this order so that `ControlFlow<A, B>` <-> `Result<B, A>`
98
    // is a no-op conversion in the `Try` implementation.
99
}
100

            
101
#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
102
#[rustc_const_unstable(feature = "const_try", issue = "74935")]
103
impl<B, C> const ops::Try for ControlFlow<B, C> {
104
    type Output = C;
105
    type Residual = ControlFlow<B, convert::Infallible>;
106

            
107
    #[inline]
108
18394
    fn from_output(output: Self::Output) -> Self {
109
18394
        ControlFlow::Continue(output)
110
18394
    }
111

            
112
    #[inline]
113
10690387
    fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
114
10690387
        match self {
115
10688428
            ControlFlow::Continue(c) => ControlFlow::Continue(c),
116
1959
            ControlFlow::Break(b) => ControlFlow::Break(ControlFlow::Break(b)),
117
        }
118
10690387
    }
119
}
120

            
121
#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
122
#[rustc_const_unstable(feature = "const_try", issue = "74935")]
123
// Note: manually specifying the residual type instead of using the default to work around
124
// https://github.com/rust-lang/rust/issues/99940
125
impl<B, C> const ops::FromResidual<ControlFlow<B, convert::Infallible>> for ControlFlow<B, C> {
126
    #[inline]
127
1959
    fn from_residual(residual: ControlFlow<B, convert::Infallible>) -> Self {
128
1959
        match residual {
129
1959
            ControlFlow::Break(b) => ControlFlow::Break(b),
130
        }
131
1959
    }
132
}
133

            
134
#[unstable(feature = "try_trait_v2_residual", issue = "91285")]
135
impl<B, C> ops::Residual<C> for ControlFlow<B, convert::Infallible> {
136
    type TryType = ControlFlow<B, C>;
137
}
138

            
139
impl<B, C> ControlFlow<B, C> {
140
    /// Returns `true` if this is a `Break` variant.
141
    ///
142
    /// # Examples
143
    ///
144
    /// ```
145
    /// use std::ops::ControlFlow;
146
    ///
147
    /// assert!(ControlFlow::<&str, i32>::Break("Stop right there!").is_break());
148
    /// assert!(!ControlFlow::<&str, i32>::Continue(3).is_break());
149
    /// ```
150
    #[inline]
151
    #[stable(feature = "control_flow_enum_is", since = "1.59.0")]
152
    pub fn is_break(&self) -> bool {
153
        matches!(*self, ControlFlow::Break(_))
154
    }
155

            
156
    /// Returns `true` if this is a `Continue` variant.
157
    ///
158
    /// # Examples
159
    ///
160
    /// ```
161
    /// use std::ops::ControlFlow;
162
    ///
163
    /// assert!(!ControlFlow::<&str, i32>::Break("Stop right there!").is_continue());
164
    /// assert!(ControlFlow::<&str, i32>::Continue(3).is_continue());
165
    /// ```
166
    #[inline]
167
    #[stable(feature = "control_flow_enum_is", since = "1.59.0")]
168
    pub fn is_continue(&self) -> bool {
169
        matches!(*self, ControlFlow::Continue(_))
170
    }
171

            
172
    /// Converts the `ControlFlow` into an `Option` which is `Some` if the
173
    /// `ControlFlow` was `Break` and `None` otherwise.
174
    ///
175
    /// # Examples
176
    ///
177
    /// ```
178
    /// use std::ops::ControlFlow;
179
    ///
180
    /// assert_eq!(ControlFlow::<&str, i32>::Break("Stop right there!").break_value(), Some("Stop right there!"));
181
    /// assert_eq!(ControlFlow::<&str, i32>::Continue(3).break_value(), None);
182
    /// ```
183
    #[inline]
184
    #[stable(feature = "control_flow_enum", since = "1.83.0")]
185
918
    pub fn break_value(self) -> Option<B> {
186
918
        match self {
187
4
            ControlFlow::Continue(..) => None,
188
914
            ControlFlow::Break(x) => Some(x),
189
        }
190
918
    }
191

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

            
266
    /// Maps `ControlFlow<B, C>` to `ControlFlow<T, C>` by applying a function
267
    /// to the break value in case it exists.
268
    #[inline]
269
    #[stable(feature = "control_flow_enum", since = "1.83.0")]
270
300000
    pub fn map_break<T>(self, f: impl FnOnce(B) -> T) -> ControlFlow<T, C> {
271
300000
        match self {
272
300000
            ControlFlow::Continue(x) => ControlFlow::Continue(x),
273
            ControlFlow::Break(x) => ControlFlow::Break(f(x)),
274
        }
275
300000
    }
276

            
277
    /// Converts the `ControlFlow` into an `Option` which is `Some` if the
278
    /// `ControlFlow` was `Continue` and `None` otherwise.
279
    ///
280
    /// # Examples
281
    ///
282
    /// ```
283
    /// use std::ops::ControlFlow;
284
    ///
285
    /// assert_eq!(ControlFlow::<&str, i32>::Break("Stop right there!").continue_value(), None);
286
    /// assert_eq!(ControlFlow::<&str, i32>::Continue(3).continue_value(), Some(3));
287
    /// ```
288
    #[inline]
289
    #[stable(feature = "control_flow_enum", since = "1.83.0")]
290
    pub fn continue_value(self) -> Option<C> {
291
        match self {
292
            ControlFlow::Continue(x) => Some(x),
293
            ControlFlow::Break(..) => None,
294
        }
295
    }
296

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

            
370
    /// Maps `ControlFlow<B, C>` to `ControlFlow<B, T>` by applying a function
371
    /// to the continue value in case it exists.
372
    #[inline]
373
    #[stable(feature = "control_flow_enum", since = "1.83.0")]
374
    pub fn map_continue<T>(self, f: impl FnOnce(C) -> T) -> ControlFlow<B, T> {
375
        match self {
376
            ControlFlow::Continue(x) => ControlFlow::Continue(f(x)),
377
            ControlFlow::Break(x) => ControlFlow::Break(x),
378
        }
379
    }
380
}
381

            
382
impl<T> ControlFlow<T, T> {
383
    /// Extracts the value `T` that is wrapped by `ControlFlow<T, T>`.
384
    ///
385
    /// # Examples
386
    ///
387
    /// ```
388
    /// #![feature(control_flow_into_value)]
389
    /// use std::ops::ControlFlow;
390
    ///
391
    /// assert_eq!(ControlFlow::<i32, i32>::Break(1024).into_value(), 1024);
392
    /// assert_eq!(ControlFlow::<i32, i32>::Continue(512).into_value(), 512);
393
    /// ```
394
    #[unstable(feature = "control_flow_into_value", issue = "137461")]
395
    #[rustc_allow_const_fn_unstable(const_precise_live_drops)]
396
    pub const fn into_value(self) -> T {
397
        match self {
398
            ControlFlow::Continue(x) | ControlFlow::Break(x) => x,
399
        }
400
    }
401
}
402

            
403
/// These are used only as part of implementing the iterator adapters.
404
/// They have mediocre names and non-obvious semantics, so aren't
405
/// currently on a path to potential stabilization.
406
#[cfg(not(feature = "ferrocene_certified"))]
407
impl<R: ops::Try> ControlFlow<R, R::Output> {
408
    /// Creates a `ControlFlow` from any type implementing `Try`.
409
    #[inline]
410
10353560
    pub(crate) fn from_try(r: R) -> Self {
411
10353560
        match R::branch(r) {
412
10352686
            ControlFlow::Continue(v) => ControlFlow::Continue(v),
413
874
            ControlFlow::Break(v) => ControlFlow::Break(R::from_residual(v)),
414
        }
415
10353560
    }
416

            
417
    /// Converts a `ControlFlow` into any type implementing `Try`.
418
    #[inline]
419
949
    pub(crate) fn into_try(self) -> R {
420
949
        match self {
421
10
            ControlFlow::Continue(v) => R::from_output(v),
422
939
            ControlFlow::Break(v) => v,
423
        }
424
949
    }
425
}