Diffstat (limited to 'tests/async.rs')
| -rw-r--r-- | tests/async.rs | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/tests/async.rs b/tests/async.rs new file mode 100644 index 0000000..2c446a1 --- /dev/null +++ b/tests/async.rs @@ -0,0 +1,148 @@ +use std::{collections::VecDeque, future::Future, ops::ControlFlow, pin::Pin}; +use treaty::{ + any::{any_trait, static_wrapper::OwnedStatic}, + async_build_with, build_with, into_walker, + protocol::{ + visitor::{Sequence, SequenceScope, Status, Value}, + AsyncEffect, ControlFlowFor, Visitor, + }, + Builder, Walk, Walker, +}; + +#[tokio::test] +async fn demo() { + let a = Data::Sequence(vec![ + Data::Bool(true), + Data::Sequence(vec![Data::Bool(false), Data::Bool(true)]), + Data::Bool(false), + ]); + + let s = async_build_with::<JsonLike, _>(into_walker(a)) + .await + .unwrap(); + + assert_eq!(s, "[true,[false,true,],false,]"); +} + +#[derive(Debug)] +enum Data { + Bool(bool), + Sequence(Vec<Data>), +} + +const _: () = { + struct Impl(Data); + + impl From<Data> for Impl { + fn from(value: Data) -> Self { + Self(value) + } + } + + impl<'ctx> Walk<'ctx> for Data { + type Walker = Impl; + } + + impl<'ctx> Walker<'ctx> for Impl { + type Effect = AsyncEffect; + + type Error = (); + + type Output = (); + + fn walk<'a>(self, visitor: &'a mut Visitor<'ctx>) -> ControlFlowFor<'a, AsyncEffect> { + Box::pin(async { + match self.0 { + Data::Bool(value) => walk_bool(value, visitor), + Data::Sequence(value) => walk_vec(value, visitor).await, + } + core::ops::ControlFlow::Continue(()) + }) + } + } +}; + +fn walk_bool(value: bool, visitor: &mut Visitor<'_>) { + visitor + .upcast_mut::<dyn Value<OwnedStatic<bool>>>() + .unwrap() + .visit(OwnedStatic(value)); +} + +async fn walk_vec(value: Vec<Data>, visitor: &mut Visitor<'_>) { + struct Scope(VecDeque<Data>); + + impl<'ctx> SequenceScope<'ctx, AsyncEffect> for Scope { + fn next<'a>( + &'a mut self, + visitor: &'a mut Visitor<'ctx>, + ) -> ControlFlowFor<'a, AsyncEffect, Status> { + Box::pin(async { + if let Some(value) = self.0.pop_front() { + into_walker(value).walk(visitor).await; + + ControlFlow::Continue(Status::Continue) + } else { + ControlFlow::Continue(Status::Done) + } + }) + } + } + + let mut scope = Scope(value.into()); + + visitor + .upcast_mut::<dyn Sequence<'_, AsyncEffect>>() + .unwrap() + .visit(&mut scope) + .await; +} + +#[derive(Default)] +struct JsonLike(String); + +impl<'ctx> Builder<'ctx> for JsonLike { + type Error = (); + + type Value = String; + + fn as_visitor(&mut self) -> &mut Visitor<'ctx> { + self + } + + fn build(self) -> Result<Self::Value, Self::Error> { + Ok(self.0) + } +} + +any_trait! { + impl['a, 'ctx] JsonLike = [ + dyn Value<'a, OwnedStatic<bool>> + 'a, + dyn Sequence<'ctx, AsyncEffect> + 'a, + ]; +} + +impl Value<'_, OwnedStatic<bool>> for JsonLike { + fn visit(&mut self, value: OwnedStatic<bool>) -> core::ops::ControlFlow<()> { + self.0.push_str(&format!("{}", value.0)); + std::ops::ControlFlow::Continue(()) + } +} + +impl<'ctx> Sequence<'ctx, AsyncEffect> for JsonLike { + fn visit<'a>( + &'a mut self, + scope: &'a mut dyn SequenceScope<'ctx, AsyncEffect>, + ) -> ControlFlowFor<'a, AsyncEffect> { + Box::pin(async { + self.0.push_str("["); + while let std::ops::ControlFlow::Continue(treaty::protocol::visitor::Status::Continue) = + scope.next(self).await + { + self.0.push_str(","); + } + self.0.push_str("]"); + std::ops::ControlFlow::Continue(()) + }) + } +} |