use core::ops::ControlFlow; /// Similar to the `Try` trait, but also implemented for `()`. pub trait VisitorResult { type Residual; fn output() -> Self; fn from_residual(residual: Self::Residual) -> Self; fn from_branch(b: ControlFlow) -> Self; fn branch(self) -> ControlFlow; } impl VisitorResult for () { #[cfg(feature = "nightly")] type Residual = !; #[cfg(not(feature = "nightly"))] type Residual = core::convert::Infallible; fn output() -> Self {} fn from_residual(_: Self::Residual) -> Self {} fn from_branch(_: ControlFlow) -> Self {} fn branch(self) -> ControlFlow { ControlFlow::Continue(()) } } impl VisitorResult for ControlFlow { type Residual = T; fn output() -> Self { ControlFlow::Continue(()) } fn from_residual(residual: Self::Residual) -> Self { ControlFlow::Break(residual) } fn from_branch(b: Self) -> Self { b } fn branch(self) -> Self { self } } #[macro_export] macro_rules! try_visit { ($e:expr) => { match $crate::visit::VisitorResult::branch($e) { core::ops::ControlFlow::Continue(()) => (), #[allow(unreachable_code)] core::ops::ControlFlow::Break(r) => { return $crate::visit::VisitorResult::from_residual(r); } } }; } #[macro_export] macro_rules! visit_opt { ($visitor: expr, $method: ident, $opt: expr $(, $($extra_args: expr),* )?) => { if let Some(x) = $opt { $crate::try_visit!($visitor.$method(x $(, $($extra_args,)* )?)); } } } #[macro_export] macro_rules! walk_list { ($visitor: expr, $method: ident, $list: expr $(, $($extra_args: expr),* )?) => { for elem in $list { $crate::try_visit!($visitor.$method(elem $(, $($extra_args,)* )?)); } } } #[macro_export] macro_rules! walk_visitable_list { ($visitor: expr, $list: expr $(, $($extra_args: expr),* )?) => { for elem in $list { $crate::try_visit!(elem.visit_with($visitor $(, $($extra_args,)* )?)); } } }