all protocols are tested
| -rw-r--r-- | src/build/builders/debug.rs | 6 | ||||
| -rw-r--r-- | src/protocol/visitor/tag.rs | 2 | ||||
| -rw-r--r-- | src/protocol/visitor/value.rs | 4 | ||||
| -rw-r--r-- | src/walk/walkers/core/struct.rs | 5 | ||||
| -rw-r--r-- | src/walk/walkers/core/tag.rs | 3 | ||||
| -rw-r--r-- | tests/common/protocol.rs | 1 | ||||
| -rw-r--r-- | tests/common/protocol/recoverable.rs | 57 | ||||
| -rw-r--r-- | tests/protocol_visitor_recoverable.rs | 68 | ||||
| -rw-r--r-- | tests/protocol_visitor_request_hint.rs | 5 | ||||
| -rw-r--r-- | tests/protocol_visitor_sequence.rs | 5 | ||||
| -rw-r--r-- | tests/protocol_visitor_tag.rs | 102 | ||||
| -rw-r--r-- | tests/protocol_visitor_value.rs | 4 | ||||
| -rw-r--r-- | tests/protocol_walker_hint.rs | 11 |
13 files changed, 250 insertions, 23 deletions
diff --git a/src/build/builders/debug.rs b/src/build/builders/debug.rs index cb447b6..b0b8003 100644 --- a/src/build/builders/debug.rs +++ b/src/build/builders/debug.rs @@ -5,10 +5,12 @@ use crate::{ any_trait, effect::{Effect, Future}, protocol::{ - self, visitor::{ + self, + visitor::{ DynSequenceScope, RequestHint, RequestHintProto, Sequence, Tag, TagDyn, TagProto, Value, ValueProto, VisitResult, - }, DynVisitor + }, + DynVisitor, }, protocol::{visitor::SequenceProto, DynWalker}, DynWalkerObjSafe, Flow, diff --git a/src/protocol/visitor/tag.rs b/src/protocol/visitor/tag.rs index dbedd22..67ac325 100644 --- a/src/protocol/visitor/tag.rs +++ b/src/protocol/visitor/tag.rs @@ -8,7 +8,7 @@ use crate::{ DynVisitor, }, symbol::Symbol, - DynWalkerObjSafe, DynWalkerAdapter, DynWalkerError, WalkerTypes, + DynWalkerAdapter, DynWalkerError, DynWalkerObjSafe, WalkerTypes, }; use super::VisitResult; diff --git a/src/protocol/visitor/value.rs b/src/protocol/visitor/value.rs index 8e902ab..e549935 100644 --- a/src/protocol/visitor/value.rs +++ b/src/protocol/visitor/value.rs @@ -100,7 +100,9 @@ pub fn visit_value<'a, 'ctx, T: Send + TypeName::LowerType<'a, 'ctx>, E: Effect> where TypeName::HigherRanked<'a, 'ctx, T>: TypeName::MemberType, { - if let Some(object) = visitor.0.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) diff --git a/src/walk/walkers/core/struct.rs b/src/walk/walkers/core/struct.rs index 8fe0ce0..6a8119d 100644 --- a/src/walk/walkers/core/struct.rs +++ b/src/walk/walkers/core/struct.rs @@ -12,7 +12,10 @@ use crate::{ RecoverableKnown, RecoverableProto, RecoverableScope, SequenceKnown, SequenceProto, SequenceScope, TagConst, TagDyn, TagError, TagHint, TagKnown, TagProto, ValueKnown, ValueProto, VisitResult, - }, walker::hint::{Hint, MetaKnown}, walker::hint::{HintMeta, HintProto, MetaHint}, DynVisitor, DynWalker + }, + 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, }; diff --git a/src/walk/walkers/core/tag.rs b/src/walk/walkers/core/tag.rs index f20b449..29a450e 100644 --- a/src/walk/walkers/core/tag.rs +++ b/src/walk/walkers/core/tag.rs @@ -8,7 +8,8 @@ use crate::{ protocol::{ visitor::{ visit_request_hint, visit_value, SequenceProto, SequenceScope, TagError, VisitResult, - }, DynVisitor, DynWalker + }, + DynVisitor, DynWalker, }, Flow, WalkerTypes, }; diff --git a/tests/common/protocol.rs b/tests/common/protocol.rs index ab619e0..38c0c61 100644 --- a/tests/common/protocol.rs +++ b/tests/common/protocol.rs @@ -1,4 +1,5 @@ pub mod hint; +pub mod recoverable; pub mod request_hint; pub mod sequence; pub mod tag; diff --git a/tests/common/protocol/recoverable.rs b/tests/common/protocol/recoverable.rs new file mode 100644 index 0000000..f1dab5c --- /dev/null +++ b/tests/common/protocol/recoverable.rs @@ -0,0 +1,57 @@ +use mockall::mock; +use treaty::{ + any::{any_trait, TypeName}, + effect::{Effect, Future}, + protocol::{ + visitor::{DynRecoverableScope, Recoverable, RecoverableProto, RecoverableScope}, + DynWalker, + }, + protocol::{ + visitor::{ + DynSequenceScope, RequestHint, RequestHintProto, Sequence, SequenceProto, + SequenceScope, Value, ValueProto, VisitResult, + }, + DynVisitor, + }, + Flow, Status, +}; + +pub type RecoverableScopeFactory<E> = + for<'a, 'ctx> fn( + &'ctx (), + DynRecoverableScope<'a, 'ctx, E>, + ) -> VisitResult<DynRecoverableScope<'a, 'ctx, E>>; + +mock! { + pub RecoverableVisitor<E> { + pub fn visit(&mut self) -> RecoverableScopeFactory<E>; + } +} + +any_trait! { + impl['ctx, E] MockRecoverableVisitor<E> = [ + RecoverableProto<E> + ] where + E: Effect, +} + +impl<'ctx, E: Effect> Recoverable<'ctx, E> for MockRecoverableVisitor<E> { + fn visit<'a>( + &'a mut self, + scope: DynRecoverableScope<'a, 'ctx, E>, + ) -> Future<'a, VisitResult<DynRecoverableScope<'a, 'ctx, E>>, E> { + E::ready(self.visit()(&(), scope)) + } +} + +mock! { + pub RecoverableScopeVisitor<E> { + pub fn new_walk<'a, 'ctx>(&'a mut self, visitor: DynVisitor<'a, 'ctx>) -> Status; + } +} + +impl<'ctx, E: Effect> RecoverableScope<'ctx, E> for MockRecoverableScopeVisitor<E> { + fn new_walk<'a>(&'a mut self, visitor: DynVisitor<'a, 'ctx>) -> Future<'a, Status, E> { + E::ready(self.new_walk(visitor)) + } +} diff --git a/tests/protocol_visitor_recoverable.rs b/tests/protocol_visitor_recoverable.rs new file mode 100644 index 0000000..07ec092 --- /dev/null +++ b/tests/protocol_visitor_recoverable.rs @@ -0,0 +1,68 @@ +use common::protocol::recoverable::MockRecoverableVisitor; +use treaty::{ + any::OwnedStatic, + effect::Blocking, + protocol::{ + visitor::{Recoverable, ValueProto, VisitResult}, + DynVisitor, + }, + Flow, +}; + +use crate::common::{ + builder::MockBuilder, + protocol::recoverable::{MockRecoverableScopeVisitor, RecoverableScopeFactory}, +}; + +mod common; + +/// Tests that the recoverable protocol allows multiple walks by the visitor. +#[test] +fn recoverable_can_be_visited() { + let mut mock = MockRecoverableVisitor::<Blocking>::new(); + + // Expect a visit using the rescoverable protocol. + mock.expect_visit().once().return_const( + (|(), scope| { + let mut visitor = MockBuilder::<(), (), ()>::new(); + + // Expect that the visitor gets used. + visitor.expect_traits().times(2).return_const(None); + + // Attempt to walk once. + assert_eq!( + scope.new_walk(DynVisitor(&mut visitor)).into_inner(), + Ok(()) + ); + + // Attempt to walk twice. + assert_eq!( + scope.new_walk(DynVisitor(&mut visitor)).into_inner(), + Ok(()) + ); + + // We are done. + VisitResult::Control(Flow::Done) + }) as RecoverableScopeFactory<Blocking>, + ); + + let visitor: &mut dyn Recoverable<Blocking> = &mut mock; + + let mut scope = MockRecoverableScopeVisitor::new(); + + // Expect two walks of the recoverable walker. + scope.expect_new_walk().times(2).returning(|visitor| { + // Attempt to use the visitor. + assert!(visitor + .upcast::<ValueProto<OwnedStatic<i32>, Blocking>>() + .is_none()); + + Ok(()) + }); + + // Visit using the recoverable protocol. + assert!(matches!( + visitor.visit(&mut scope).into_inner(), + VisitResult::Control(Flow::Done) + )); +} diff --git a/tests/protocol_visitor_request_hint.rs b/tests/protocol_visitor_request_hint.rs index 234d64f..06f811f 100644 --- a/tests/protocol_visitor_request_hint.rs +++ b/tests/protocol_visitor_request_hint.rs @@ -14,6 +14,7 @@ use treaty::{ protocol::{ visitor::{RequestHint, RequestHintProto, ValueKnown, ValueProto, VisitResult}, walker::hint::HintProto, + DynWalker, }, Flow, }; @@ -28,7 +29,7 @@ fn hints_can_be_requested() { // We will request a hint from the visitor. mock.expect_request_hint().once().return_const( - (|_, walker| { + (|_, mut walker| { // Lookup the value protocol on the walker. let obj = walker .upcast_mut::<HintProto<ValueProto<OwnedStatic<i32>, Blocking>>>() @@ -75,7 +76,7 @@ fn hints_can_be_requested() { // Request a hint from the visitor. assert!(matches!( - visitor.request_hint(&mut mock).into_inner(), + visitor.request_hint(DynWalker(&mut mock)).into_inner(), VisitResult::Control(Flow::Done) )); } diff --git a/tests/protocol_visitor_sequence.rs b/tests/protocol_visitor_sequence.rs index 52433dc..1b74c3f 100644 --- a/tests/protocol_visitor_sequence.rs +++ b/tests/protocol_visitor_sequence.rs @@ -6,7 +6,10 @@ use common::protocol::sequence::{ use treaty::{ any::{OwnedStatic, TypeNameId}, effect::Blocking, - protocol::{visitor::{Sequence, SequenceProto, ValueProto, VisitResult}, DynVisitor}, + protocol::{ + visitor::{Sequence, SequenceProto, ValueProto, VisitResult}, + DynVisitor, + }, Flow, }; diff --git a/tests/protocol_visitor_tag.rs b/tests/protocol_visitor_tag.rs index 9e92ff6..eb24523 100644 --- a/tests/protocol_visitor_tag.rs +++ b/tests/protocol_visitor_tag.rs @@ -1,40 +1,64 @@ +use std::any::TypeId; + use common::protocol::tag::MockTagVisitor; use treaty::{ + any::{OwnedStatic, TypeNameId}, effect::Blocking, - protocol::visitor::{Tag, TagDyn, VisitResult}, + protocol::{ + visitor::{Tag, TagConst, TagDyn, TagProto, ValueProto, VisitResult}, + DynVisitor, + }, symbol::Symbol, DynWalkerAdapter, Flow, }; -use crate::common::walker::MockWalker; +use crate::common::{builder::MockBuilder, walker::MockWalker}; mod common; +/// Tests that the tag protocol can be visited with a value walker. #[test] -fn demo() { +fn tag_can_be_visited() { let mut mock = MockTagVisitor::<TagDyn, Blocking>::new(); + // Expect a visit with the tag protocol. mock.expect_visit() .once() .returning(|TagDyn(kind), walker| { + // The kind should be test. assert_eq!(kind, Symbol::new("test")); - + + let mut builder = MockBuilder::<(), (), ()>::new(); + + // Expect that the builder is attempted to be used by the walker for the value. + builder.expect_traits().once().return_const(None); + + // Walk the value of the tag. + walker.walk(DynVisitor(&mut builder)); + + // We are done. VisitResult::Control(Flow::Done) }); + // Use the tag protocol trait. let visitor: &mut dyn Tag<TagDyn, Blocking> = &mut mock; let mut walker = MockWalker::<(), ()>::new(); - walker.expect_walk() - .once() - .returning(|visitor| { - - Ok(()) - }); + // Expect the tag value to be walked. + walker.expect_walk().once().returning(|visitor| { + // Attempt to use the visitor. + assert!(visitor + .upcast::<ValueProto<OwnedStatic<i32>, Blocking>>() + .is_none()); + Ok(()) + }); + + // We need to use the adapter to make the walker object safe to pass to the protocol. let mut walker = DynWalkerAdapter::new(walker); + // Visit the tag protocol for kind test with the value walker. assert!(matches!( visitor .visit(TagDyn(Symbol::new("test")), &mut walker) @@ -42,3 +66,61 @@ fn demo() { VisitResult::Control(Flow::Done) )); } + +/// Checks that compile time tag symbols work. +#[test] +fn const_tag_can_be_visited() { + const TEST: u64 = Symbol::new("test").to_int(); + + let mut mock = MockTagVisitor::<TagConst<TEST>, Blocking>::new(); + + // Expect a visit with the tag protocol. + mock.expect_visit().once().returning(|TagConst, walker| { + let mut builder = MockBuilder::<(), (), ()>::new(); + + // Expect that the builder is attempted to be used by the walker for the value. + builder.expect_traits().once().return_const(None); + + // Walk the value of the tag. + walker.walk(DynVisitor(&mut builder)); + + // We are done. + VisitResult::Control(Flow::Done) + }); + + // Use the tag protocol trait. + let visitor: &mut dyn Tag<TagConst<TEST>, Blocking> = &mut mock; + + let mut walker = MockWalker::<(), ()>::new(); + + // Expect the tag value to be walked. + walker.expect_walk().once().returning(|visitor| { + // Attempt to use the visitor. + assert!(visitor + .upcast::<ValueProto<OwnedStatic<i32>, Blocking>>() + .is_none()); + + Ok(()) + }); + + // We need to use the adapter to make the walker object safe to pass to the protocol. + let mut walker = DynWalkerAdapter::new(walker); + + // Visit the tag protocol for kind test with the value walker. + assert!(matches!( + visitor.visit(TagConst, &mut walker).into_inner(), + VisitResult::Control(Flow::Done) + )); +} + +#[test] +fn tag_proto() { + // The type id of the higher ranked type. + let id = TypeId::of::<TagProto<TagDyn, Blocking>>(); + + // The type id for the lifetime containing value protocol trait object. + let name_id = TypeNameId::of_lower::<dyn Tag<TagDyn, Blocking> + Send + Sync>(); + + // They should be the same. + assert_eq!(id, name_id.into_type_id()); +} diff --git a/tests/protocol_visitor_value.rs b/tests/protocol_visitor_value.rs index 8ca591c..374ed99 100644 --- a/tests/protocol_visitor_value.rs +++ b/tests/protocol_visitor_value.rs @@ -12,7 +12,9 @@ use treaty::{ }, effect::Blocking, protocol::{ - visitor::{visit_value, Value, ValueKnown, ValueProto, VisitResult}, walker::hint::Hint, DynVisitor + visitor::{visit_value, Value, ValueKnown, ValueProto, VisitResult}, + walker::hint::Hint, + DynVisitor, }, Flow, }; diff --git a/tests/protocol_walker_hint.rs b/tests/protocol_walker_hint.rs index 6f39590..d15d345 100644 --- a/tests/protocol_walker_hint.rs +++ b/tests/protocol_walker_hint.rs @@ -6,7 +6,8 @@ use treaty::{ effect::{Blocking, Effect, Future, Spin}, hkt::higher_ranked_type, protocol::{ - walker::hint::{self, Hint, HintMeta, HintProto, Meta, MetaKnown}, DynVisitor + walker::hint::{self, Hint, HintMeta, HintProto, Meta, MetaKnown}, + DynVisitor, }, Flow, }; @@ -236,7 +237,9 @@ fn hint_can_have_temp_mutable_borrow() { // 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(), + walker + .hint(DynVisitor(&mut visitor), Hint(&mut temp)) + .into_inner(), Flow::Done ); @@ -284,7 +287,9 @@ fn hint_can_have_context_borrow() { // We can call known to get what the walker knows about the protocol. assert_eq!( - walker.hint(DynVisitor(&mut visitor), Hint(&context)).into_inner(), + walker + .hint(DynVisitor(&mut visitor), Hint(&context)) + .into_inner(), Flow::Done ); } |