use effectful::{
environment::{Environment, NativeForm, DynBind},
bound::{Bool, IsSend, IsSync, Dynamic},
effective::Effective,
forward_send_sync,
};
use mockall::mock;
use treaty::{
any::{any_trait, OwnedStatic, TypeName},
protocol::{
visitor::{visit_value, Value, ValueProto, VisitResult},
AsVisitor, DynVisitor,
},
Flow,
};
use crate::common::Blocking;
mock! {
pub ValueVisitor<T: TypeName::MemberType<E>, E: Environment>
where
for<'a, 'ctx> TypeName::T<'a, 'ctx, T, E>: Sized
{
pub fn visit<'a, 'ctx>(&'a mut self, value: &TypeName::T<'a, 'ctx, T, E>) -> VisitResult<()>;
}
}
forward_send_sync!({} {} {T: (TypeName::MemberType<E>), E: (Environment)} MockValueVisitor<T, E> where {
for<'a, 'ctx> TypeName::T<'a, 'ctx, T, E>: Sized
});
any_trait! {
impl['ctx, T][E] MockValueVisitor<T, E> = [
ValueProto<T, E>
] where
T: TypeName::MemberType<E>,
for<'a, 'b> TypeName::T<'a, 'b, T, E>: Sized,
for<'a> Dynamic<TypeName::T<'a, 'ctx, T, E>>: DynBind<E>,
E: Environment,
}
impl<'ctx, T: TypeName::MemberType<E>, E: Environment> Value<'ctx, T, E> for MockValueVisitor<T, E>
where
for<'a, 'lt> TypeName::T<'a, 'lt, T, E>: Sized,
for<'a> Dynamic<TypeName::T<'a, 'ctx, T, E>>: DynBind<E>,
{
fn visit<'a>(
&'a mut self,
value: TypeName::T<'a, 'ctx, T, E>,
) -> NativeForm<'a, VisitResult<Dynamic<TypeName::T<'a, 'ctx, T, E>>>, E>
where
'ctx: 'a,
{
E::value(match self.visit(&value) {
VisitResult::Skipped(_) => VisitResult::Skipped(Dynamic(value)),
VisitResult::Control(flow) => VisitResult::Control(flow),
}).cast()
}
}
pub trait ValueVisitorExt<'ctx> {
fn visit_value_and_done<'a, T>(&'a mut self, value: T)
where
T: TypeName::LowerType<'a, 'ctx, Blocking>,
TypeName::HigherRanked<'a, 'ctx, T, Blocking>: TypeName::MemberType<Blocking>,
'ctx: 'a;
fn visit_value_and_skipped<'a, T>(&'a mut self, value: T)
where
T: TypeName::LowerType<'a, 'ctx, Blocking>,
TypeName::HigherRanked<'a, 'ctx, T, Blocking>: TypeName::MemberType<Blocking>,
'ctx: 'a;
}
impl<'ctx, U> ValueVisitorExt<'ctx> for U
where
U: AsVisitor<'ctx, Blocking>,
{
#[track_caller]
fn visit_value_and_done<'a, T>(&'a mut self, value: T)
where
T: TypeName::LowerType<'a, 'ctx, Blocking>,
TypeName::HigherRanked<'a, 'ctx, T, Blocking>: TypeName::MemberType<Blocking>,
'ctx: 'a,
{
let result = visit_value::<_, Blocking>(self.as_visitor(), value).into_value();
assert_eq!(result, VisitResult::Control(Flow::Done));
}
#[track_caller]
fn visit_value_and_skipped<'a, T>(&'a mut self, value: T)
where
T: TypeName::LowerType<'a, 'ctx, Blocking>,
TypeName::HigherRanked<'a, 'ctx, T, Blocking>: TypeName::MemberType<Blocking>,
'ctx: 'a,
{
let result = visit_value::<_, Blocking>(self.as_visitor(), value).into_value();
assert_eq!(result.unit_skipped(), VisitResult::Skipped(()));
}
}