Diffstat (limited to 'src/protocol/visitor/request_hint.rs')
-rw-r--r--src/protocol/visitor/request_hint.rs49
1 files changed, 36 insertions, 13 deletions
diff --git a/src/protocol/visitor/request_hint.rs b/src/protocol/visitor/request_hint.rs
index f1ab735..50ae76d 100644
--- a/src/protocol/visitor/request_hint.rs
+++ b/src/protocol/visitor/request_hint.rs
@@ -1,31 +1,54 @@
-use core::ops::ControlFlow;
-
use crate::{
effect::{Effect, Future},
nameable,
- protocol::Walker,
+ never::Never,
+ protocol::{Visitor, Walker},
+ Flow,
};
/// Protocol for requesting a hint from a visitor.
-pub trait RequestHint<'ctx> {
- type Effect: Effect<'ctx>;
-
+pub trait RequestHint<'ctx, E: Effect<'ctx>> {
/// Call this to request a hint.
///
/// `walker` is what the visitor (`self`) will call to give a hint using the
/// [`Hint`][crate::builtins::walker::Hint] protocol.
- fn request_hint<'a>(
- &'a mut self,
- walker: Walker<'a, 'ctx>,
- ) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect>
- where
- Self: 'a;
+ fn request_hint<'a>(&'a mut self, walker: Walker<'a, 'ctx>) -> Future<'a, 'ctx, Flow, E>;
}
+pub type DynRequestHint<'a, 'ctx, E> = dyn RequestHint<'ctx, E> + Send + 'a;
+
nameable! {
pub struct Name['a, 'ctx, E];
- impl [E] for dyn RequestHint<'ctx, Effect = E> + 'a where {
+ impl [E] for DynRequestHint<'a, 'ctx, E> where {
E: Effect<'ctx>,
'ctx: 'a
}
}
+
+/// Visit using the [`RequestHint`] protocol.
+///
+/// If `true` is returned then the walker should stop.
+/// This is either because of an error or the visitor is done.
+pub fn visit_request_hint<'a, 'ctx, E: Effect<'ctx>>(
+ visitor: Visitor<'a, 'ctx>,
+ walker: Walker<'a, 'ctx>,
+) -> Future<'a, 'ctx, bool, E> {
+ if let Some(object) = visitor.upcast_mut::<DynRequestHint<'_, 'ctx, E>>() {
+ // Allow the visitor to give a hint if it wants.
+ E::map(object.request_hint(walker), |flow| match flow {
+ Flow::Continue => {
+ // The visitor wants the walker to continue to it's normal
+ // walking.
+ false
+ }
+ _ => {
+ // The visitor is done (either because of an error or because
+ // it already used a hint).
+ true
+ }
+ })
+ } else {
+ // If the visitor doesn't support request hint then we continue.
+ E::ready(false)
+ }
+}