added more tests, rustc ICE
37 files changed, 1096 insertions, 613 deletions
@@ -1 +1,3 @@ /target +/target-bisector-* +rustc-ice-* @@ -100,7 +100,7 @@ higher_ranked_type! { /// /// // Cast to be a AnyTrait trait object. /// // Now we don't know the type. -/// let anything: &(dyn AnyTrait<'_> + Send) = &my_num; +/// let anything: &(dyn AnyTrait<'_> + Send + Sync) = &my_num; /// /// // We can still upcast to an impl of ToNum. /// let to_num_object: &dyn ToNum = anything.upcast::<DynToNum>().unwrap(); @@ -173,7 +173,7 @@ pub trait AnyTrait<'ctx> { 'ctx: 'a; } -impl<'b, 'ctx: 'b> dyn AnyTrait<'ctx> + Send + 'b { +impl<'b, 'ctx: 'b> dyn AnyTrait<'ctx> + Send + Sync + 'b { /// Upcast a borrow to the given trait object type. /// /// This should be used instead of [`upcast_to_id`][AnyTrait::upcast_to_id] @@ -407,7 +407,9 @@ mod test { let z = 42; let x = X(&z); - let y = (&x as &(dyn AnyTrait<'_> + Send)).upcast::<DynZ>().unwrap(); + let y = (&x as &(dyn AnyTrait<'_> + Send + Sync)) + .upcast::<DynZ>() + .unwrap(); assert_eq!(y.get(), 42); } diff --git a/src/build.rs b/src/build.rs index f4476f0..716b882 100644 --- a/src/build.rs +++ b/src/build.rs @@ -2,23 +2,23 @@ pub mod builders; use crate::{ effect::{Effect, Future}, - protocol::Visitor, + protocol::DynVisitor, }; /// A buildable type. -pub trait Build<'ctx, M, E: Effect>: BuilderTypes<Value = Self> + Send { +pub trait Build<'ctx, M, E: Effect>: BuilderTypes<Value = Self> + Send + Sync { /// The builder that can be used to build a value of `Self`. type Builder: Builder<'ctx, E, Seed = Self::Seed, Error = Self::Error, Value = Self>; } pub trait BuilderTypes { - type Seed: Send; + type Seed: Send + Sync; /// Error that can happen during filling the builder with data. - type Error: Send; + type Error: Send + Sync; /// Type to be built. - type Value: Send; + type Value: Send + Sync; } /// Builder for a type. @@ -34,7 +34,7 @@ pub trait BuilderTypes { /// the builder with data from it's walk. /// - Call [`Self::build()`] to finish building the value and get any errors /// that happened during filling it with data. -pub trait Builder<'ctx, E: Effect>: BuilderTypes + Sized + Send { +pub trait Builder<'ctx, E: Effect>: BuilderTypes + Sized + Send + Sync { fn from_seed<'a>(seed: Self::Seed) -> Future<'a, Self, E> where Self: 'a; @@ -50,5 +50,5 @@ pub trait Builder<'ctx, E: Effect>: BuilderTypes + Sized + Send { /// Get the builder as a visitor that a walker can use. /// /// This is expected to just be `self`. - fn as_visitor(&mut self) -> Visitor<'_, 'ctx>; + fn as_visitor(&mut self) -> DynVisitor<'_, 'ctx>; } diff --git a/src/build/builders/core/bool.rs b/src/build/builders/core/bool.rs index f122e8a..29b6ab0 100644 --- a/src/build/builders/core/bool.rs +++ b/src/build/builders/core/bool.rs @@ -6,7 +6,7 @@ use crate::{ effect::{Effect, Future}, protocol::{ visitor::{Value, ValueProto, VisitResult}, - Visitor, + DynVisitor, }, Flow, }; @@ -54,8 +54,8 @@ impl<'ctx, E: Effect> crate::Builder<'ctx, E> for Builder<E> { E::wrap(core::future::ready(Self(None, PhantomData))) } - fn as_visitor(&mut self) -> Visitor<'_, 'ctx> { - self + fn as_visitor(&mut self) -> DynVisitor<'_, 'ctx> { + DynVisitor(self) } } diff --git a/src/build/builders/debug.rs b/src/build/builders/debug.rs index b7331a1..cb447b6 100644 --- a/src/build/builders/debug.rs +++ b/src/build/builders/debug.rs @@ -5,14 +5,13 @@ use crate::{ any_trait, effect::{Effect, Future}, protocol::{ - self, - visitor::{ + self, visitor::{ DynSequenceScope, RequestHint, RequestHintProto, Sequence, Tag, TagDyn, TagProto, Value, ValueProto, VisitResult, - }, + }, DynVisitor }, - protocol::{visitor::SequenceProto, Walker}, - DynWalker, Flow, + protocol::{visitor::SequenceProto, DynWalker}, + DynWalkerObjSafe, Flow, }; pub struct Visitor<E>(usize, PhantomData<fn() -> E>); @@ -59,8 +58,8 @@ impl<E: Effect> Visitor<E> { impl<'ctx, E: Effect> RequestHint<'ctx, E> for Visitor<E> { fn request_hint<'a>( &'a mut self, - _walker: Walker<'a, 'ctx>, - ) -> Future<'a, VisitResult<Walker<'a, 'ctx>>, E> { + _walker: DynWalker<'a, 'ctx>, + ) -> Future<'a, VisitResult<DynWalker<'a, 'ctx>>, E> { // self.tab(); // println!("Visit request hint (no hint given)"); // println!("Visit request hint (hint for recoverable)"); @@ -72,8 +71,8 @@ impl<'ctx, E: Effect> Tag<'ctx, TagDyn, E> for Visitor<E> { fn visit<'a>( &'a mut self, kind: TagDyn, - walker: DynWalker<'a, 'ctx, E>, - ) -> Future<'a, VisitResult<DynWalker<'a, 'ctx, E>>, E> { + walker: DynWalkerObjSafe<'a, 'ctx, E>, + ) -> Future<'a, VisitResult<DynWalkerObjSafe<'a, 'ctx, E>>, E> { E::wrap(async move { match kind.0 { crate::TAG_TYPE_NAME => { @@ -81,7 +80,7 @@ impl<'ctx, E: Effect> Tag<'ctx, TagDyn, E> for Visitor<E> { println!("type name:"); self.0 += 1; - let _ = walker.walk(self).await; + let _ = walker.walk(DynVisitor(self)).await; self.0 -= 1; Flow::Continue.into() @@ -91,7 +90,7 @@ impl<'ctx, E: Effect> Tag<'ctx, TagDyn, E> for Visitor<E> { println!("key:"); self.0 += 1; - let _ = walker.walk(self).await; + let _ = walker.walk(DynVisitor(self)).await; self.0 -= 1; Flow::Continue.into() @@ -101,7 +100,7 @@ impl<'ctx, E: Effect> Tag<'ctx, TagDyn, E> for Visitor<E> { println!("value:"); self.0 += 1; - let _ = walker.walk(self).await; + let _ = walker.walk(DynVisitor(self)).await; self.0 -= 1; Flow::Continue.into() @@ -199,7 +198,7 @@ impl<'ctx, E: Effect> Sequence<'ctx, E> for Visitor<E> { println!("{}:", index); self.0 += 1; - match scope.next(self).await { + match scope.next(DynVisitor(self)).await { Flow::Done => { self.tab(); println!("<end>"); diff --git a/src/effect.rs b/src/effect.rs index 1d10cbc..cf8cbdd 100644 --- a/src/effect.rs +++ b/src/effect.rs @@ -111,7 +111,7 @@ pub struct Ready<Output> { } impl<Output> Ready<Output> { - pub fn into_innter(self) -> Output { + pub fn into_inner(self) -> Output { self.value.expect("`into_inner` called after completion") } } diff --git a/src/protocol.rs b/src/protocol.rs index 33d73be..822d827 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -55,7 +55,50 @@ pub mod visitor; pub mod walker; +use core::ops::{Deref, DerefMut}; + use crate::any::AnyTrait; -pub type Visitor<'a, 'ctx> = &'a mut (dyn AnyTrait<'ctx> + Send + 'a); -pub type Walker<'a, 'ctx> = &'a mut (dyn AnyTrait<'ctx> + Send + 'a); +pub struct DynVisitor<'a, 'ctx>(pub &'a mut (dyn AnyTrait<'ctx> + Send + Sync + 'a)); + +impl<'a, 'ctx> DynVisitor<'a, 'ctx> { + pub fn cast<'b>(&'b mut self) -> DynVisitor<'b, 'ctx> { + DynVisitor(&mut *self.0) + } +} + +impl<'a, 'ctx> Deref for DynVisitor<'a, 'ctx> { + type Target = dyn AnyTrait<'ctx> + Send + Sync + 'a; + + fn deref(&self) -> &Self::Target { + &*self.0 + } +} + +impl<'a, 'ctx> DerefMut for DynVisitor<'a, 'ctx> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut *self.0 + } +} + +pub struct DynWalker<'a, 'ctx>(pub &'a mut (dyn AnyTrait<'ctx> + Send + Sync + 'a)); + +impl<'a, 'ctx> DynWalker<'a, 'ctx> { + pub fn cast<'b>(&'b mut self) -> DynVisitor<'b, 'ctx> { + DynVisitor(&mut *self.0) + } +} + +impl<'a, 'ctx> Deref for DynWalker<'a, 'ctx> { + type Target = dyn AnyTrait<'ctx> + Send + Sync + 'a; + + fn deref(&self) -> &Self::Target { + &*self.0 + } +} + +impl<'a, 'ctx> DerefMut for DynWalker<'a, 'ctx> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut *self.0 + } +} diff --git a/src/protocol/visitor/recoverable.rs b/src/protocol/visitor/recoverable.rs index 4c9c604..b0d14de 100644 --- a/src/protocol/visitor/recoverable.rs +++ b/src/protocol/visitor/recoverable.rs @@ -4,8 +4,8 @@ use crate::{ higher_ranked_type, hkt::Marker, protocol::{ - walker::hint::{HintKnown, HintMeta}, - Visitor, + walker::hint::{HintMeta, Meta}, + DynVisitor, }, Status, }; @@ -38,7 +38,7 @@ higher_ranked_type! { } pub trait RecoverableScope<'ctx, E: Effect> { - fn new_walk<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, Status, E>; + fn new_walk<'a>(&'a mut self, visitor: DynVisitor<'a, 'ctx>) -> Future<'a, Status, E>; } pub type DynRecoverableScope<'a, 'ctx, E> = @@ -47,7 +47,7 @@ pub type DynRecoverableScope<'a, 'ctx, E> = pub struct RecoverableKnown; higher_ranked_type! { - impl HintKnown { + impl Meta { impl['a, 'ctx] type T['a, 'ctx] for RecoverableKnown = RecoverableKnown; @@ -60,13 +60,15 @@ impl<E: Effect> HintMeta for RecoverableProto<E> { type Known = RecoverableKnown; type Hint = (); + + type Effect = E; } pub fn visit_recoverable<'a, 'ctx, E: Effect>( - visitor: Visitor<'a, 'ctx>, + visitor: DynVisitor<'a, 'ctx>, scope: DynRecoverableScope<'a, 'ctx, E>, ) -> Future<'a, VisitResult<DynRecoverableScope<'a, 'ctx, E>>, E> { - if let Some(object) = visitor.upcast_mut::<RecoverableProto<E>>() { + if let Some(object) = visitor.0.upcast_mut::<RecoverableProto<E>>() { // Allow the visitor to give a hint if it wants. object.visit(scope) } else { diff --git a/src/protocol/visitor/request_hint.rs b/src/protocol/visitor/request_hint.rs index c2f8837..1e699a1 100644 --- a/src/protocol/visitor/request_hint.rs +++ b/src/protocol/visitor/request_hint.rs @@ -3,7 +3,7 @@ use crate::{ effect::{Effect, Future}, higher_ranked_type, hkt::Marker, - protocol::{Visitor, Walker}, + protocol::{DynVisitor, DynWalker}, }; use super::VisitResult; @@ -16,8 +16,8 @@ pub trait RequestHint<'ctx, E: Effect> { /// [`Hint`][crate::builtins::walker::Hint] protocol. fn request_hint<'a>( &'a mut self, - walker: Walker<'a, 'ctx>, - ) -> Future<'a, VisitResult<Walker<'a, 'ctx>>, E>; + walker: DynWalker<'a, 'ctx>, + ) -> Future<'a, VisitResult<DynWalker<'a, 'ctx>>, E>; } pub struct RequestHintProto<E: Effect>(Marker<E>); @@ -46,10 +46,10 @@ higher_ranked_type! { /// should stop walking. /// If [`Flow::Break`] is returned then there was an error and the walker should stop walking. pub fn visit_request_hint<'a, 'ctx, E: Effect>( - visitor: Visitor<'a, 'ctx>, - walker: Walker<'a, 'ctx>, -) -> Future<'a, VisitResult<Walker<'a, 'ctx>>, E> { - if let Some(object) = visitor.upcast_mut::<RequestHintProto<E>>() { + visitor: DynVisitor<'a, 'ctx>, + walker: DynWalker<'a, 'ctx>, +) -> Future<'a, VisitResult<DynWalker<'a, 'ctx>>, E> { + if let Some(object) = visitor.0.upcast_mut::<RequestHintProto<E>>() { // Allow the visitor to give a hint if it wants. object.request_hint(walker) } else { diff --git a/src/protocol/visitor/sequence.rs b/src/protocol/visitor/sequence.rs index afa6f9c..ef0c5e9 100644 --- a/src/protocol/visitor/sequence.rs +++ b/src/protocol/visitor/sequence.rs @@ -4,14 +4,18 @@ use crate::{ higher_ranked_type, hkt::Marker, protocol::{ - walker::hint::{HintKnown, HintMeta}, - Visitor, + walker::hint::{HintMeta, Meta}, + 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<'ctx, E: Effect> { fn visit<'a>( &'a mut self, @@ -40,13 +44,18 @@ higher_ranked_type! { pub trait SequenceScope<'ctx, E: Effect> { fn size_hint(&mut self) -> Future<'_, (usize, Option<usize>), E>; - fn next<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, Flow, E>; + fn next<'a>(&'a mut self, visitor: DynVisitor<'a, 'ctx>) -> Future<'a, Flow, E>; } pub type DynSequenceScope<'a, 'ctx, E> = &'a mut (dyn SequenceScope<'ctx, E> + Send + Sync + 'a); +#[derive(Default)] +pub struct SequenceKnown { + pub len: (usize, Option<usize>), +} + higher_ranked_type! { - impl HintKnown { + impl Meta { impl['a, 'ctx] type T['a, 'ctx] for SequenceKnown = SequenceKnown; @@ -55,26 +64,33 @@ higher_ranked_type! { } } -#[derive(Default)] -pub struct SequenceKnown { +pub struct SequenceHint { pub len: (usize, Option<usize>), } -pub struct SequenceHint { - pub len: (usize, Option<usize>), +higher_ranked_type! { + impl Meta { + impl['a, 'ctx] type T['a, 'ctx] for SequenceHint = + SequenceHint; + + impl['a, 'ctx] type HigherRanked['a, 'ctx] for SequenceHint = + SequenceHint; + } } impl<E: Effect> HintMeta for SequenceProto<E> { type Known = SequenceKnown; type Hint = SequenceHint; + + type Effect = E; } pub fn visit_sequence<'a, 'ctx, E: Effect>( - visitor: Visitor<'a, 'ctx>, + visitor: DynVisitor<'a, 'ctx>, scope: DynSequenceScope<'a, 'ctx, E>, ) -> Future<'a, VisitResult<DynSequenceScope<'a, 'ctx, E>>, E> { - if let Some(object) = visitor.upcast_mut::<SequenceProto<E>>() { + if let Some(object) = visitor.0.upcast_mut::<SequenceProto<E>>() { // Allow the visitor to give a hint if it wants. object.visit(scope) } else { diff --git a/src/protocol/visitor/tag.rs b/src/protocol/visitor/tag.rs index 94828b4..dbedd22 100644 --- a/src/protocol/visitor/tag.rs +++ b/src/protocol/visitor/tag.rs @@ -4,11 +4,11 @@ use crate::{ higher_ranked_type, hkt::Marker, protocol::{ - walker::hint::{HintKnown, HintMeta}, - Visitor, + walker::hint::{HintMeta, Meta}, + DynVisitor, }, symbol::Symbol, - DynWalker, DynWalkerAdapter, DynWalkerError, WalkerTypes, + DynWalkerObjSafe, DynWalkerAdapter, DynWalkerError, WalkerTypes, }; use super::VisitResult; @@ -39,8 +39,8 @@ pub trait Tag<'ctx, K: TagKind, E: Effect> { fn visit<'a>( &'a mut self, kind: K, - walker: DynWalker<'a, 'ctx, E>, - ) -> Future<'a, VisitResult<DynWalker<'a, 'ctx, E>>, E>; + walker: DynWalkerObjSafe<'a, 'ctx, E>, + ) -> Future<'a, VisitResult<DynWalkerObjSafe<'a, 'ctx, E>>, E>; } pub struct TagProto<K: TagKind, E: Effect>(Marker<(K, E)>); @@ -63,8 +63,12 @@ higher_ranked_type! { } } +pub struct TagKnown { + pub kind_available: Option<bool>, +} + higher_ranked_type! { - impl HintKnown { + impl Meta { impl['a, 'ctx] type T['a, 'ctx] for TagKnown = TagKnown; @@ -73,18 +77,32 @@ higher_ranked_type! { } } -pub struct TagKnown { - pub kind_available: Option<bool>, -} - pub struct TagHint<K> { pub kind: K, } +higher_ranked_type! { + impl Meta { + impl['a, 'ctx, K] type T['a, 'ctx] for TagHint<K> = + TagHint<K> + where { + K: Send + Sync + }; + + impl['a, 'ctx, K] type HigherRanked['a, 'ctx] for TagHint<K> = + TagHint<K> + where { + K: Send + Sync + }; + } +} + impl<K: TagKind, E: Effect> HintMeta for TagProto<K, E> { type Known = TagKnown; type Hint = TagHint<K>; + + type Effect = E; } #[derive(Debug)] @@ -139,7 +157,7 @@ impl<E> TagError<E> { pub fn visit_tag<'a, 'ctx: 'a, K: TagKind, E: Effect, W: crate::Walker<'ctx, E> + 'a>( kind: K, - visitor: Visitor<'a, 'ctx>, + mut visitor: DynVisitor<'a, 'ctx>, walker: W, ) -> Future<'a, Result<VisitResult<W>, TagError<W::Error>>, E> where diff --git a/src/protocol/visitor/value.rs b/src/protocol/visitor/value.rs index b2ae696..8e902ab 100644 --- a/src/protocol/visitor/value.rs +++ b/src/protocol/visitor/value.rs @@ -8,8 +8,8 @@ use crate::{ higher_ranked_type, hkt::Marker, protocol::{ - walker::hint::{HintKnown, HintMeta}, - Visitor, + walker::hint::{HintMeta, Meta}, + DynVisitor, }, }; @@ -69,7 +69,7 @@ pub struct ValueKnown<'a, T: ?Sized> { pub struct ValueKnownHrt<T: ?Sized>(Marker<T>); higher_ranked_type! { - impl HintKnown { + impl Meta { impl['a, 'ctx, T] type T['a, 'ctx] for ValueKnownHrt<T> = ValueKnown<'a, TypeName::T<'a, 'ctx, T>> where { @@ -89,16 +89,18 @@ impl<T: TypeName::MemberType, E: Effect> HintMeta for ValueProto<T, E> { type Known = ValueKnownHrt<T>; type Hint = (); + + type Effect = E; } pub fn visit_value<'a, 'ctx, T: Send + TypeName::LowerType<'a, 'ctx>, E: Effect>( - visitor: Visitor<'a, 'ctx>, + visitor: DynVisitor<'a, 'ctx>, value: T, ) -> Future<'a, VisitResult<T>, E> where TypeName::HigherRanked<'a, 'ctx, T>: TypeName::MemberType, { - if let Some(object) = visitor.upcast_mut::<ValueProto<TypeName::HigherRanked<'a, 'ctx, T>, E>>() + if let Some(object) = visitor.0.upcast_mut::<ValueProto<TypeName::HigherRanked<'a, 'ctx, T>, E>>() { // Allow the visitor to give a hint if it wants. object.visit(value) @@ -107,168 +109,3 @@ where E::ready(VisitResult::Skipped(value)) } } - -// #[cfg(test)] -// mod test { -// use core::marker::PhantomData; -// -// use crate::{ -// any::{AnyTrait, BorrowedMutStatic, BorrowedStatic, OwnedStatic}, -// any_trait, -// effect::{BlockOn, Blocking, Spin}, -// }; -// -// use super::*; -// -// #[test] -// fn visit() { -// struct Visitor<E>(Option<i32>, PhantomData<fn() -> E>); -// -// impl<'ctx, E> Value<'ctx, OwnedStatic<i32>, E> for Visitor<E> -// where -// E: Effect, -// { -// fn visit<'a>(&'a mut self, OwnedStatic(value): OwnedStatic<i32>) -> Future<'a, Flow, E> -// where -// 'ctx: 'a, -// { -// E::wrap(async move { -// self.0 = Some(value); -// Flow::Continue -// }) -// } -// } -// -// impl<'ctx, E> Value<'ctx, BorrowedStatic<'ctx, i32>, E> for Visitor<E> -// where -// E: Effect, -// { -// fn visit<'a>( -// &'a mut self, -// BorrowedStatic(value): BorrowedStatic<'ctx, i32>, -// ) -> Future<'a, Flow, E> -// where -// 'ctx: 'a, -// { -// E::wrap(async { -// self.0 = Some(*value); -// Flow::Continue -// }) -// } -// } -// -// any_trait! { -// impl['ctx, E] Visitor<E> = [ -// DynValue<'ctx, OwnedStatic<i32>, E>, -// DynValue<'ctx, BorrowedStatic<'ctx, i32>, E>, -// ] where E: Effect, -// } -// -// let mut v = Visitor::<Blocking>(None, PhantomData); -// let object: &mut (dyn AnyTrait<'_> + Send) = &mut v; -// let _ = Spin::block_on( -// object -// .upcast_mut::<DynValue<'_, OwnedStatic<i32>, Blocking>>() -// .unwrap() -// .visit(OwnedStatic(42)), -// ); -// -// assert_eq!(v.0, Some(42)); -// -// let object: &mut (dyn AnyTrait<'_> + Send) = &mut v; -// let _ = Spin::block_on( -// object -// .upcast_mut::<DynValue<'_, BorrowedStatic<'_, i32>, Blocking>>() -// .unwrap() -// .visit(BorrowedStatic(&101)), -// ); -// -// assert_eq!(v.0, Some(101)); -// } -// -// #[test] -// fn visit_borrowed() { -// struct Visitor<'ctx, E>(Option<&'ctx mut String>, PhantomData<fn() -> E>); -// -// impl<'ctx, E> Value<'ctx, BorrowedMutStatic<'ctx, String>, E> for Visitor<'ctx, E> -// where -// E: Effect, -// { -// fn visit<'a>( -// &'a mut self, -// BorrowedMutStatic(value): BorrowedMutStatic<'ctx, String>, -// ) -> Future<'a, Flow, E> -// where -// 'ctx: 'a, -// { -// E::wrap(async { -// self.0 = Some(value); -// -// Flow::Continue -// }) -// } -// } -// -// any_trait! { -// impl['ctx, E] Visitor<'ctx, E> = [ -// DynValue<'ctx, BorrowedMutStatic<'ctx, String>, E>, -// ] where E: Effect -// } -// -// let mut v = Visitor::<Blocking>(None, PhantomData); -// -// let mut y = String::from("abc"); -// let object: &mut (dyn AnyTrait<'_> + Send) = &mut v; -// let _ = Spin::block_on( -// object -// .upcast_mut::<DynValue<'_, BorrowedMutStatic<'_, _>, Blocking>>() -// .unwrap() -// .visit(BorrowedMutStatic(&mut y)), -// ); -// -// v.0.unwrap().push_str("def"); -// assert_eq!(y, "abcdef"); -// } -// -// #[test] -// fn visit_borrowed_unsized() { -// struct Visitor<'ctx, E>(Option<&'ctx str>, PhantomData<fn() -> E>); -// -// impl<'ctx, E> Value<'ctx, BorrowedStatic<'ctx, str>, E> for Visitor<'ctx, E> -// where -// E: Effect, -// { -// fn visit<'a>( -// &'a mut self, -// BorrowedStatic(value): BorrowedStatic<'ctx, str>, -// ) -> Future<'a, Flow, E> -// where -// 'ctx: 'a, -// { -// E::wrap(async { -// self.0 = Some(value); -// Flow::Continue -// }) -// } -// } -// -// any_trait! { -// impl['ctx, E] Visitor<'ctx, E> = [ -// DynValue<'ctx, BorrowedStatic<'ctx, str>, E>, -// ] where E: Effect -// } -// -// let mut v = Visitor::<Blocking>(None, PhantomData); -// -// let y = String::from("abc"); -// let object: &mut (dyn AnyTrait<'_> + Send) = &mut v; -// let _ = Spin::block_on( -// object -// .upcast_mut::<DynValue<'_, BorrowedStatic<'_, str>, Blocking>>() -// .unwrap() -// .visit(BorrowedStatic(&y)), -// ); -// -// assert_eq!(v.0, Some("abc")); -// } -// } diff --git a/src/protocol/walker/hint.rs b/src/protocol/walker/hint.rs index 9bb35e6..9253264 100644 --- a/src/protocol/walker/hint.rs +++ b/src/protocol/walker/hint.rs @@ -9,12 +9,12 @@ use crate::{ effect::{Effect, Future}, higher_ranked_trait, higher_ranked_type, hkt::Marker, - protocol::Visitor, + protocol::DynVisitor, Flow, }; higher_ranked_trait! { - pub type class HintKnown for<'a, 'ctx> { + pub type class Meta for<'a, 'ctx> { type Bound = &'a &'ctx (); type T: { Send + Sized } where { 'ctx: 'a }; @@ -23,6 +23,13 @@ higher_ranked_trait! { } } +higher_ranked_type! { + impl Meta { + impl['a, 'ctx] type T['a, 'ctx] for () = (); + impl['a, 'ctx] type HigherRanked['a, 'ctx] for () = (); + } +} + /// Meta information for the hint. /// /// This gives the visitor more information to work from when selecting a hint. @@ -31,115 +38,49 @@ pub trait HintMeta: Send + Sync + 'static { /// /// This should be information easy to get without changing the state of the walker /// in an irreversible way. - type Known: HintKnown::MemberType; + type Known: Meta::MemberType; /// Extra information the visitor can give to the walker about what it is expecting. - type Hint; + type Hint: Meta::MemberType; + + type Effect: Effect; } -pub type Known<'a, 'ctx, Protocol> = HintKnown::T<'a, 'ctx, <Protocol as HintMeta>::Known>; +pub type MetaKnown<'a, 'ctx, Protocol> = Meta::T<'a, 'ctx, <Protocol as HintMeta>::Known>; +pub type MetaHint<'a, 'ctx, Protocol> = Meta::T<'a, 'ctx, <Protocol as HintMeta>::Hint>; /// Object implementing the [`Hint`] protocol. -pub trait Hint<'ctx, Protocol: ?Sized + HintMeta, E: Effect> { +pub trait Hint<'ctx, Protocol: ?Sized + HintMeta> { /// Hint to the walker to use the `P` protocol. /// /// This should only be called once per [`RequestHint`]. fn hint<'a>( &'a mut self, - visitor: Visitor<'a, 'ctx>, - hint: <Protocol as HintMeta>::Hint, - ) -> Future<'a, Flow, E>; + visitor: DynVisitor<'a, 'ctx>, + hint: MetaHint<'a, 'ctx, Protocol>, + ) -> Future<'a, Flow, Protocol::Effect>; /// Ask the walker for information about it's support of the protocol. fn known<'a>( &'a mut self, - hint: &'a <Protocol as HintMeta>::Hint, - ) -> Future<'a, Result<Known<'a, 'ctx, Protocol>, ()>, E>; + hint: &'a MetaHint<'a, 'ctx, Protocol>, + ) -> Future<'a, Result<MetaKnown<'a, 'ctx, Protocol>, ()>, Protocol::Effect>; } -pub struct HintProto<Protocol: ?Sized, E: Effect>(Marker<(*const Protocol, E)>); +pub struct HintProto<Protocol: ?Sized>(Marker<Protocol>); higher_ranked_type! { impl TypeName { - impl['a, 'ctx, Protocol, E] type T['a, 'ctx] for HintProto<Protocol, E> = - dyn Hint<'ctx, Protocol, E> + Send + Sync + 'a + impl['a, 'ctx, Protocol] type T['a, 'ctx] for HintProto<Protocol> = + dyn Hint<'ctx, Protocol> + Send + Sync + 'a where { Protocol: 'static, - E: Effect }; - impl['a, 'ctx, Protocol, E] type HigherRanked['a, 'ctx] for dyn Hint<'ctx, Protocol, E> + Send + Sync + 'a = - HintProto<Protocol, E> + impl['a, 'ctx, Protocol] type HigherRanked['a, 'ctx] for dyn Hint<'ctx, Protocol> + Send + Sync + 'a = + HintProto<Protocol> where { Protocol: 'static, - E: Effect, }; } } - -// #[cfg(test)] -// mod test { -// use crate::{ -// effect::{BlockOn, Blocking, Spin}, -// }; -// -// use super::*; -// -// #[test] -// fn demo() { -// struct X<'ctx>(&'ctx mut i32); -// -// #[derive(Debug)] -// struct Y; -// -// bijective_higher_ranked_type! { -// type DynY['ctx][]: WithContextLt['ctx][] for<'a> (Y) -// } -// -// bijective_higher_ranked_type! { -// type [][]: TypeName[][] for<'ctx> (DynY<'ctx>) -// } -// -// impl<'ctx, E: Effect<'ctx>> Hint<'ctx, DynY<'ctx>, E> for X<'ctx> { -// fn hint<'a>( -// &'a mut self, -// _visitor: Visitor<'a, 'ctx>, -// _hint: <DynY<'ctx> as HintMeta<'ctx>>::Hint, -// ) -> Future<'a, 'ctx, Flow, E> { -// todo!() -// } -// -// fn known<'a>( -// &'a mut self, -// _hint: &'a <DynY<'ctx> as HintMeta<'ctx>>::Hint, -// ) -> Future<'a, 'ctx, Result<Known<'a, 'ctx, DynY<'ctx>>, ()>, E> { -// E::ready(Ok(&mut *self.0)) -// } -// } -// -// higher_ranked_type! { -// type KnownHkt['ctx]: (AnySend) = for<'lt> &'lt mut i32 -// } -// -// impl<'ctx> HintMeta<'ctx> for DynY<'ctx> { -// type Known = KnownHkt<'ctx>; -// -// type Hint = (); -// } -// -// let mut z = 42; -// let mut x = X(&mut z); -// let y: &mut WithContextLt::T<'_, '_, DynHint<'_, DynY<'_>, Blocking>> = &mut x; -// -// fn id<'a, 'ctx, T: ?Sized + TypeName::LowerType<'ctx>>(_x: &WithContextLt::T<'a, 'ctx, T>) { -// } -// id::<DynHint<'_, DynY<'_>, Blocking>>(y); -// -// let x = Spin::block_on(y.known(&())); -// match x { -// Ok(value) => *value += 1, -// Err(_) => todo!(), -// } -// assert_eq!(z, 43); -// } -// } diff --git a/src/transform.rs b/src/transform.rs index 64aea20..edfa92a 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -1,7 +1,8 @@ use crate::{ build::Builder, effect::{Effect, Future}, - Walker, + hkt::Marker, + Walk, Walker, WalkerTypes, }; #[inline] @@ -23,3 +24,85 @@ pub fn transform<'a, 'ctx, B: Builder<'ctx, E> + 'a, W: Walker<'ctx, E> + 'a, E: (builder_result, walker_result) }) } + +/// For use in a lens. +pub struct Projection<T, B, U, M> { + value: T, + builder: B, + _marker: Marker<(U, M)>, +} + +impl<T, B, U: Send + Sync, M> Projection<T, B, U, M> { + pub fn project_ref<'a, E: Effect>( + &'a self, + ) -> Future< + 'a, + ( + Result<&'a U, B::Error>, + Result<<&'a T as WalkerTypes>::Output, <&'a T as WalkerTypes>::Error>, + ), + E, + > + where + &'a T: Walk<'a, M, E>, + B: Clone + Builder<'a, E, Value = &'a U>, + { + let walker = self.value.into_walker(); + let mut builder = self.builder.clone(); + + E::wrap(async { + let result = walker.walk(builder.as_visitor()).await; + + (builder.build().await, result) + }) + } + + pub fn project_mut<'a, E: Effect>( + &'a mut self, + ) -> Future< + 'a, + ( + Result<&'a mut U, B::Error>, + Result<<&'a mut T as WalkerTypes>::Output, <&'a mut T as WalkerTypes>::Error>, + ), + E, + > + where + &'a mut T: Walk<'a, M, E>, + B: Clone + Builder<'a, E, Value = &'a mut U>, + { + let walker = self.value.into_walker(); + let mut builder = self.builder.clone(); + + E::wrap(async { + let result = walker.walk(builder.as_visitor()).await; + + (builder.build().await, result) + }) + } + + pub fn project<'a, E: Effect>( + self, + ) -> Future< + 'a, + ( + Result<U, B::Error>, + Result<<T as WalkerTypes>::Output, <T as WalkerTypes>::Error>, + ), + E, + > + where + T: Walk<'a, M, E> + 'a, + M: 'a, + B: Clone + Builder<'a, E, Value = U> + 'a, + { + let walker = self.value.into_walker(); + let mut builder = self.builder.clone(); + + E::wrap(async { + let result = walker.walk(builder.as_visitor()).await; + + (builder.build().await, result) + }) + } +} diff --git a/src/walk.rs b/src/walk.rs index 5bdd5ec..349a63d 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -2,7 +2,7 @@ pub mod walkers; use crate::{ effect::{Effect, Future}, - protocol::Visitor, + protocol::DynVisitor, Flow, }; @@ -16,12 +16,12 @@ pub trait Walk<'ctx, M, E: Effect>: WalkerTypes + Sized { } pub trait WalkerTypes { - type Error: Send; + type Error: Send + Sync; /// An arbitrary type the walker is left with after walking. /// /// Its recommended that this is `Self` if the walker is repeatable. - type Output: Send; + type Output: Send + Sync; } /// Walker for a type. @@ -33,25 +33,25 @@ pub trait WalkerTypes { /// - Call [From::from()] with a value to be walked to make a walker. /// - Call [Self::walk()] to walk the value. Data will be sent to the provided /// visitor. -pub trait Walker<'ctx, E: Effect>: WalkerTypes + Send { +pub trait Walker<'ctx, E: Effect>: WalkerTypes + Send + Sync { /// Walk the value. /// /// The walker should send data to the `visitor` as it walks the value. fn walk<'a>( self, - visitor: Visitor<'a, 'ctx>, + visitor: DynVisitor<'a, 'ctx>, ) -> Future<'a, Result<Self::Output, Self::Error>, E> where Self: 'a; } pub trait WalkerObjSafe<'ctx, E: Effect>: Send { - fn walk<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, Flow, E> + fn walk<'a>(&'a mut self, visitor: DynVisitor<'a, 'ctx>) -> Future<'a, Flow, E> where Self: 'a; } -pub type DynWalker<'a, 'ctx, E> = &'a mut (dyn WalkerObjSafe<'ctx, E> + Send + 'a); +pub type DynWalkerObjSafe<'a, 'ctx, E> = &'a mut (dyn WalkerObjSafe<'ctx, E> + Send + 'a); enum DynWalkerState<W: WalkerTypes> { Walking, @@ -103,7 +103,7 @@ impl<W: WalkerTypes> DynWalkerAdapter<W> { } impl<'ctx, W: Walker<'ctx, E>, E: Effect> WalkerObjSafe<'ctx, E> for DynWalkerAdapter<W> { - fn walk<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, Flow, E> + fn walk<'a>(&'a mut self, visitor: DynVisitor<'a, 'ctx>) -> Future<'a, Flow, E> where Self: 'a, { diff --git a/src/walk/walkers/core/key_value.rs b/src/walk/walkers/core/key_value.rs index 85a15a3..8e14a1c 100644 --- a/src/walk/walkers/core/key_value.rs +++ b/src/walk/walkers/core/key_value.rs @@ -3,7 +3,7 @@ use crate::{ never::Never, protocol::{ visitor::{visit_tag, TagConst, TagError, TagKind, VisitResult}, - Visitor, + DynVisitor, }, walkers::core::noop::NoopWalker, Flow, WalkerTypes, TAG_KEY, TAG_KEY_VALUE, TAG_VALUE, @@ -55,17 +55,17 @@ where { fn walk<'a>( self, - visitor: Visitor<'a, 'ctx>, + mut visitor: DynVisitor<'a, 'ctx>, ) -> Future<'a, Result<Self::Output, Self::Error>, E> where Self: 'a, { E::wrap(async move { - match visit_tag::<T, E, _>(self.tag, visitor, NoopWalker::new()).await { + match visit_tag::<T, E, _>(self.tag, visitor.cast(), NoopWalker::new()).await { Ok(VisitResult::Skipped(_)) => { match visit_tag::<TagConst<{ TAG_KEY_VALUE.to_int() }>, E, _>( TagConst, - visitor, + visitor.cast(), NoopWalker::new(), ) .await @@ -82,7 +82,7 @@ where match visit_tag::<TagConst<{ TAG_KEY.to_int() }>, E, _>( TagConst, - visitor, + visitor.cast(), self.key_walker, ) .await @@ -94,7 +94,7 @@ where match visit_tag::<TagConst<{ TAG_VALUE.to_int() }>, E, _>( TagConst, - visitor, + visitor.cast(), self.value_walker, ) .await diff --git a/src/walk/walkers/core/noop.rs b/src/walk/walkers/core/noop.rs index 8bb05cb..7468016 100644 --- a/src/walk/walkers/core/noop.rs +++ b/src/walk/walkers/core/noop.rs @@ -1,7 +1,7 @@ use crate::{ effect::{Effect, Future}, never::Never, - protocol::Visitor, + protocol::DynVisitor, WalkerTypes, }; @@ -27,7 +27,7 @@ impl WalkerTypes for NoopWalker { impl<'ctx, E: Effect> crate::Walker<'ctx, E> for NoopWalker { fn walk<'a>( self, - _visitor: Visitor<'a, 'ctx>, + _visitor: DynVisitor<'a, 'ctx>, ) -> Future<'a, Result<Self::Output, Self::Error>, E> where Self: 'a, diff --git a/src/walk/walkers/core/struct.rs b/src/walk/walkers/core/struct.rs index 93e8bba..8fe0ce0 100644 --- a/src/walk/walkers/core/struct.rs +++ b/src/walk/walkers/core/struct.rs @@ -12,10 +12,7 @@ use crate::{ RecoverableKnown, RecoverableProto, RecoverableScope, SequenceKnown, SequenceProto, SequenceScope, TagConst, TagDyn, TagError, TagHint, TagKnown, TagProto, ValueKnown, ValueProto, VisitResult, - }, - walker::hint::{Hint, Known}, - walker::hint::{HintMeta, HintProto}, - Visitor, + }, walker::hint::{Hint, MetaKnown}, walker::hint::{HintMeta, HintProto, MetaHint}, DynVisitor, DynWalker }, Flow, Status, WalkerTypes, TAG_FIELD_NAMES, TAG_MAP, TAG_STRUCT, TAG_TYPE_ID, TAG_TYPE_NAME, }; @@ -58,7 +55,7 @@ pub trait StructTypeInfo<'ctx, M>: 'static { fn walk_field<'a, E: Effect>( index: usize, value: &'ctx Self::T, - visitor: Visitor<'a, 'ctx>, + visitor: DynVisitor<'a, 'ctx>, ) -> Future<'a, Result<Flow, Self::FieldError>, E>; } @@ -117,14 +114,14 @@ where { fn walk<'a>( mut self, - visitor: Visitor<'a, 'ctx>, + mut visitor: DynVisitor<'a, 'ctx>, ) -> Future<'a, Result<Self::Output, Self::Error>, E> where Self: 'a, { - E::wrap(async { + E::wrap(async move { // Use the recoverable walk to not duplicate the code. - let _ = RecoverableScope::<'ctx, E>::new_walk(&mut self, visitor).await; + let _ = RecoverableScope::<'ctx, E>::new_walk(&mut self, visitor.cast()).await; // Get the error if there was one. match self.error { @@ -137,22 +134,22 @@ where any_trait! { impl['ctx, T, I, M, E] StructWalker<'ctx, T, I, M, E> = [ - HintProto<RecoverableProto<E>, E>, - HintProto<SequenceProto<E>, E>, - HintProto<ValueProto<BorrowedStaticHrt<T>, E>, E>, - HintProto<TagProto<TagDyn, E>, E>, - HintProto<TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E>, E>, - HintProto<TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E>, E>, - HintProto<TagProto<TagConst<{ TAG_MAP.to_int() }>, E>, E>, - HintProto<TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E>, E>, - HintProto<TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>, E>, + HintProto<RecoverableProto<E>>, + HintProto<SequenceProto<E>>, + HintProto<ValueProto<BorrowedStaticHrt<T>, E>>, + HintProto<TagProto<TagDyn, E>>, + HintProto<TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E>>, + HintProto<TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E>>, + HintProto<TagProto<TagConst<{ TAG_MAP.to_int() }>, E>>, + HintProto<TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E>>, + HintProto<TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>>, ] where E: Effect, T: Send + Sync + 'static, I: StructTypeInfo<'ctx, M, T = T> } -impl<'ctx, T, I, M, E> Hint<'ctx, RecoverableProto<E>, E> for StructWalker<'ctx, T, I, M, E> +impl<'ctx, T, I, M, E> Hint<'ctx, RecoverableProto<E>> for StructWalker<'ctx, T, I, M, E> where E: Effect, I: StructTypeInfo<'ctx, M, T = T>, @@ -160,7 +157,7 @@ where { fn hint<'a>( &'a mut self, - visitor: Visitor<'a, 'ctx>, + visitor: DynVisitor<'a, 'ctx>, _hint: <RecoverableProto<E> as HintMeta>::Hint, ) -> Future<'a, Flow, E> { E::map( @@ -175,12 +172,12 @@ where fn known<'a>( &'a mut self, _hint: &'a <RecoverableProto<E> as HintMeta>::Hint, - ) -> Future<'a, Result<Known<'a, 'ctx, RecoverableProto<E>>, ()>, E> { + ) -> Future<'a, Result<MetaKnown<'a, 'ctx, RecoverableProto<E>>, ()>, E> { E::ready(Ok(RecoverableKnown)) } } -impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>, E> +impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>> for StructWalker<'ctx, T, I, M, E> where E: Effect, @@ -189,8 +186,8 @@ where { fn hint<'a>( &'a mut self, - visitor: Visitor<'a, 'ctx>, - _hint: <TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E> as HintMeta>::Hint, + visitor: DynVisitor<'a, 'ctx>, + _hint: MetaHint<'a, 'ctx, TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>>, ) -> Future<'a, Flow, E> { E::map( visit_tag::<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E, _>( @@ -211,10 +208,10 @@ where fn known<'a>( &'a mut self, - _hint: &'a <TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E> as HintMeta>::Hint, + _hint: &'a MetaHint<'a, 'ctx, TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>>, ) -> Future< 'a, - Result<Known<'a, 'ctx, TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>>, ()>, + Result<MetaKnown<'a, 'ctx, TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>>, ()>, E, > { E::ready(Ok(TagKnown { @@ -223,7 +220,7 @@ where } } -impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E>, E> +impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E>> for StructWalker<'ctx, T, I, M, E> where E: Effect, @@ -232,7 +229,7 @@ where { fn hint<'a>( &'a mut self, - visitor: Visitor<'a, 'ctx>, + visitor: DynVisitor<'a, 'ctx>, _hint: <TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E> as HintMeta>::Hint, ) -> Future<'a, Flow, E> { E::map( @@ -255,15 +252,18 @@ where fn known<'a>( &'a mut self, _hint: &'a <TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E> as HintMeta>::Hint, - ) -> Future<'a, Result<Known<'a, 'ctx, TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E>>, ()>, E> - { + ) -> Future< + 'a, + Result<MetaKnown<'a, 'ctx, TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E>>, ()>, + E, + > { E::ready(Ok(TagKnown { kind_available: Some(true), })) } } -impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_MAP.to_int() }>, E>, E> +impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_MAP.to_int() }>, E>> for StructWalker<'ctx, T, I, M, E> where E: Effect, @@ -272,7 +272,7 @@ where { fn hint<'a>( &'a mut self, - visitor: Visitor<'a, 'ctx>, + visitor: DynVisitor<'a, 'ctx>, _hint: <TagProto<TagConst<{ TAG_MAP.to_int() }>, E> as HintMeta>::Hint, ) -> Future<'a, Flow, E> { E::map( @@ -291,7 +291,7 @@ where fn known<'a>( &'a mut self, _hint: &'a <TagProto<TagConst<{ TAG_MAP.to_int() }>, E> as HintMeta>::Hint, - ) -> Future<'a, Result<Known<'a, 'ctx, TagProto<TagConst<{ TAG_MAP.to_int() }>, E>>, ()>, E> + ) -> Future<'a, Result<MetaKnown<'a, 'ctx, TagProto<TagConst<{ TAG_MAP.to_int() }>, E>>, ()>, E> { E::ready(Ok(TagKnown { kind_available: Some(true), @@ -299,7 +299,7 @@ where } } -impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E>, E> +impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E>> for StructWalker<'ctx, T, I, M, E> where E: Effect, @@ -308,7 +308,7 @@ where { fn hint<'a>( &'a mut self, - visitor: Visitor<'a, 'ctx>, + visitor: DynVisitor<'a, 'ctx>, _hint: <TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E> as HintMeta>::Hint, ) -> Future<'a, Flow, E> { E::map( @@ -331,15 +331,18 @@ where fn known<'a>( &'a mut self, _hint: &'a <TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E> as HintMeta>::Hint, - ) -> Future<'a, Result<Known<'a, 'ctx, TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E>>, ()>, E> - { + ) -> Future< + 'a, + Result<MetaKnown<'a, 'ctx, TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E>>, ()>, + E, + > { E::ready(Ok(TagKnown { kind_available: Some(true), })) } } -impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E>, E> +impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E>> for StructWalker<'ctx, T, I, M, E> where E: Effect, @@ -348,7 +351,7 @@ where { fn hint<'a>( &'a mut self, - visitor: Visitor<'a, 'ctx>, + visitor: DynVisitor<'a, 'ctx>, _hint: <TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E> as HintMeta>::Hint, ) -> Future<'a, Flow, E> { E::map( @@ -371,15 +374,18 @@ where fn known<'a>( &'a mut self, _hint: &'a <TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E> as HintMeta>::Hint, - ) -> Future<'a, Result<Known<'a, 'ctx, TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E>>, ()>, E> - { + ) -> Future< + 'a, + Result<MetaKnown<'a, 'ctx, TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E>>, ()>, + E, + > { E::ready(Ok(TagKnown { kind_available: Some(true), })) } } -impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagDyn, E>, E> for StructWalker<'ctx, T, I, M, E> +impl<'ctx, T, I, M, E> Hint<'ctx, TagProto<TagDyn, E>> for StructWalker<'ctx, T, I, M, E> where E: Effect, I: StructTypeInfo<'ctx, M>, @@ -387,38 +393,39 @@ where { fn hint<'a>( &'a mut self, - visitor: Visitor<'a, 'ctx>, + visitor: DynVisitor<'a, 'ctx>, hint: <TagProto<TagDyn, E> as HintMeta>::Hint, ) -> Future<'a, Flow, E> { match hint.kind.0 { crate::TAG_TYPE_ID => { - Hint::<'ctx, TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E>, E>::hint( + Hint::<'ctx, TagProto<TagConst<{ TAG_TYPE_ID.to_int() }>, E>>::hint( self, visitor, TagHint { kind: TagConst }, ) } crate::TAG_STRUCT => { - Hint::<'ctx, TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E>, E>::hint( + Hint::<'ctx, TagProto<TagConst<{ TAG_STRUCT.to_int() }>, E>>::hint( self, visitor, TagHint { kind: TagConst }, ) } - crate::TAG_MAP => Hint::<'ctx, TagProto<TagConst<{ TAG_MAP.to_int() }>, E>, E>::hint( + crate::TAG_MAP => Hint::<'ctx, TagProto<TagConst<{ TAG_MAP.to_int() }>, E>>::hint( self, visitor, TagHint { kind: TagConst }, ), - crate::TAG_TYPE_NAME => Hint::< - 'ctx, - TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E>, - E, - >::hint(self, visitor, TagHint { kind: TagConst }), + crate::TAG_TYPE_NAME => { + Hint::<'ctx, TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, E>>::hint( + self, + visitor, + TagHint { kind: TagConst }, + ) + } crate::TAG_FIELD_NAMES => Hint::< 'ctx, TagProto<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E>, - E, >::hint(self, visitor, TagHint { kind: TagConst }), _ => E::ready(Flow::Continue), } @@ -427,7 +434,7 @@ where fn known<'a>( &'a mut self, hint: &'a <TagProto<TagDyn, E> as HintMeta>::Hint, - ) -> Future<'a, Result<Known<'a, 'ctx, TagProto<TagDyn, E>>, ()>, E> { + ) -> Future<'a, Result<MetaKnown<'a, 'ctx, TagProto<TagDyn, E>>, ()>, E> { E::ready(match hint.kind { TagDyn(crate::TAG_TYPE_ID) | TagDyn(crate::TAG_STRUCT) => Ok(TagKnown { kind_available: Some(true), @@ -439,14 +446,14 @@ where } } -impl<'ctx, T, I, M, E> Hint<'ctx, ValueProto<BorrowedStaticHrt<T>, E>, E> +impl<'ctx, T, I, M, E> Hint<'ctx, ValueProto<BorrowedStaticHrt<T>, E>> for StructWalker<'ctx, T, I, M, E> where E: Effect, I: StructTypeInfo<'ctx, M>, T: Send + Sync + 'static, { - fn hint<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>, _hint: ()) -> Future<'a, Flow, E> { + fn hint<'a>(&'a mut self, visitor: DynVisitor<'a, 'ctx>, _hint: ()) -> Future<'a, Flow, E> { E::map( visit_value::<_, E>(visitor, BorrowedStatic(self.value)), |status| match status { @@ -464,7 +471,7 @@ where } } -impl<'ctx, T, I, M, E> Hint<'ctx, SequenceProto<E>, E> for StructWalker<'ctx, T, I, M, E> +impl<'ctx, T, I, M, E> Hint<'ctx, SequenceProto<E>> for StructWalker<'ctx, T, I, M, E> where E: Effect, I: StructTypeInfo<'ctx, M, T = T>, @@ -472,7 +479,7 @@ where { fn hint<'a>( &'a mut self, - visitor: Visitor<'a, 'ctx>, + visitor: DynVisitor<'a, 'ctx>, _hint: <SequenceProto<E> as HintMeta>::Hint, ) -> Future<'a, Flow, E> { E::map(visit_sequence::<E>(visitor, self), |status| match status { @@ -484,7 +491,7 @@ where fn known<'a>( &'a mut self, _hint: &'a <SequenceProto<E> as HintMeta>::Hint, - ) -> Future<'a, Result<Known<'a, 'ctx, SequenceProto<E>>, ()>, E> { + ) -> Future<'a, Result<MetaKnown<'a, 'ctx, SequenceProto<E>>, ()>, E> { let len = I::FIELDS.len(); E::ready(Ok(SequenceKnown { @@ -504,7 +511,7 @@ where E::ready((len, Some(len))) } - fn next<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, Flow, E> { + fn next<'a>(&'a mut self, visitor: DynVisitor<'a, 'ctx>) -> Future<'a, Flow, E> { if self.index >= I::FIELDS.len() { return E::ready(Flow::Done); } @@ -532,7 +539,7 @@ where I: StructTypeInfo<'ctx, M, T = T>, T: Send + Sync + 'static, { - fn new_walk<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, Status, E> { + fn new_walk<'a>(&'a mut self, mut visitor: DynVisitor<'a, 'ctx>) -> Future<'a, Status, E> { // Reset the errors to default state. self.error = None; @@ -541,14 +548,14 @@ where E::wrap(async move { // We should check if the visitor wants something specific. - match visit_request_hint::<E>(visitor, self).await { + match visit_request_hint::<E>(visitor.cast(), DynWalker(self)).await { VisitResult::Skipped(_) | VisitResult::Control(Flow::Continue) => {} VisitResult::Control(Flow::Done) => return Ok(()), VisitResult::Control(Flow::Err) => return Err(()), } // Attempt to visit the value directly. - match visit_value::<_, E>(visitor, BorrowedStatic(self.value)).await { + match visit_value::<_, E>(visitor.cast(), BorrowedStatic(self.value)).await { VisitResult::Skipped(_) | VisitResult::Control(Flow::Continue) => {} VisitResult::Control(Flow::Done) => return Ok(()), VisitResult::Control(Flow::Err) => return Err(()), @@ -563,7 +570,7 @@ where match visit_tag::<TagConst<{ TAG_TYPE_ID.to_int() }>, E, _>( TagConst, - visitor, + visitor.cast(), ValueWalker::new(TypeId::of::<T>()), ) .await @@ -579,7 +586,7 @@ where match visit_tag::<TagConst<{ TAG_STRUCT.to_int() }>, E, _>( TagConst, - visitor, + visitor.cast(), NoopWalker::new(), ) .await @@ -587,7 +594,7 @@ where Ok(VisitResult::Skipped(_)) => { match visit_tag::<TagConst<{ TAG_MAP.to_int() }>, E, _>( TagConst, - visitor, + visitor.cast(), NoopWalker::new(), ) .await @@ -612,7 +619,7 @@ where match visit_tag::<TagConst<{ TAG_TYPE_NAME.to_int() }>, E, _>( TagConst, - visitor, + visitor.cast(), ValueWalker::new(I::NAME), ) .await @@ -628,7 +635,7 @@ where match visit_tag::<TagConst<{ TAG_FIELD_NAMES.to_int() }>, E, _>( TagConst, - visitor, + visitor.cast(), StaticSliceWalker::<_, ValueWalker<&'static str>>::new(I::FIELDS), ) .await diff --git a/src/walk/walkers/core/tag.rs b/src/walk/walkers/core/tag.rs index a4f1cea..f20b449 100644 --- a/src/walk/walkers/core/tag.rs +++ b/src/walk/walkers/core/tag.rs @@ -8,8 +8,7 @@ use crate::{ protocol::{ visitor::{ visit_request_hint, visit_value, SequenceProto, SequenceScope, TagError, VisitResult, - }, - Visitor, + }, DynVisitor, DynWalker }, Flow, WalkerTypes, }; @@ -45,24 +44,24 @@ where { fn walk<'a>( mut self, - visitor: Visitor<'a, 'ctx>, + mut visitor: DynVisitor<'a, 'ctx>, ) -> Future<'a, Result<Self::Output, Self::Error>, E> where Self: 'a, { E::wrap(async move { - match visit_request_hint::<E>(visitor, &mut self).await { + match visit_request_hint::<E>(visitor.cast(), DynWalker(&mut self)).await { VisitResult::Skipped(_) | VisitResult::Control(Flow::Continue) => {} _ => return Ok(()), } - match visit_value::<_, E>(visitor, OwnedStatic(self.names)).await { + match visit_value::<_, E>(visitor.cast(), OwnedStatic(self.names)).await { VisitResult::Skipped(_) => {} VisitResult::Control(Flow::Continue) => {} _ => return Ok(()), } - if let Some(object) = visitor.upcast_mut::<SequenceProto<E>>() { + if let Some(object) = visitor.cast().upcast_mut::<SequenceProto<E>>() { // Visit with the name. Ignore the flow because we return a result not a flow. let _ = object.visit(&mut self).await; } @@ -84,7 +83,7 @@ where T: Sync, &'static T: Into<W>, { - fn next<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, Flow, E> { + fn next<'a>(&'a mut self, visitor: DynVisitor<'a, 'ctx>) -> Future<'a, Flow, E> { if let Some(name) = self.names.get(self.current) { self.current += 1; E::wrap(async move { diff --git a/src/walk/walkers/core/value.rs b/src/walk/walkers/core/value.rs index b8e5b79..c33b2fe 100644 --- a/src/walk/walkers/core/value.rs +++ b/src/walk/walkers/core/value.rs @@ -2,7 +2,7 @@ use crate::{ any::{BorrowedStatic, OwnedStatic}, effect::{Effect, Future}, never::Never, - protocol::{visitor::visit_value, Visitor}, + protocol::{visitor::visit_value, DynVisitor}, WalkerTypes, }; @@ -41,7 +41,7 @@ impl<T> WalkerTypes for ValueWalker<T> { impl<'ctx, T: Send + Sync + 'static, E: Effect> crate::Walker<'ctx, E> for ValueWalker<T> { fn walk<'a>( self, - visitor: Visitor<'a, 'ctx>, + visitor: DynVisitor<'a, 'ctx>, ) -> Future<'a, Result<Self::Output, Self::Error>, E> where Self: 'a, @@ -77,7 +77,7 @@ impl<'ctx, T: ?Sized + Send + Sync + 'static, E: Effect> crate::Walker<'ctx, E> { fn walk<'a>( self, - visitor: Visitor<'a, 'ctx>, + visitor: DynVisitor<'a, 'ctx>, ) -> Future<'a, Result<Self::Output, Self::Error>, E> where Self: 'a, diff --git a/tests/common/builder.rs b/tests/common/builder.rs index 160846a..e12b013 100644 --- a/tests/common/builder.rs +++ b/tests/common/builder.rs @@ -2,7 +2,7 @@ use mockall::mock; use treaty::{ any::{indirect, AnyTrait, AnyTraitObject, TypeNameId}, effect::{Effect, Future}, - protocol::Visitor, + protocol::DynVisitor, Builder, BuilderTypes, }; @@ -17,12 +17,14 @@ mock! { pub fn from_seed(seed: Seed) -> Self; pub fn build(self) -> Result<Value, Error>; - pub fn traits(&self, id: TypeNameId) -> &Option<Box<dyn for<'ctx> AnyTrait<'ctx> + Send>>; - pub fn traits_mut(&mut self, id: TypeNameId) -> &mut Option<Box<dyn for<'ctx> AnyTrait<'ctx> + Send>>; + pub fn traits(&self, id: TypeNameId) -> &Option<Box<dyn for<'ctx> AnyTrait<'ctx> + Send + Sync>>; + pub fn traits_mut(&mut self, id: TypeNameId) -> &mut Option<Box<dyn for<'ctx> AnyTrait<'ctx> + Send + Sync>>; } } -impl<Seed: Send, Value: Send, Error: Send> BuilderTypes for MockBuilder<Seed, Value, Error> { +impl<Seed: Send + Sync, Value: Send + Sync, Error: Send + Sync> BuilderTypes + for MockBuilder<Seed, Value, Error> +{ type Seed = Seed; type Error = Error; @@ -44,7 +46,7 @@ impl<Seed: 'static, Value: 'static, Error: 'static> MockBuilder<Seed, Value, Err } } -impl<'ctx, Seed: Send, Value: Send, Error: Send, E: Effect> Builder<'ctx, E> +impl<'ctx, Seed: Send + Sync, Value: Send + Sync, Error: Send + Sync, E: Effect> Builder<'ctx, E> for MockBuilder<Seed, Value, Error> { fn from_seed<'a>(seed: Self::Seed) -> Future<'a, Self, E> @@ -61,8 +63,8 @@ impl<'ctx, Seed: Send, Value: Send, Error: Send, E: Effect> Builder<'ctx, E> E::ready(self.build()) } - fn as_visitor(&mut self) -> Visitor<'_, 'ctx> { - self + fn as_visitor(&mut self) -> DynVisitor<'_, 'ctx> { + DynVisitor(self) } } diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 8b9fb03..bad703e 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -11,6 +11,7 @@ use std::{ pub mod builder; pub mod protocol; +pub mod walker; pub struct StaticTypeMap { map: OnceLock<RwLock<HashMap<TypeId, &'static (dyn Any + Send + Sync)>>>, diff --git a/tests/common/protocol.rs b/tests/common/protocol.rs index 148a458..ab619e0 100644 --- a/tests/common/protocol.rs +++ b/tests/common/protocol.rs @@ -1,3 +1,5 @@ pub mod hint; +pub mod request_hint; +pub mod sequence; pub mod tag; pub mod visitor; diff --git a/tests/common/protocol/hint.rs b/tests/common/protocol/hint.rs index bcc2a02..07c7c41 100644 --- a/tests/common/protocol/hint.rs +++ b/tests/common/protocol/hint.rs @@ -3,44 +3,43 @@ use treaty::{ any::{any_trait, TypeName}, effect::{Effect, Future}, protocol::{ - walker::hint::{Hint, HintMeta, HintProto, Known}, - Visitor, + walker::hint::{Hint, HintMeta, HintProto, MetaHint, MetaKnown}, + DynVisitor, }, Flow, }; pub type KnownFactory<P> = - for<'a, 'ctx> fn(&'ctx (), &'a <P as HintMeta>::Hint) -> Result<Known<'a, 'ctx, P>, ()>; + for<'a, 'ctx> fn(&'ctx (), &'a MetaHint<'a, 'ctx, P>) -> Result<MetaKnown<'a, 'ctx, P>, ()>; mock! { - pub HintVisitor<P: HintMeta, E> { - pub fn hint<'a, 'ctx>(&'a mut self, visitor: Visitor<'a, 'ctx>, hint: <P as HintMeta>::Hint) -> Flow; + pub HintWalker<P: HintMeta> { + pub fn hint<'a, 'ctx>(&'a mut self, visitor: DynVisitor<'a, 'ctx>, hint: MetaHint<'a, 'ctx, P>) -> Flow; pub fn known(&self) -> KnownFactory<P>; } } any_trait! { - impl['ctx, P, E] MockHintVisitor<P, E> = [ - HintProto<P, E> + impl['ctx, P] MockHintWalker<P> = [ + HintProto<P> ] where P: HintMeta, - E: Effect, } -impl<'ctx, P: HintMeta, E: Effect> Hint<'ctx, P, E> for MockHintVisitor<P, E> { +impl<'ctx, P: HintMeta> Hint<'ctx, P> for MockHintWalker<P> { fn hint<'a>( &'a mut self, - visitor: Visitor<'a, 'ctx>, - hint: <P as HintMeta>::Hint, - ) -> Future<'a, Flow, E> { - E::ready(self.hint(visitor, hint)) + visitor: DynVisitor<'a, 'ctx>, + hint: MetaHint<'a, 'ctx, P>, + ) -> Future<'a, Flow, P::Effect> { + P::Effect::ready(self.hint(visitor, hint)) } fn known<'a>( &'a mut self, - hint: &'a <P as HintMeta>::Hint, - ) -> Future<'a, Result<Known<'a, 'ctx, P>, ()>, E> { - E::ready(Self::known(self)(&(), hint)) + hint: &'a MetaHint<'a, 'ctx, P>, + ) -> Future<'a, Result<MetaKnown<'a, 'ctx, P>, ()>, P::Effect> { + P::Effect::ready(Self::known(self)(&(), hint)) } } diff --git a/tests/common/protocol/request_hint.rs b/tests/common/protocol/request_hint.rs new file mode 100644 index 0000000..be203b3 --- /dev/null +++ b/tests/common/protocol/request_hint.rs @@ -0,0 +1,33 @@ +use mockall::mock; +use treaty::{ + any::{any_trait, TypeName}, + effect::{Effect, Future}, + protocol::visitor::{RequestHint, RequestHintProto, Value, ValueProto, VisitResult}, + protocol::DynWalker, + Flow, +}; + +pub type RequestHintFactory = + for<'a, 'ctx> fn(&'ctx (), DynWalker<'a, 'ctx>) -> VisitResult<DynWalker<'a, 'ctx>>; + +mock! { + pub RequestHintVisitor<E> { + pub fn request_hint(&mut self) -> RequestHintFactory; + } +} + +any_trait! { + impl['ctx, E] MockRequestHintVisitor<E> = [ + RequestHintProto<E> + ] where + E: Effect, +} + +impl<'ctx, E: Effect> RequestHint<'ctx, E> for MockRequestHintVisitor<E> { + fn request_hint<'a>( + &'a mut self, + walker: DynWalker<'a, 'ctx>, + ) -> Future<'a, VisitResult<DynWalker<'a, 'ctx>>, E> { + E::ready(self.request_hint()(&(), walker)) + } +} diff --git a/tests/common/protocol/sequence.rs b/tests/common/protocol/sequence.rs new file mode 100644 index 0000000..ff4249f --- /dev/null +++ b/tests/common/protocol/sequence.rs @@ -0,0 +1,58 @@ +use mockall::mock; +use treaty::{ + any::{any_trait, TypeName}, + effect::{Effect, Future}, + protocol::DynWalker, + protocol::{ + visitor::{ + DynSequenceScope, RequestHint, RequestHintProto, Sequence, SequenceProto, + SequenceScope, Value, ValueProto, VisitResult, + }, + DynVisitor, + }, + Flow, +}; + +pub type SequenceScopeFactory<E> = for<'a, 'ctx> fn( + &'ctx (), + DynSequenceScope<'a, 'ctx, E>, +) -> VisitResult<DynSequenceScope<'a, 'ctx, E>>; + +mock! { + pub SequenceVisitor<E> { + pub fn visit(&mut self) -> SequenceScopeFactory<E>; + } +} + +any_trait! { + impl['ctx, E] MockSequenceVisitor<E> = [ + SequenceProto<E> + ] where + E: Effect, +} + +impl<'ctx, E: Effect> Sequence<'ctx, E> for MockSequenceVisitor<E> { + fn visit<'a>( + &'a mut self, + scope: DynSequenceScope<'a, 'ctx, E>, + ) -> Future<'a, VisitResult<DynSequenceScope<'a, 'ctx, E>>, E> { + E::ready(self.visit()(&(), scope)) + } +} + +mock! { + pub SequenceScopeVisitor<E> { + pub fn size_hint(&mut self) -> (usize, Option<usize>); + pub fn next<'a, 'ctx>(&'a mut self, visitor: DynVisitor<'a, 'ctx>) -> Flow; + } +} + +impl<'ctx, E: Effect> SequenceScope<'ctx, E> for MockSequenceScopeVisitor<E> { + fn size_hint(&mut self) -> Future<'_, (usize, Option<usize>), E> { + E::ready(self.size_hint()) + } + + fn next<'a>(&'a mut self, visitor: DynVisitor<'a, 'ctx>) -> Future<'a, Flow, E> { + E::ready(self.next(visitor)) + } +} diff --git a/tests/common/protocol/tag.rs b/tests/common/protocol/tag.rs index 7bc152a..581cced 100644 --- a/tests/common/protocol/tag.rs +++ b/tests/common/protocol/tag.rs @@ -3,12 +3,12 @@ use treaty::{ any::any_trait, effect::{Effect, Future}, protocol::visitor::{Tag, TagKind, TagProto, VisitResult}, - DynWalker, + DynWalkerObjSafe, }; mock! { pub TagVisitor<K: TagKind, E> { - pub fn visit<'a, 'ctx>(&'a mut self, kind: K, walker: DynWalker<'a, 'ctx, E>) -> VisitResult<()>; + pub fn visit<'a, 'ctx>(&'a mut self, kind: K, walker: DynWalkerObjSafe<'a, 'ctx, E>) -> VisitResult<()>; } } @@ -24,8 +24,8 @@ impl<'ctx, K: TagKind, E: Effect> Tag<'ctx, K, E> for MockTagVisitor<K, E> { fn visit<'a>( &'a mut self, kind: K, - walker: DynWalker<'a, 'ctx, E>, - ) -> Future<'a, VisitResult<DynWalker<'a, 'ctx, E>>, E> { + walker: DynWalkerObjSafe<'a, 'ctx, E>, + ) -> Future<'a, VisitResult<DynWalkerObjSafe<'a, 'ctx, E>>, E> { E::ready(match self.visit(kind, walker) { VisitResult::Skipped(_) => VisitResult::Skipped(walker), VisitResult::Control(flow) => VisitResult::Control(flow), diff --git a/tests/common/walker.rs b/tests/common/walker.rs new file mode 100644 index 0000000..b1064f6 --- /dev/null +++ b/tests/common/walker.rs @@ -0,0 +1,57 @@ +use mockall::mock; +use treaty::{ + any::{indirect, AnyTrait, AnyTraitObject, TypeNameId}, + effect::{Effect, Future}, + protocol::DynVisitor, + Builder, BuilderTypes, Walker, WalkerTypes, +}; + +mock! { + pub Walker<Output, Error> { + pub fn walk<'a, 'ctx>(self, visitor: DynVisitor<'a, 'ctx>) -> Result<Output, Error>; + + pub fn traits(&self, id: TypeNameId) -> &Option<Box<dyn for<'ctx> AnyTrait<'ctx> + Send + Sync>>; + pub fn traits_mut(&mut self, id: TypeNameId) -> &mut Option<Box<dyn for<'ctx> AnyTrait<'ctx> + Send + Sync>>; + } +} + +impl<Output: Send + Sync, Error: Send + Sync> WalkerTypes for MockWalker<Output, Error> { + type Error = Error; + + type Output = Output; +} + +impl<'ctx, Output: Send + Sync, Error: Send + Sync, E: Effect> Walker<'ctx, E> + for MockWalker<Output, Error> +{ + fn walk<'a>( + self, + visitor: DynVisitor<'a, 'ctx>, + ) -> Future<'a, Result<Self::Output, Self::Error>, E> + where + Self: 'a, + { + E::ready(self.walk(visitor)) + } +} + +impl<'ctx, Output, Error> AnyTrait<'ctx> for MockWalker<Output, Error> { + fn upcast_to_id<'a>(&'a self, id: TypeNameId) -> Option<AnyTraitObject<'a, 'ctx, indirect::Ref>> + where + 'ctx: 'a, + { + self.traits(id).as_ref().and_then(|t| t.upcast_to_id(id)) + } + + fn upcast_to_id_mut<'a>( + &'a mut self, + id: TypeNameId, + ) -> Option<AnyTraitObject<'a, 'ctx, indirect::Mut>> + where + 'ctx: 'a, + { + self.traits_mut(id) + .as_mut() + .and_then(|t| t.upcast_to_id_mut(id)) + } +} diff --git a/tests/protocol_visitor_request_hint.rs b/tests/protocol_visitor_request_hint.rs new file mode 100644 index 0000000..234d64f --- /dev/null +++ b/tests/protocol_visitor_request_hint.rs @@ -0,0 +1,93 @@ +use std::any::TypeId; + +use common::{ + protocol::{ + hint::MockHintWalker, + request_hint::{MockRequestHintVisitor, RequestHintFactory}, + }, + walker::MockWalker, +}; +use mockall::predicate::eq; +use treaty::{ + any::{OwnedStatic, TypeNameId}, + effect::Blocking, + protocol::{ + visitor::{RequestHint, RequestHintProto, ValueKnown, ValueProto, VisitResult}, + walker::hint::HintProto, + }, + Flow, +}; + +use crate::common::protocol::hint::KnownFactory; + +mod common; + +#[test] +fn hints_can_be_requested() { + let mut mock = MockRequestHintVisitor::<Blocking>::new(); + + // We will request a hint from the visitor. + mock.expect_request_hint().once().return_const( + (|_, walker| { + // Lookup the value protocol on the walker. + let obj = walker + .upcast_mut::<HintProto<ValueProto<OwnedStatic<i32>, Blocking>>>() + .unwrap(); + + // Get the known for the value protocol. + assert_eq!( + obj.known(&()).into_inner(), + Ok(ValueKnown { + preview: Some(&OwnedStatic(42)) + }) + ); + + // We are done. + VisitResult::Control(Flow::Done) + }) as RequestHintFactory, + ); + + // This mock becomes the visitor. + let visitor: &mut dyn RequestHint<Blocking> = &mut mock; + + let mut mock = MockWalker::<(), ()>::new(); + + // The visitor will lookup the value protocol on the walker. + mock.expect_traits_mut() + .once() + .with(eq(TypeNameId::of::< + HintProto<ValueProto<OwnedStatic<i32>, Blocking>>, + >())) + .returning(|_id| { + let mut mock = MockHintWalker::<ValueProto<OwnedStatic<i32>, Blocking>>::new(); + + // Expect to give a known for the value protocol to the visitor. + mock.expect_known().once().return_const( + (|_, ()| { + Ok(ValueKnown { + preview: Some(&OwnedStatic(42)), + }) + }) as KnownFactory<ValueProto<OwnedStatic<i32>, Blocking>>, + ); + + Some(Box::new(mock)) + }); + + // Request a hint from the visitor. + assert!(matches!( + visitor.request_hint(&mut mock).into_inner(), + VisitResult::Control(Flow::Done) + )); +} + +#[test] +fn request_hint_proto() { + // The type id of the higher ranked type. + let id = TypeId::of::<RequestHintProto<Blocking>>(); + + // The type id for the lifetime containing value protocol trait object. + let name_id = TypeNameId::of_lower::<dyn RequestHint<Blocking> + Send + Sync>(); + + // They should be the same. + assert_eq!(id, name_id.into_type_id()); +} diff --git a/tests/protocol_visitor_sequence.rs b/tests/protocol_visitor_sequence.rs new file mode 100644 index 0000000..52433dc --- /dev/null +++ b/tests/protocol_visitor_sequence.rs @@ -0,0 +1,76 @@ +use std::any::TypeId; + +use common::protocol::sequence::{ + MockSequenceScopeVisitor, MockSequenceVisitor, SequenceScopeFactory, +}; +use treaty::{ + any::{OwnedStatic, TypeNameId}, + effect::Blocking, + protocol::{visitor::{Sequence, SequenceProto, ValueProto, VisitResult}, DynVisitor}, + Flow, +}; + +use crate::common::builder::MockBuilder; + +mod common; + +#[test] +fn sequence_has_scope_with_size_hint_and_next() { + let mut mock = MockSequenceVisitor::<Blocking>::new(); + + // Expect a visit with the sequence protocol. + mock.expect_visit().once().return_const( + (|(), scope| { + // Get the size hint from the sequence scope. + assert_eq!(scope.size_hint().into_inner(), (1, Some(1))); + + let mut visitor = MockBuilder::<(), (), ()>::new(); + + // Expect the walker to lookup a trait. + visitor.expect_traits().once().return_const(None); + + // Get the next item in the sequence from the walker. + scope.next(DynVisitor(&mut visitor)); + + // We are done. + VisitResult::Control(Flow::Done) + }) as SequenceScopeFactory<Blocking>, + ); + + // Everything goes throw the sequence protocol trait. + let visitor: &mut dyn Sequence<Blocking> = &mut mock; + + let mut scope = MockSequenceScopeVisitor::<Blocking>::new(); + + // Expect a size hint to be asked for. + scope.expect_size_hint().once().return_const((1, Some(1))); + + // Expect that one element is gotten from the sequence. + scope.expect_next().once().returning(|visitor| { + // Attempt to lookup a trait on the visitor. + assert!(visitor + .upcast::<ValueProto<OwnedStatic<i32>, Blocking>>() + .is_none()); + + // We are done. + Flow::Done + }); + + // Visit a sequence. + assert!(matches!( + visitor.visit(&mut scope).into_inner(), + VisitResult::Control(Flow::Done) + )); +} + +#[test] +fn sequence_proto() { + // The type id of the higher ranked type. + let id = TypeId::of::<SequenceProto<Blocking>>(); + + // The type id for the lifetime containing value protocol trait object. + let name_id = TypeNameId::of_lower::<dyn Sequence<Blocking> + Send + Sync>(); + + // They should be the same. + assert_eq!(id, name_id.into_type_id()); +} diff --git a/tests/protocol_visitor_tag.rs b/tests/protocol_visitor_tag.rs new file mode 100644 index 0000000..9e92ff6 --- /dev/null +++ b/tests/protocol_visitor_tag.rs @@ -0,0 +1,44 @@ +use common::protocol::tag::MockTagVisitor; +use treaty::{ + effect::Blocking, + protocol::visitor::{Tag, TagDyn, VisitResult}, + symbol::Symbol, + DynWalkerAdapter, Flow, +}; + +use crate::common::walker::MockWalker; + +mod common; + +#[test] +fn demo() { + let mut mock = MockTagVisitor::<TagDyn, Blocking>::new(); + + mock.expect_visit() + .once() + .returning(|TagDyn(kind), walker| { + assert_eq!(kind, Symbol::new("test")); + + VisitResult::Control(Flow::Done) + }); + + let visitor: &mut dyn Tag<TagDyn, Blocking> = &mut mock; + + let mut walker = MockWalker::<(), ()>::new(); + + walker.expect_walk() + .once() + .returning(|visitor| { + + Ok(()) + }); + + let mut walker = DynWalkerAdapter::new(walker); + + assert!(matches!( + visitor + .visit(TagDyn(Symbol::new("test")), &mut walker) + .into_inner(), + VisitResult::Control(Flow::Done) + )); +} diff --git a/tests/protocol_visitor_value.rs b/tests/protocol_visitor_value.rs index ff17fc4..8ca591c 100644 --- a/tests/protocol_visitor_value.rs +++ b/tests/protocol_visitor_value.rs @@ -1,19 +1,18 @@ use std::any::TypeId; use common::protocol::{ - hint::{KnownFactory, MockHintVisitor}, + hint::{KnownFactory, MockHintWalker}, visitor::MockValueVisitor, }; use mockall::predicate::eq; use treaty::{ any::{ - BorrowedStatic, BorrowedStaticHrt, OwnedStatic, TempBorrowedMutStatic, + AnyTrait, BorrowedStatic, BorrowedStaticHrt, OwnedStatic, TempBorrowedMutStatic, TempBorrowedMutStaticHrt, TypeNameId, }, effect::Blocking, protocol::{ - visitor::{Value, ValueKnown, ValueProto, VisitResult}, - walker::hint::Hint, + visitor::{visit_value, Value, ValueKnown, ValueProto, VisitResult}, walker::hint::Hint, DynVisitor }, Flow, }; @@ -33,7 +32,7 @@ fn custom_value_type() { // Expect the visit method to be called once with the custom type. mock.expect_visit() - .once() + .times(2) .with(eq(OwnedStatic(MyValue))) .return_const(VisitResult::Control(Flow::Done)); @@ -42,10 +41,16 @@ fn custom_value_type() { let visitor: &mut dyn Value<OwnedStatic<MyValue>, Blocking> = &mut mock; // Visit the value. - let result = visitor.visit(OwnedStatic(MyValue)).into_innter(); + let result = visitor.visit(OwnedStatic(MyValue)).into_inner(); // The mock returns that it is done. assert_eq!(result, VisitResult::Control(Flow::Done)); + + let visitor: &mut (dyn AnyTrait + Send + Sync) = &mut mock; + assert_eq!( + visit_value::<_, Blocking>(DynVisitor(visitor), OwnedStatic(MyValue)).into_inner(), + VisitResult::Control(Flow::Done) + ); } /// Tests that a value with a lifetime can be given to the value protocol. @@ -67,7 +72,7 @@ fn borrowed_value() { // Expect the visit method to be called once with the borrowed value. mock.expect_visit() - .once() + .times(2) .withf(|BorrowedStatic(value)| *value == "test") .return_const(VisitResult::Control(Flow::Done)); @@ -76,6 +81,12 @@ fn borrowed_value() { // Visit the borrowed value. visitor.visit(BorrowedStatic(value)); + + let visitor: &mut (dyn AnyTrait + Send + Sync) = &mut mock; + assert_eq!( + visit_value::<_, Blocking>(DynVisitor(visitor), BorrowedStatic(value)).into_inner(), + VisitResult::Control(Flow::Done) + ); } // Make sure the compiler doesn't do anything funny with the lifetime. @@ -161,19 +172,19 @@ fn all_visit_results() { // Visit can return a done. assert_eq!( - visitor.visit(OwnedStatic(0)).into_innter(), + visitor.visit(OwnedStatic(0)).into_inner(), VisitResult::Control(Flow::Done) ); // Visit can return an error signal. assert_eq!( - visitor.visit(OwnedStatic(1)).into_innter(), + visitor.visit(OwnedStatic(1)).into_inner(), VisitResult::Control(Flow::Err) ); // Visit can return a continue. assert_eq!( - visitor.visit(OwnedStatic(2)).into_innter(), + visitor.visit(OwnedStatic(2)).into_inner(), VisitResult::Control(Flow::Continue) ); @@ -181,7 +192,7 @@ fn all_visit_results() { // This is for runtime visit support checking. // The value should be given back, but that's not forced. assert_eq!( - visitor.visit(OwnedStatic(3)).into_innter(), + visitor.visit(OwnedStatic(3)).into_inner(), VisitResult::Skipped(OwnedStatic(3)) ); } @@ -205,7 +216,7 @@ fn value_proto() { #[test] fn as_hint() { { - let mut mock = MockHintVisitor::<ValueProto<OwnedStatic<i32>, Blocking>, Blocking>::new(); + let mut mock = MockHintWalker::<ValueProto<OwnedStatic<i32>, Blocking>>::new(); mock.expect_known().once().return_const( (|_, _hint| { @@ -215,11 +226,11 @@ fn as_hint() { }) as KnownFactory<ValueProto<OwnedStatic<i32>, Blocking>>, ); - let walker: &mut dyn Hint<ValueProto<OwnedStatic<i32>, Blocking>, Blocking> = &mut mock; + let walker: &mut dyn Hint<ValueProto<OwnedStatic<i32>, Blocking>> = &mut mock; // The value protocol has no hint data, and it has no known data. assert_eq!( - walker.known(&()).into_innter(), + walker.known(&()).into_inner(), Ok(ValueKnown { preview: Some(&OwnedStatic(42)) }) @@ -227,8 +238,7 @@ fn as_hint() { } { - let mut mock = - MockHintVisitor::<ValueProto<BorrowedStaticHrt<i32>, Blocking>, Blocking>::new(); + let mut mock = MockHintWalker::<ValueProto<BorrowedStaticHrt<i32>, Blocking>>::new(); mock.expect_known().once().return_const( (|_, _hint| { @@ -238,12 +248,11 @@ fn as_hint() { }) as KnownFactory<ValueProto<BorrowedStaticHrt<i32>, Blocking>>, ); - let walker: &mut dyn Hint<ValueProto<BorrowedStaticHrt<i32>, Blocking>, Blocking> = - &mut mock; + let walker: &mut dyn Hint<ValueProto<BorrowedStaticHrt<i32>, Blocking>> = &mut mock; // The value protocol has no hint data, and it has no known data. assert_eq!( - walker.known(&()).into_innter(), + walker.known(&()).into_inner(), Ok(ValueKnown { preview: Some(&BorrowedStatic(&42)) }) @@ -251,20 +260,18 @@ fn as_hint() { } { - let mut mock = - MockHintVisitor::<ValueProto<TempBorrowedMutStaticHrt<i32>, Blocking>, Blocking>::new(); + let mut mock = MockHintWalker::<ValueProto<TempBorrowedMutStaticHrt<i32>, Blocking>>::new(); mock.expect_known().once().return_const( (|_, _hint| Ok(ValueKnown { preview: None })) as KnownFactory<ValueProto<TempBorrowedMutStaticHrt<i32>, Blocking>>, ); - let walker: &mut dyn Hint<ValueProto<TempBorrowedMutStaticHrt<i32>, Blocking>, Blocking> = - &mut mock; + let walker: &mut dyn Hint<ValueProto<TempBorrowedMutStaticHrt<i32>, Blocking>> = &mut mock; // The value protocol has no hint data, and it has no known data. assert_eq!( - walker.known(&()).into_innter(), + walker.known(&()).into_inner(), Ok(ValueKnown { preview: None }) ); } diff --git a/tests/protocol_walker_hint.rs b/tests/protocol_walker_hint.rs new file mode 100644 index 0000000..6f39590 --- /dev/null +++ b/tests/protocol_walker_hint.rs @@ -0,0 +1,313 @@ +use std::any::TypeId; + +use common::protocol::hint::MockHintWalker; +use treaty::{ + any::TypeNameId, + effect::{Blocking, Effect, Future, Spin}, + hkt::higher_ranked_type, + protocol::{ + walker::hint::{self, Hint, HintMeta, HintProto, Meta, MetaKnown}, DynVisitor + }, + Flow, +}; + +use crate::common::{builder::MockBuilder, protocol::hint::KnownFactory}; + +mod common; + +/// This tests for the hint protocol being able to give the known info and being able to hint. +#[test] +fn can_get_known_and_hint() { + // The protocol we will hint for. + struct MyProtocol; + + // The known value for the protocol. + #[derive(Debug, PartialEq)] + struct Known(f32); + + // Link the higher ranked type with the known type. + higher_ranked_type! { + impl Meta { + impl['a, 'ctx] type T['a, 'ctx] for Known = Known; + impl['a, 'ctx] type HigherRanked['a, 'ctx] for Known = Known; + } + } + + #[derive(Debug, PartialEq)] + struct Hint(i32); + + higher_ranked_type! { + impl Meta { + impl['a, 'ctx] type T['a, 'ctx] for Hint = Hint; + impl['a, 'ctx] type HigherRanked['a, 'ctx] for Hint = Hint; + } + } + + // Enroll the protocol in the hint system. + impl HintMeta for MyProtocol { + type Known = Known; + type Hint = Hint; + type Effect = Blocking; + } + + let mut mock = MockHintWalker::<MyProtocol>::new(); + + mock.expect_known() + .once() + .return_const((|_, Hint(hint)| Ok(Known(*hint as f32))) as KnownFactory<MyProtocol>); + + mock.expect_hint() + .once() + .withf(|_visitor, Hint(hint)| *hint == 123) + .return_const(Flow::Done); + + // Get the mock as a hint protocol trait object. + let walker: &mut dyn hint::Hint<MyProtocol> = &mut mock; + + // We can call known to get what the walker knows about the protocol. + assert_eq!(walker.known(&Hint(42)).into_inner(), Ok(Known(42.0))); + + { + // A hint needs the visitor for the walker to walk. + let mut mock = MockBuilder::<(), (), ()>::new(); + + // We can call hint to "commit" to the protocol and ask the walker to use it. + walker.hint(DynVisitor(&mut mock), Hint(123)); + } +} + +#[test] +fn known_can_have_temp_mutable_borrow() { + struct MyProtocol; + + struct KnownHrt; + + #[derive(Debug, PartialEq)] + struct Known<'a>(&'a mut String); + + higher_ranked_type! { + impl Meta { + impl['a, 'ctx] type T['a, 'ctx] for KnownHrt = Known<'a>; + impl['a, 'ctx] type HigherRanked['a, 'ctx] for Known<'a> = KnownHrt; + } + } + + impl HintMeta for MyProtocol { + type Known = KnownHrt; + type Hint = (); + type Effect = Blocking; + } + + struct Walker<'ctx>(&'ctx mut String); + + impl<'ctx> Hint<'ctx, MyProtocol> for Walker<'ctx> { + fn hint<'a>( + &'a mut self, + _visitor: DynVisitor<'a, 'ctx>, + _hint: <MyProtocol as HintMeta>::Hint, + ) -> Future<'a, Flow, Blocking> { + unreachable!() + } + + fn known<'a>( + &'a mut self, + (): &'a <MyProtocol as HintMeta>::Hint, + ) -> Future<'a, Result<MetaKnown<'a, 'ctx, MyProtocol>, ()>, Blocking> { + self.0.push_str("test"); + + Blocking::<Spin>::ready(Ok(Known(self.0))) + } + } + + let mut context = String::new(); + + { + let mut walker = Walker(&mut context); + + // Get the mock as a hint protocol trait object. + let walker: &mut dyn Hint<MyProtocol> = &mut walker; + + // We can call known to get what the walker knows about the protocol. + let mut x = String::from("test"); + assert_eq!(walker.known(&()).into_inner(), Ok(Known(&mut x))); + } + + drop(context); +} + +#[test] +fn known_can_have_context_borrow() { + struct MyProtocol; + + struct KnownHrt; + + #[derive(Debug, PartialEq)] + struct Known<'ctx>(&'ctx String); + + higher_ranked_type! { + impl Meta { + impl['a, 'ctx] type T['a, 'ctx] for KnownHrt = Known<'ctx>; + impl['a, 'ctx] type HigherRanked['a, 'ctx] for Known<'ctx> = KnownHrt; + } + } + + impl HintMeta for MyProtocol { + type Known = KnownHrt; + type Hint = (); + type Effect = Blocking; + } + + struct Walker<'ctx>(&'ctx String); + + impl<'ctx> Hint<'ctx, MyProtocol> for Walker<'ctx> { + fn hint<'a>( + &'a mut self, + _visitor: DynVisitor<'a, 'ctx>, + _hint: <MyProtocol as HintMeta>::Hint, + ) -> Future<'a, Flow, Blocking> { + unreachable!() + } + + fn known<'a>( + &'a mut self, + (): &'a <MyProtocol as HintMeta>::Hint, + ) -> Future<'a, Result<MetaKnown<'a, 'ctx, MyProtocol>, ()>, Blocking> { + Blocking::<Spin>::ready(Ok(Known(self.0))) + } + } + + let mut context = String::from("test"); + + let ctx = { + let mut walker = Walker(&mut context); + + // Get the mock as a hint protocol trait object. + let walker: &mut dyn Hint<MyProtocol> = &mut walker; + + // We can call known to get what the walker knows about the protocol. + let Ok(Known(y)) = walker.known(&()).into_inner() else { + unreachable!() + }; + y + }; + + assert_eq!(ctx, "test"); + + drop(context); +} + +#[test] +fn hint_can_have_temp_mutable_borrow() { + struct MyProtocol; + + struct HintHrt; + + #[derive(Debug, PartialEq)] + struct Hint<'a>(&'a mut String); + + higher_ranked_type! { + impl Meta { + impl['a, 'ctx] type T['a, 'ctx] for HintHrt = Hint<'a>; + impl['a, 'ctx] type HigherRanked['a, 'ctx] for Hint<'a> = HintHrt; + } + } + + impl HintMeta for MyProtocol { + type Known = (); + type Hint = HintHrt; + type Effect = Blocking; + } + + let mut mock = MockHintWalker::new(); + + mock.expect_hint().once().returning(|_, hint: Hint| { + hint.0.push_str("test"); + + Flow::Done + }); + + { + // Get the mock as a hint protocol trait object. + let walker: &mut dyn hint::Hint<MyProtocol> = &mut mock; + + let mut visitor = MockBuilder::<(), (), ()>::new(); + + let mut temp = String::new(); + + // We can call known to get what the walker knows about the protocol. + assert_eq!( + walker.hint(DynVisitor(&mut visitor), Hint(&mut temp)).into_inner(), + Flow::Done + ); + + assert_eq!(temp, "test"); + } +} + +#[test] +fn hint_can_have_context_borrow() { + struct MyProtocol; + + struct HintHrt; + + #[derive(Debug, PartialEq)] + struct Hint<'ctx>(&'ctx String); + + higher_ranked_type! { + impl Meta { + impl['a, 'ctx] type T['a, 'ctx] for HintHrt = Hint<'ctx>; + impl['a, 'ctx] type HigherRanked['a, 'ctx] for Hint<'ctx> = HintHrt; + } + } + + impl HintMeta for MyProtocol { + type Known = (); + type Hint = HintHrt; + type Effect = Blocking; + } + + let mut mock = MockHintWalker::new(); + + mock.expect_hint().once().returning(|_, hint: Hint| { + assert_eq!(hint.0, "test"); + + Flow::Done + }); + + let context = String::from("test"); + + { + // Get the mock as a hint protocol trait object. + let walker: &mut dyn hint::Hint<MyProtocol> = &mut mock; + + let mut visitor = MockBuilder::<(), (), ()>::new(); + + // We can call known to get what the walker knows about the protocol. + assert_eq!( + walker.hint(DynVisitor(&mut visitor), Hint(&context)).into_inner(), + Flow::Done + ); + } + + drop(context); +} + +#[test] +fn hint_proto() { + struct MyProtocol; + + impl HintMeta for MyProtocol { + type Known = (); + type Hint = (); + type Effect = Blocking; + } + + // The type id of the higher ranked type. + let id = TypeId::of::<HintProto<MyProtocol>>(); + + // The type id for the lifetime containing value protocol trait object. + let name_id = TypeNameId::of_lower::<dyn hint::Hint<MyProtocol> + Send + Sync>(); + + // They should be the same. + assert_eq!(id, name_id.into_type_id()); +} diff --git a/tests/walk.rs b/tests/walk.rs deleted file mode 100644 index f83ef24..0000000 --- a/tests/walk.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod common; - -mod walkers; diff --git a/tests/walkers/core.rs b/tests/walkers/core.rs deleted file mode 100644 index c10aef3..0000000 --- a/tests/walkers/core.rs +++ /dev/null @@ -1 +0,0 @@ -mod r#struct; diff --git a/tests/walkers/core/struct.rs b/tests/walkers/core/struct.rs deleted file mode 100644 index 9ac2d59..0000000 --- a/tests/walkers/core/struct.rs +++ /dev/null @@ -1,146 +0,0 @@ -use mockall::{predicate::eq, Sequence}; -use treaty::{ - any::{OwnedStatic, TypeNameId}, - effect::{BlockOn, Blocking, Effect, Future, Spin}, - protocol::{ - visitor::{TagConst, TagProto, ValueProto}, - Visitor, - }, - walkers::core::{ - r#struct::{StructTypeInfo, StructWalker}, - value::ValueWalker, - }, - Builder, DefaultMode, Flow, Walker, TAG_STRUCT, TAG_TYPE_NAME, -}; - -use crate::common::{ - builder::MockBuilder, - protocol::{tag::MockTagVisitor, visitor::MockValueVisitor}, -}; - -struct Demo { - a: bool, - b: bool, -} - -impl<'ctx, M> StructTypeInfo<'ctx, M> for Demo { - const NAME: &'static str = "Demo"; - - const FIELDS: &'static [&'static str] = &["a", "b"]; - - type FieldError = (); - - type T = Demo; - - fn walk_field<'a, E: Effect>( - index: usize, - value: &'ctx Self::T, - visitor: Visitor<'a, 'ctx>, - ) -> Future<'a, Result<Flow, Self::FieldError>, E> { - E::wrap(async move { - match index { - 0 => { - let walker = ValueWalker::<bool>::new(value.a); - Walker::<E>::walk(walker, visitor).await.unwrap(); - Ok(Flow::Continue) - } - 1 => { - let walker = ValueWalker::<bool>::new(value.b); - Walker::<E>::walk(walker, visitor).await.unwrap(); - Ok(Flow::Continue) - } - _ => Ok(Flow::Done), - } - }) - } -} - -#[test] -fn demo2() { - let mut builder = MockBuilder::<(), (), ()>::new(); - - let mut seq = Sequence::new(); - - builder - .expect_traits_mut() - .times(4) - .in_sequence(&mut seq) - .return_var(None); - - builder - .expect_traits_mut() - .once() - .with(eq(TypeNameId::of::< - TagProto<TagConst<{ TAG_STRUCT.to_int() }>, Blocking>, - >())) - .in_sequence(&mut seq) - .return_var(Some(Box::new({ - let mut mock = MockTagVisitor::<TagConst<{ TAG_STRUCT.to_int() }>, Blocking>::new(); - - mock.expect_visit().once().returning(|_, walker| { - let mut builder = MockBuilder::<(), (), ()>::new(); - assert_eq!( - Spin::block_on(walker.walk(Builder::<Blocking>::as_visitor(&mut builder))), - Flow::Done - ); - - Flow::Continue.into() - }); - - mock - }))); - - builder - .expect_traits_mut() - .once() - .with(eq(TypeNameId::of::< - TagProto<TagConst<{ TAG_TYPE_NAME.to_int() }>, Blocking>, - >())) - .in_sequence(&mut seq) - .return_var(Some(Box::new({ - let mut mock = MockTagVisitor::<TagConst<{ TAG_TYPE_NAME.to_int() }>, Blocking>::new(); - - mock.expect_visit().return_once(|_, walker| { - let mut builder = MockBuilder::<(), (), ()>::new(); - - builder - .expect_traits_mut() - .once() - .with(eq(TypeNameId::of::< - ValueProto<OwnedStatic<&'static str>, Blocking>, - >())) - .return_var(Some(Box::new({ - let mut mock = - MockValueVisitor::<OwnedStatic<&'static str>, Blocking>::new(); - - mock.expect_visit() - .once() - .with(eq(OwnedStatic("Demo"))) - .return_const(Flow::Done); - - mock - }))); - - assert_eq!( - Spin::block_on(walker.walk(Builder::<Blocking>::as_visitor(&mut builder))), - Flow::Done - ); - - Flow::Continue.into() - }); - - mock - }))); - - builder - .expect_traits_mut() - .times(3) - .in_sequence(&mut seq) - .return_var(None); - - let value = Demo { a: true, b: false }; - - let walker = StructWalker::<Demo, Demo, DefaultMode, Blocking>::new(&value); - - Spin::block_on(walker.walk(Builder::<Blocking>::as_visitor(&mut builder))).unwrap(); -} diff --git a/tests/walkers/mod.rs b/tests/walkers/mod.rs deleted file mode 100644 index 9816037..0000000 --- a/tests/walkers/mod.rs +++ /dev/null @@ -1 +0,0 @@ -mod core; |