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<'a, '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<'a, '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(())
})
}
}