/* use effectful::{ bound::{Dynamic, ForceDynamic}, effective::{Effective, Canonical}, environment::{Environment}, DynBind, SendSync, }; use mockall::predicate::eq; use treaty::{ any::{BorrowedStatic, OwnedStatic}, protocol::{ visitor::{tags, TagConst, VisitResult}, AsVisitor, DynVisitor, }, walk::walkers::core::r#struct::{StructTypeInfo, StructWalker}, DefaultMode, Flow, Walker, }; use effectful::blocking::BlockingSpin; use crate::common::{ builder::{EmptyError, MockBuilder}, protocol::{sequence::MockSequenceVisitor, tag::MockTagVisitor, value::MockValueVisitor}, }; mod common; #[derive(SendSync)] struct X { a: bool, b: i32, } struct Info; // This gives the struct walker enough information to walk the X struct. impl<'ctx, M, E: Environment> StructTypeInfo<'ctx, M, E> for Info where Dynamic>: DynBind, Dynamic>: DynBind, { const NAME: &'static str = "X"; const FIELDS: &'static [&'static str] = &["a", "b"]; type FieldError = (); type S = StaticType; type T = X; fn walk_field<'a>( index: usize, value: &'ctx Self::T, mut visitor: DynVisitor<'a, 'ctx, E>, ) -> Canonical<'a, Result, E> { E::future(unsafe { ForceDynamic::new(async move { match index { // A real impl would be expected to tag these values with the field name. 0 => { // Basic visit for the field value. let obj = visitor .upcast_mut::, E>>() .unwrap(); // Emit the field value. assert_eq!( obj.visit(OwnedStatic(value.a)).into_future().await, Flow::Done.into() ); // There are more fields. Ok(Flow::Continue) } 1 => { // Basic visit for the field value. let obj = visitor .upcast_mut::, E>>() .unwrap(); // Emit the field value. assert_eq!( obj.visit(OwnedStatic(value.b)).into_future().await, Flow::Done.into() ); // There are no more fields. Ok(Flow::Done) } _ => Ok(Flow::Done), } }) }) .cast() } } /// Tests that a struct walker in its most basic form just emits a sequence of field values. /// /// This makes structs behave like tuples (lists) if the builder doesn't know about any of the /// extra tags. #[test] fn sequence_of_field_values() { // The struct value to walk. let value = X { a: true, b: 42 }; // The struct walker using the info we provided about the struct. let walker = StructWalker::::new(&value); let mut builder = MockBuilder::<(), (), EmptyError, BlockingSpin>::new(); // Expect a visit on the sequence protocol for the struct fields. builder .expect_traits_mut() .once() .with(eq(TypeNameId::of::, BlockingSpin>())) .returning(|_| { let mut visitor = MockSequenceVisitor::::new(); // Expect the sequence visitor to be used. visitor.expect_visit().once().returning(|scope| { // The struct should have exactly 2 fields. assert_eq!(scope.size_hint().into_value(), (2, Some(2))); // Get the first field value. { let mut visitor = MockBuilder::<(), (), EmptyError, BlockingSpin>::new(); // Expect a bool value for the field. visitor .expect_traits_mut() .once() .with(eq(TypeNameId::of::< ValueProto, BlockingSpin>, BlockingSpin, >())) .returning(|_| { let mut visitor = MockValueVisitor::, BlockingSpin>::new(); // Expect true. visitor .expect_visit() .once() .with(eq(OwnedStatic(true))) .return_const(Flow::Done); Some(Box::new(DynamicShim(visitor))) }); assert_eq!( scope.next(AsVisitor::as_visitor(&mut visitor)).into_value(), Flow::Continue ); } // Get the second field value. { let mut visitor = MockBuilder::<(), (), EmptyError, BlockingSpin>::new(); // Expect a i32 value. visitor .expect_traits_mut() .once() .with(eq(TypeNameId::of::< ValueProto, BlockingSpin>, BlockingSpin, >())) .returning(|_| { let mut visitor = MockValueVisitor::, BlockingSpin>::new(); // Expect a 42. visitor .expect_visit() .once() .with(eq(OwnedStatic(42))) .return_const(Flow::Done); Some(Box::new(DynamicShim(visitor))) }); assert_eq!( scope.next(AsVisitor::as_visitor(&mut visitor)).into_value(), Flow::Done ); } // We are done with the sequence of fields. VisitResult::Control(Flow::Done) }); Some(Box::new(DynamicShim(visitor))) }); // All other protocols are not used for this test. builder.expect_traits_mut().return_var(None); // Walk the struct. assert_eq!( walker .walk(AsVisitor::as_visitor(&mut builder)) .into_value(), Ok(()) ); } #[test] fn has_struct_tag() { // The struct value to walk. let value = X { a: true, b: 42 }; // The struct walker using the info we provided about the struct. let walker = StructWalker::::new(&value); let mut builder = MockBuilder::<(), (), EmptyError, BlockingSpin>::new(); let mut seq = mockall::Sequence::new(); // Skip the request hint, borrowed value, and type id. builder .expect_traits_mut() .times(4) .in_sequence(&mut seq) .return_var(None); // Expect that the tag for a struct is emmited. builder .expect_traits_mut() .once() .in_sequence(&mut seq) .with(eq(TypeNameId::of::< TagProto, Blocking, >())) .returning(|_| { let mut visitor = MockTagVisitor::::new(); visitor.expect_visit().once().returning(|TagConst, walker| { let mut visitor = MockBuilder::<(), (), (), Blocking>::new(); // Walk the noop walker so there isn't an error. assert_eq!( walker.walk(DynVisitor(&mut visitor)).into_value(), Flow::Done ); // We are done, the walker should now stop early. VisitResult::Control(Flow::Done) }); Some(Box::new(DynamicShim(visitor))) }); // Walk the struct. assert_eq!( walker .walk(AsVisitor::as_visitor(&mut builder)) .into_value(), Ok(()) ); } #[test] fn has_map_backup_tag() { // The struct value to walk. let value = X { a: true, b: 42 }; // The struct walker using the info we provided about the struct. let walker = StructWalker::::new(&value); let mut builder = MockBuilder::<(), (), EmptyError, Blocking>::new(); let mut seq = mockall::Sequence::new(); // Skip the request hint, borrowed value type id, and struct tag. builder .expect_traits_mut() .times(6) .in_sequence(&mut seq) .return_var(None); // Expect that the tag for a map is emmited. // // This only happens if the struct tag isn't supported by the visitor. builder .expect_traits_mut() .once() .in_sequence(&mut seq) .with(eq( TypeNameId::of::, Blocking>(), )) .returning(|_| { let mut visitor = MockTagVisitor::::new(); visitor.expect_visit().once().returning(|TagConst, walker| { let mut visitor = MockBuilder::<(), (), (), Blocking>::new(); // Walk the noop walker so there isn't an error. assert_eq!( walker.walk(DynVisitor(&mut visitor)).into_value(), Flow::Done ); // We are done, the walker should now stop early. VisitResult::Control(Flow::Done) }); Some(Box::new(DynamicShim(visitor))) }); // Walk the struct. assert_eq!( walker .walk(AsVisitor::as_visitor(&mut builder)) .into_value(), Ok(()) ); } #[test] fn borrowed_value_directly() { // The struct value to walk. let value = X { a: true, b: 42 }; // The struct walker using the info we provided about the struct. let walker = StructWalker::::new(&value); let mut builder = MockBuilder::<(), (), EmptyError, Blocking>::new(); let mut seq = mockall::Sequence::new(); // Skip the request hint. builder .expect_traits_mut() .once() .in_sequence(&mut seq) .return_var(None); // Get the struct value directly from the walker. builder .expect_traits_mut() .once() .in_sequence(&mut seq) .with(eq(TypeNameId::of::< ValueProto, Blocking>, Blocking, >())) .returning(|_| { let mut visitor = MockValueVisitor::, Blocking>::new(); // Expect the struct value. visitor .expect_visit() .once() .returning(|BorrowedStatic(value)| { // Check the value to be the same. assert!(value.a); assert_eq!(value.b, 42); // We are done, the walker should now stop early. VisitResult::Control(Flow::Done) }); Some(Box::new(DynamicShim(visitor))) }); // Walk the struct. assert_eq!( walker .walk(AsVisitor::as_visitor(&mut builder)) .into_value(), Ok(()) ); } */