use crate::{
effect::{Effect, Future},
never::Never,
protocol::{
visitor::{visit_tag, TagConst, TagError, TagKind, VisitResult},
Visitor,
},
walkers::core::noop::NoopWalker,
Flow, WalkerTypes, TAG_KEY, TAG_KEY_VALUE, TAG_VALUE,
};
pub struct KeyValueWalker<T, K, V> {
key_walker: K,
value_walker: V,
tag: T,
}
impl<T, K, V> KeyValueWalker<T, K, V> {
pub fn new(tag: T, key_walker: K, value_walker: V) -> Self {
Self {
key_walker,
value_walker,
tag,
}
}
}
#[derive(Debug)]
#[allow(unused)]
enum KeyValueErrorKind<K, V> {
Tag(TagError<Never>),
Key(K),
Value(V),
}
#[derive(Debug)]
pub struct KeyValueError<K, V>(KeyValueErrorKind<K, V>);
impl<T, K, V> WalkerTypes for KeyValueWalker<T, K, V>
where
K: WalkerTypes,
V: WalkerTypes,
{
type Error = KeyValueError<K::Error, V::Error>;
type Output = ();
}
impl<'ctx, T, K, V, E> crate::Walker<'ctx, E> for KeyValueWalker<T, K, V>
where
E: Effect,
T: TagKind,
K: crate::Walker<'ctx, E>,
V: crate::Walker<'ctx, E>,
{
fn walk<'a>(
self,
visitor: Visitor<'a, 'ctx>,
) -> Future<'a, Result<Self::Output, Self::Error>, E>
where
Self: 'a,
{
E::wrap(async move {
match visit_tag::<T, E, _>(self.tag, visitor, NoopWalker::new()).await {
Ok(VisitResult::Skipped(_)) => {
match visit_tag::<TagConst<{ TAG_KEY_VALUE.to_int() }>, E, _>(
TagConst,
visitor,
NoopWalker::new(),
)
.await
{
Ok(VisitResult::Skipped(_) | VisitResult::Control(Flow::Continue)) => {}
Ok(VisitResult::Control(_flow)) => return Ok(()),
Err(_) => todo!(),
}
}
Ok(VisitResult::Control(Flow::Continue)) => {}
Ok(VisitResult::Control(_flow)) => todo!(),
Err(_) => todo!(),
}
match visit_tag::<TagConst<{ TAG_KEY.to_int() }>, E, _>(
TagConst,
visitor,
self.key_walker,
)
.await
{
Ok(VisitResult::Skipped(_) | VisitResult::Control(Flow::Continue)) => {}
Ok(VisitResult::Control(_flow)) => return Ok(()),
Err(_) => todo!(),
}
match visit_tag::<TagConst<{ TAG_VALUE.to_int() }>, E, _>(
TagConst,
visitor,
self.value_walker,
)
.await
{
Ok(VisitResult::Control(Flow::Continue)) => {}
Ok(VisitResult::Skipped(value_walker)) => {
// Fallback to just walking the value.
match value_walker.walk(visitor).await {
Ok(_) => {}
Err(_err) => todo!(),
}
}
Ok(VisitResult::Control(_flow)) => todo!(),
Err(_) => todo!(),
}
Ok(())
})
}
}