use crate::{
effect::{Effect, Future},
higher_ranked_type,
hkt::AnySend,
nameable,
protocol::{walker::hint::HintMeta, Visitor},
Flow,
};
use super::Status;
pub trait Sequence<'ctx, E: Effect<'ctx>> {
fn visit<'a>(&'a mut self, scope: DynSequenceScope<'a, 'ctx, E>) -> Future<'a, 'ctx, Flow, E>;
}
pub type DynSequence<'a, 'ctx, E> = dyn Sequence<'ctx, E> + Send + 'a;
nameable! {
pub struct Name['ctx, E] for<'a>;
impl [E] for DynSequence<'a, 'ctx, E> where {
E: Effect<'ctx>,
}
}
pub trait SequenceScope<'ctx, E: Effect<'ctx>> {
fn size_hint<'a>(&'a mut self) -> Future<'a, 'ctx, (usize, Option<usize>), E>;
fn next<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, 'ctx, Flow, E>;
}
pub type DynSequenceScope<'a, 'ctx, E> = &'a mut (dyn SequenceScope<'ctx, E> + Send + 'a);
higher_ranked_type! {
pub type SequenceKnownHkt['ctx]: (AnySend) = for<'lt> SequenceKnown
}
#[derive(Default)]
pub struct SequenceKnown {
pub len: (usize, Option<usize>),
}
pub struct SequenceHint {
pub len: (usize, Option<usize>),
}
impl<'a, 'ctx: 'a, E: Effect<'ctx>> HintMeta<'ctx> for DynSequence<'a, 'ctx, E> {
type Known = SequenceKnownHkt<'ctx>;
type Hint = SequenceHint;
}
pub fn visit_sequence<'a, 'ctx, E: Effect<'ctx>>(
visitor: Visitor<'a, 'ctx>,
scope: DynSequenceScope<'a, 'ctx, E>,
) -> Future<'a, 'ctx, Status, E> {
if let Some(object) = visitor.upcast_mut::<DynSequence<'_, 'ctx, E>>() {
// Allow the visitor to give a hint if it wants.
E::map(object.visit(scope), |flow| match flow {
Flow::Continue => {
// The visitor wants the walker to continue to it's normal
// walking.
Status::r#continue()
}
Flow::Break | Flow::Done => {
// The visitor is done (either because of an error or because
// it already used a hint).
Status::r#break()
}
})
} else {
// If the visitor doesn't support request hint then we continue.
E::ready(Status::skipped())
}
}