Diffstat (limited to 'src/protocol/visitor/request_hint.rs')
| -rw-r--r-- | src/protocol/visitor/request_hint.rs | 49 |
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) + } +} |