Skip to main content

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}