//! Protocol for giving a hint to a walker. //! //! Sometimes a walker has multiple protocols it could use, //! this module gives a protocol by which a visitor can give a hint //! to the walker about what it is expecting. use core::ops::{Deref, DerefMut}; use effectful::{ effective::{Canonical, Effective}, environment::{Environment, InEnvironment}, higher_ranked::{Hrt, WithLt}, DynBind, SendSync, }; use crate::{ any::{type_name, AnyTrait}, hkt::Marker, protocol::{visitor::VisitResult, AnyTraitDynBind, DynVisitor, DynWalker}, }; /// Meta information for the hint. /// /// This gives the visitor more information to work from when selecting a hint. pub trait HintMeta: InEnvironment + type_name::Static { /// Information known by the walker. /// /// This should be information easy to get without changing the state of the walker /// in an irreversible way. type Known: Hrt; /// Extra information the visitor can give to the walker about what it is expecting. type Hint: Hrt; } /// Object implementing the [`Hint`] protocol. pub trait Hint<'src, Protocol: ?Sized + HintMeta>: DynBind where for<'r> WithLt<'r, Protocol::Hint>: Sized, for<'r> WithLt<'r, Protocol::Known>: DynBind + Sized, { /// Hint to the walker to use the `P` protocol. /// /// This should only be called once per [`RequestHint`]. fn hint<'r>( &'r mut self, visitor: DynVisitorWith<'r, 'src, Protocol>, hint: WithLt<'r, Protocol::Hint>, ) -> Canonical<'r, VisitResult, Protocol::Env>; /// Ask the walker for information about it's support of the protocol. fn known<'r>( &'r mut self, hint: &'r WithLt<'r, Protocol::Hint>, ) -> Canonical<'r, Result, ()>, Protocol::Env>; } #[derive(SendSync)] pub struct DynVisitorWith<'r, 'src, Protocol: ?Sized + HintMeta> { visitor: DynVisitor<'r, 'src, Protocol::Env>, _marker: Marker, } impl<'r, 'src, Protocol: ?Sized + HintMeta> DynVisitorWith<'r, 'src, Protocol> { pub fn new(visitor: &'r mut T) -> Self where T: AnyTraitDynBind<'src, Protocol::Env>, { Self { visitor: DynVisitor::new(visitor), _marker: Default::default(), } } pub fn as_known(&mut self) -> &mut type_name::Lowered<'_, 'src, Protocol> { self.visitor .upcast_mut::>() .unwrap() } pub fn into_inner(self) -> DynVisitor<'r, 'src, Protocol::Env> { self.visitor } } impl<'r, 'src, Protocol: ?Sized + HintMeta> Deref for DynVisitorWith<'r, 'src, Protocol> { type Target = DynVisitor<'r, 'src, Protocol::Env>; fn deref(&self) -> &Self::Target { &self.visitor } } impl<'r, 'src, Protocol: ?Sized + HintMeta> DerefMut for DynVisitorWith<'r, 'src, Protocol> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.visitor } } impl<'u, 'src, Protocol: ?Sized> type_name::Lower<'u, 'src, &'u &'src ()> for dyn Hint<'static, Protocol> where Protocol: HintMeta, { type Lowered = dyn Hint<'src, Protocol> + 'u; } impl<'u, 'src, Protocol: ?Sized> type_name::Raise<'u, 'src, &'u &'src ()> for dyn Hint<'src, Protocol> + 'u where Protocol: HintMeta, { type Raised = dyn Hint<'static, Protocol>; } pub fn hint_protocol<'r, 'src, Protocol: ?Sized + type_name::WithLt<'r, 'src>, E, T>( walker: DynWalker<'r, 'src, E>, visitor: &'r mut T, hint: WithLt<'r, as HintMeta>::Hint>, ) -> Canonical<'r, VisitResult<()>, E> where E: Environment, T: AnyTrait<'src> + DynBind, type_name::Raised<'r, 'src, Protocol>: HintMeta, for<'a> WithLt<'a, as HintMeta>::Hint>: Sized, for<'a> WithLt<'a, as HintMeta>::Known>: DynBind + Sized, { if let Some(object) = walker .into_inner() .as_any_trait_mut() .upcast_mut::> + 'r>() { object .hint(DynVisitorWith::new(visitor), hint) .map((), |_, x| Into::into(x)) .cast() } else { E::value(VisitResult::Skipped(())).cast() } }