1use core::ops::ControlFlow;
2
3pub trait VisitorResult {
5 type Residual;
6 fn output() -> Self;
7 fn from_residual(residual: Self::Residual) -> Self;
8 fn from_branch(b: ControlFlow<Self::Residual>) -> Self;
9 fn branch(self) -> ControlFlow<Self::Residual>;
10}
11
12impl VisitorResult for () {
13 #[cfg(feature = "nightly")]
14 type Residual = !;
15
16 #[cfg(not(feature = "nightly"))]
17 type Residual = core::convert::Infallible;
18
19 fn output() -> Self {}
20 fn from_residual(_: Self::Residual) -> Self {}
21 fn from_branch(_: ControlFlow<Self::Residual>) -> Self {}
22 fn branch(self) -> ControlFlow<Self::Residual> {
23 ControlFlow::Continue(())
24 }
25}
26
27impl<T> VisitorResult for ControlFlow<T> {
28 type Residual = T;
29
30 fn output() -> Self {
31 ControlFlow::Continue(())
32 }
33 fn from_residual(residual: Self::Residual) -> Self {
34 ControlFlow::Break(residual)
35 }
36 fn from_branch(b: Self) -> Self {
37 b
38 }
39 fn branch(self) -> Self {
40 self
41 }
42}
43
44impl<E> VisitorResult for Result<(), E> {
45 type Residual = E;
46
47 fn output() -> Self {
48 Ok(())
49 }
50 fn from_residual(residual: Self::Residual) -> Self {
51 Err(residual)
52 }
53 fn from_branch(b: ControlFlow<Self::Residual>) -> Self {
54 match b {
55 ControlFlow::Continue(()) => Ok(()),
56 ControlFlow::Break(e) => Err(e),
57 }
58 }
59 fn branch(self) -> ControlFlow<Self::Residual> {
60 match self {
61 Ok(()) => ControlFlow::Continue(()),
62 Err(e) => ControlFlow::Break(e),
63 }
64 }
65}
66
67#[macro_export]
68macro_rules! try_visit {
69 ($e:expr) => {
70 match $crate::visit::VisitorResult::branch($e) {
71 core::ops::ControlFlow::Continue(()) => (),
72 #[allow(unreachable_code)]
73 core::ops::ControlFlow::Break(r) => {
74 return $crate::visit::VisitorResult::from_residual(r);
75 }
76 }
77 };
78}
79
80#[macro_export]
81macro_rules! visit_opt {
82 ($visitor: expr, $method: ident, $opt: expr $(, $($extra_args: expr),* )?) => {
83 if let Some(x) = $opt {
84 $crate::try_visit!($visitor.$method(x $(, $($extra_args,)* )?));
85 }
86 }
87}
88
89#[macro_export]
90macro_rules! walk_list {
91 ($visitor: expr, $method: ident, $list: expr $(, $($extra_args: expr),* )?) => {
92 for elem in $list {
93 $crate::try_visit!($visitor.$method(elem $(, $($extra_args,)* )?));
94 }
95 }
96}
97
98#[macro_export]
99macro_rules! walk_visitable_list {
100 ($visitor: expr, $list: expr $(, $($extra_args: expr),* )?) => {
101 for elem in $list {
102 $crate::try_visit!(elem.visit_with($visitor $(, $($extra_args,)* )?));
103 }
104 }
105}