use macro_rules_attribute::derive;
use treaty::{
any::{OwnedStatic, TempBorrowedStatic},
builders::{self, core::r#struct::StructBuilder},
effect::{blocking::Blocking, Effect, Effective, ErasedEffective},
protocol::{
visitor::{tags, visit_sequence, visit_tag, visit_value, TagConst, VisitResult},
DynVisitor,
},
transform,
walkers::{
self,
core::{noop::NoopWalker, r#struct::StructWalker},
},
Build, Builder, DefaultMode, Flow, Walk, Walker,
};
use crate::common::{protocol::sequence::MockSequenceScope, walker::MockWalker};
mod common;
#[derive(Build!, Walk!, Debug, PartialEq)]
struct X {
a: bool,
b: bool,
}
#[test]
fn demo() {
let value = X { a: true, b: false };
let (other, _) = transform::<<X as Build<DefaultMode, _>>::Builder, _, Blocking>(
((), ()),
<&X as Walk<DefaultMode, _>>::Walker::new(&value),
)
.value();
assert_eq!(other.unwrap(), value);
}
#[test]
fn from_basic_tuple_like() {
// A tuple like is just a sequence.
let mut scope = MockSequenceScope::<Blocking>::new();
// First field.
scope.expect_next().once().returning(|visitor| {
// Visit a bool value.
//
// The bool visitor should report that it is done.
assert_eq!(
visit_value::<_, Blocking>(visitor, OwnedStatic(true)).value(),
VisitResult::Control(Flow::Done)
);
// We have another field.
Flow::Continue
});
// Second field.
scope.expect_next().once().returning(|visitor| {
// Visit a bool value.
//
// The bool visitor should report that it is done.
assert_eq!(
visit_value::<_, Blocking>(visitor, OwnedStatic(false)).value(),
VisitResult::Control(Flow::Done)
);
// No more fields.
Flow::Done
});
let mut builder = <X as Build<DefaultMode, Blocking>>::Builder::from_seed(((), ())).value();
let visitor = builder.as_visitor();
// Visit the sequence of field values.
assert!(matches!(
visit_sequence(visitor, &mut scope).value(),
VisitResult::Control(Flow::Done)
));
assert_eq!(builder.build().value().unwrap(), X { a: true, b: false });
}
#[test]
fn from_basic_map_like() {
// A map is built from a sequence.
let mut scope = MockSequenceScope::<Blocking>::new();
// Here we do the b field first to show a map-like doesn't care about order.
scope.expect_next().once().returning(|mut visitor| {
let mut walker = MockWalker::<(), ()>::new();
// We need to give the b field name in the key tag.
walker.expect_walk().once().returning(|visitor| {
assert_eq!(
visit_value::<_, Blocking>(visitor, TempBorrowedStatic("b")).value(),
VisitResult::Control(Flow::Done)
);
Ok(())
});
// Tag the value with a key as the field name.
assert_eq!(
visit_tag::<tags::Key, Blocking, _>(TagConst, visitor.cast(), walker).value(),
Ok(VisitResult::Control(Flow::Continue)),
);
// Visit the value as normal.
assert_eq!(
visit_value::<_, Blocking>(visitor, OwnedStatic(true)).value(),
VisitResult::Control(Flow::Done)
);
// There is another field.
Flow::Continue
});
// The other field.
scope.expect_next().once().returning(|mut visitor| {
let mut walker = MockWalker::<(), ()>::new();
// Here we do field a.
walker.expect_walk().once().returning(|visitor| {
assert_eq!(
visit_value::<_, Blocking>(visitor, TempBorrowedStatic("a")).value(),
VisitResult::Control(Flow::Done)
);
Ok(())
});
// Tag the value with a key.
assert_eq!(
visit_tag::<tags::Key, Blocking, _>(TagConst, visitor.cast(), walker).value(),
Ok(VisitResult::Control(Flow::Continue)),
);
// The field value.
assert_eq!(
visit_value::<_, Blocking>(visitor, OwnedStatic(false)).value(),
VisitResult::Control(Flow::Done)
);
// The sequence protocol allows for us to wait to decide if there is another item.
Flow::Continue
});
// There are no more fields.
scope.expect_next().once().returning(|_visitor| Flow::Done);
let mut builder = <X as Build<DefaultMode, Blocking>>::Builder::from_seed(((), ())).value();
let mut visitor = builder.as_visitor();
// We need to provide the map tag to the struct before getting into the sequence.
// This tag notifies the struct builder to expect the sequence as a map.
assert_eq!(
visit_tag::<tags::Map, Blocking, _>(TagConst, visitor.cast(), NoopWalker::new()).value(),
Ok(VisitResult::Control(Flow::Continue))
);
// Visit the sequence of fields.
assert_eq!(
visit_sequence(visitor, &mut scope).value(),
VisitResult::Control(Flow::Done)
);
// The struct is built as the mock walker above makes it.
assert_eq!(builder.build().value().unwrap(), X { a: false, b: true });
}
pub mod demo {
use crate::Walk;
use macro_rules_attribute::derive;
use treaty::{
effect::{
blocking::{BlockOn, Blocking, Spin},
// r#async::Async,
Effective as _,
},
transform, Build, DefaultMode,
};
#[derive(Walk!, Debug)]
pub struct X {
pub a: bool,
pub b: bool,
pub c: bool,
}
#[derive(Build!, Debug, PartialEq)]
pub struct Y {
pub b: bool,
pub a: bool,
pub c: bool,
}
#[no_mangle]
#[inline(never)]
pub fn ident(x: X) -> Y {
let other =
transform::<<Y as crate::Build<'_, DefaultMode, _>>::Builder, _, Blocking<Spin>>(
((), (), ()),
Walk::<DefaultMode, _>::into_walker(&x),
)
.value();
// let other = Spin::block_on(other.into_future());
other.0.unwrap()
}
#[test]
fn demo() {
assert_eq!(
ident(X {
a: true,
b: false,
c: true
}),
Y {
a: true,
b: false,
c: true
}
);
}
}