//! [`Protocol`] for giving a visitor an owned value. //! //! In some sense, this is the most basic protocol. use effectful::{ effective::{Canonical, Effective}, environment::Environment, higher_ranked::{for_lt, Rank1}, DynBind, SendSync, }; use crate::{ any::type_name, protocol::{walker::hint::HintMeta, DynVisitor}, }; use super::VisitResult; /// Trait object for the [`Value`] protocol. /// /// Types implementing the [`Value`] protocol will implement this trait. pub trait Value<'src, T: ?Sized + type_name::Static, E: Environment>: DynBind { /// Visit a value of type `T`. /// /// Use this to give a value to a visitor. Its expected that a walker /// only calls this once per usage of the trait object, but that is not /// forced. /// /// If a [`ControlFlow::Break`] is returned then the walker /// should stop walking as soon as possible as there has likely been /// and error. fn visit<'r>( &'r mut self, value: type_name::Lowered<'r, 'src, T>, ) -> Canonical<'r, VisitResult>, E> where type_name::Lowered<'r, 'src, T>: Sized + DynBind; } impl<'u, 'src, T: ?Sized, E> type_name::Lower<'u, 'src, &'u &'src ()> for dyn Value<'static, T, E> where E: Environment, T: type_name::Static, { type Lowered = dyn Value<'src, T, E> + 'u; } impl<'u, 'src, T: ?Sized, E> type_name::Raise<'u, 'src, &'u &'src ()> for dyn Value<'src, T, E> + 'u where E: Environment, T: type_name::Static, { type Raised = dyn Value<'static, T, E>; } // This enrolls the Value protocol into the walker hint system. impl HintMeta for dyn Value<'static, T, E> where T: ?Sized + type_name::Static, { type Known = for_lt!(<'src> ValueKnown<'src, type_name::Lowered<'src, 'src, T>>); type Hint = Rank1<()>; } impl effectful::environment::InEnvironment for dyn Value<'static, T, E> { type Env = E; } #[derive(Copy, Clone, PartialEq, Debug, SendSync)] pub struct ValueKnown<'src, T: ?Sized> { /// A preview of the value. /// /// This can be used to inspect the value before committing to a visit. pub preview: Option<&'src T>, } pub fn visit_value<'r, 'src, T, E>( visitor: DynVisitor<'r, 'src, E>, value: T, ) -> Canonical<'r, VisitResult, E> where E: Environment, T: type_name::WithLt<'r, 'src> + DynBind, type_name::Raised<'r, 'src, T>: type_name::Static, { if let Some(object) = visitor .into_inner() .as_any_trait_mut() .upcast_mut::, E> + '_>() { // Allow the visitor to give a hint if it wants. object.visit(value) } else { // If the visitor doesn't support request hint then we continue. E::value(VisitResult::Skipped(value)).cast() } }