visit_flow/lib.rs
1use std::ops::ControlFlow;
2
3/// Controls whether children are visited after a `visit_*` method returns.
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum VisitAction {
6 /// Recurse into children (default).
7 Descend,
8 /// Skip recursing into children.
9 SkipChildren,
10}
11
12/// Controls early termination of the entire traversal.
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum VisitBreak {
15 /// Halt immediately; no further visits or exits.
16 Stop,
17}
18
19/// Convenience alias for the visitor control-flow type.
20pub type VisitFlow = ControlFlow<VisitBreak, VisitAction>;
21
22/// Named [`VisitFlow`] values.
23///
24/// `VisitFlow` is a type alias for [`ControlFlow`], so the canonical values are
25/// exposed as associated consts via this extension trait rather than inherent
26/// consts. Bringing the trait into scope lets you write `VisitFlow::DESCEND`,
27/// `VisitFlow::SKIP_CHILDREN`, and `VisitFlow::STOP`.
28pub trait VisitFlowExt {
29 /// Continue traversal and recurse into children.
30 const DESCEND: VisitFlow = ControlFlow::Continue(VisitAction::Descend);
31 /// Continue traversal but skip visiting children (`exit_*` still fires).
32 const SKIP_CHILDREN: VisitFlow = ControlFlow::Continue(VisitAction::SkipChildren);
33 /// Stop traversal immediately.
34 const STOP: VisitFlow = ControlFlow::Break(VisitBreak::Stop);
35}
36
37impl VisitFlowExt for VisitFlow {}
38
39/// Propagates a [`VisitFlow`]: on `Break`, returns early; on `Continue`, yields the [`VisitAction`].
40#[macro_export]
41macro_rules! try_visit {
42 ($e:expr) => {
43 match $e {
44 ::std::ops::ControlFlow::Continue(action) => action,
45 ::std::ops::ControlFlow::Break(r) => return ::std::ops::ControlFlow::Break(r),
46 }
47 };
48}