use effectful::{ effective::{Canonical, Effective}, environment::{Environment, InEnvironment}, higher_ranked::Rank1, DynBind, SendSync, }; use crate::{ any::type_name, protocol::{walker::hint::HintMeta, DynVisitor}, Flow, }; use super::VisitResult; /// Protocol for visiting a sequence. /// /// This protocol uses a scope to give temporary control to the visitor. /// The visitor will drive the walker for each item. pub trait Sequence<'src, E: Environment>: DynBind { fn visit<'r>( &'r mut self, scope: DynSequenceScope<'r, 'src, E>, ) -> Canonical<'r, VisitResult, E>; } impl<'u, 'src, E> type_name::Lower<'u, 'src, &'u &'src ()> for dyn Sequence<'static, E> where E: Environment, { type Lowered = dyn Sequence<'src, E> + 'u; } impl<'u, 'src, E> type_name::Raise<'u, 'src, &'u &'src ()> for dyn Sequence<'src, E> + 'u where E: Environment, { type Raised = dyn Sequence<'static, E>; } impl HintMeta for dyn Sequence<'static, E> { type Known = Rank1; type Hint = Rank1; } impl InEnvironment for dyn Sequence<'static, E> { type Env = E; } pub trait SequenceScope<'src, E: Environment>: DynBind { fn size_hint(&mut self) -> Canonical<'_, (usize, Option), E>; fn next<'r>(&'r mut self, visitor: DynVisitor<'r, 'src, E>) -> Canonical<'r, Flow, E>; } pub type DynSequenceScope<'r, 'src, E> = &'r mut dyn SequenceScope<'src, E>; #[derive(Default, SendSync)] pub struct SequenceKnown { pub len: (usize, Option), } #[derive(SendSync)] pub struct SequenceHint { pub len: (usize, Option), } #[inline(always)] pub fn visit_sequence<'r, 'src, E: Environment>( visitor: DynVisitor<'r, 'src, E>, scope: DynSequenceScope<'r, 'src, E>, ) -> Canonical<'r, VisitResult, E> { if let Some(object) = visitor .into_inner() .as_any_trait_mut() .upcast_mut:: + 'r>() { // Allow the visitor to walk the sequence scope. object.visit(scope) } else { // If the visitor doesn't support sequence then we continue. E::value(VisitResult::Skipped(())).cast() } }