//! # Design
//!
#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
#![deny(elided_lifetimes_in_paths)]
#[cfg(feature = "alloc")]
extern crate alloc;
pub mod any;
mod build;
pub mod effect;
pub mod hkt;
pub mod protocol;
pub mod symbol;
mod walk;
// pub mod impls;
mod transform;
// pub use build::Build;
// pub use build::Builder;
//
// pub use walk::Walk;
// pub use walk::Walker;
use core::ops::ControlFlow;
pub use build::*;
use effect::{Effect, Future};
use protocol::Visitor;
use symbol::Symbol;
pub use transform::*;
pub use walk::*;
pub mod never {
mod sealed {
pub trait Extract {
type T;
}
impl<T> Extract for fn() -> T {
type T = T;
}
}
#[doc(hidden)]
pub type Never = <fn() -> ! as sealed::Extract>::T;
}
pub const TAG_TYPE_NAME: Symbol = Symbol::new("Type Name");
pub const TAG_TYPE_ID: Symbol = Symbol::new("Type ID");
pub const TAG_TYPE_SIZE: Symbol = Symbol::new("Type Size");
pub const TAG_FIELD_NAMES: Symbol = Symbol::new("Field Names");
#[derive(Debug)]
pub enum StructWalkError {
Tag(Symbol, &'static str),
}
#[macro_export]
macro_rules! Walk {
{
$(#[$($attr:tt)*])*
$vis:vis struct $name:ident {$(
$field:ident: $type:ty
),* $(,)?}
} => {
const _: () = {
impl<'ctx> $crate::Walk<'ctx> for &'ctx $name {
type Walker<E: $crate::effect::Effect<'ctx>> = Walker<'ctx, E>;
fn into_walker<E: $crate::effect::Effect<'ctx>>(self) -> Self::Walker<E> {
Walker {
value: self,
_marker: ::core::marker::PhantomData,
}
}
}
impl<'ctx> $crate::WalkerTypes<'ctx> for &'ctx $name {
type Error = $crate::StructWalkError;
type Output = ();
}
pub struct Walker<'ctx, E> {
value: &'ctx $name,
_marker: ::core::marker::PhantomData<fn() -> E>,
}
impl<'ctx, E> $crate::WalkerTypes<'ctx> for Walker<'ctx, E> {
type Error = $crate::StructWalkError;
type Output = ();
}
impl<'ctx, E: $crate::effect::Effect<'ctx>> $crate::Walker<'ctx> for Walker<'ctx, E> {
type Effect = E;
fn walk<'a>(
mut self,
visitor: $crate::protocol::Visitor<'a, 'ctx>,
) -> $crate::effect::Future<'a, 'ctx, Result<Self::Output, Self::Error>, Self::Effect>
where
Self: 'a
{
E::wrap(async move {
// We should check if the visitor wants something specific.
if let Some(object) = visitor.upcast_mut::<dyn $crate::protocol::visitor::request_hint::RequestHint<'ctx, Effect = E> + '_>() {
// Allow the visitor to give a hint if it wants.
match object.request_hint(&mut self).await {
::core::ops::ControlFlow::Continue(()) => {
// The visitor wants the walker to continue to it's normal
// walking.
},
::core::ops::ControlFlow::Break(()) => {
// The visitor is done (either because of an error or because
// it already used a hint).
return Ok(());
},
}
}
// Follow the standard set of protocols for a struct.
// - Tagged: struct name
// - Tagged: struct type
// - Tagged: struct field names
// - Sequence: the fields
if let Ok((result, flow)) =
$crate::try_visit_tag::<{ $crate::TAG_TYPE_NAME.to_int() }, E, _>(
visitor,
$crate::walkers::core::tag::NameWalker::new(stringify!($name))
).await
{
match result {
Ok(()) => {},
Err($crate::DynWalkerError::Walker($crate::walkers::core::tag::MissingProtocol(msg))) => {
return Err($crate::StructWalkError::Tag($crate::TAG_TYPE_NAME, msg))
}
Err($crate::DynWalkerError::NeverWalked(_)) => {
return Err($crate::StructWalkError::Tag($crate::TAG_TYPE_NAME, "visitor didn't walk walker"))
},
Err($crate::DynWalkerError::WalkNeverFinished) => {
return Err($crate::StructWalkError::Tag($crate::TAG_TYPE_NAME, "walk didn't finish"))
},
}
if let ::core::ops::ControlFlow::Break(()) = flow {
return Ok(());
}
}
if let Ok((result, flow)) =
$crate::try_visit_tag::<{ $crate::TAG_TYPE_ID.to_int() }, E, _>(
visitor,
$crate::walkers::core::tag::TypeIdWalker::new::<$name>()
).await
{
match result {
Ok(()) => {},
Err($crate::DynWalkerError::Walker($crate::walkers::core::tag::MissingProtocol(msg))) => {
return Err($crate::StructWalkError::Tag($crate::TAG_TYPE_ID, msg))
}
Err($crate::DynWalkerError::NeverWalked(_)) => {
return Err($crate::StructWalkError::Tag($crate::TAG_TYPE_ID, "visitor didn't walk walker"))
},
Err($crate::DynWalkerError::WalkNeverFinished) => {
return Err($crate::StructWalkError::Tag($crate::TAG_TYPE_ID, "walk didn't finish"))
},
}
if let ::core::ops::ControlFlow::Break(()) = flow {
return Ok(());
}
}
todo!()
})
}
}
$crate::any::any_trait! {
impl['a, 'ctx, E] Walker<'ctx, E> = [
// dyn Hint<'a, 'ctx, OwnedStatic<bool>, E> + 'a,
] where E: $crate::effect::Effect<'ctx>
}
};
};
}
pub fn try_visit_tag<
'a,
'ctx,
const SYMBOL: u64,
E: Effect<'ctx>,
W: Walker<'ctx, Effect = E> + 'a,
>(
visitor: Visitor<'a, 'ctx>,
walker: W,
) -> Future<
'a,
'ctx,
Result<
(
Result<W::Output, DynWalkerError<'ctx, W>>,
ControlFlow<(), protocol::visitor::tag::Status>,
),
W,
>,
E,
> {
E::wrap(async {
if let Some(object) = visitor.upcast_mut::<
dyn protocol::visitor::tag::Tag<
'ctx,
protocol::visitor::tag::Const<SYMBOL>,
Effect = E
> + '_
>() {
let mut name_walker = DynWalkerAdapter::new(walker);
let flow = object.visit(protocol::visitor::tag::Const, &mut name_walker).await;
Ok((name_walker.finish(), match flow {
ControlFlow::Continue(()) => ControlFlow::Continue(protocol::visitor::tag::Status::Walked),
ControlFlow::Break(()) => ControlFlow::Break(()),
}))
} else if let Some(object) = visitor.upcast_mut::<
dyn protocol::visitor::tag::Tag<
'ctx,
protocol::visitor::tag::Dyn,
Effect = E
> + '_
>() {
let mut name_walker = DynWalkerAdapter::new(walker);
let flow = object.visit(protocol::visitor::tag::Dyn(Symbol::from_int(SYMBOL)), &mut name_walker).await;
Ok((name_walker.finish(), flow))
} else {
Err(walker)
}
})
}
#[cfg(test)]
mod test {
use crate::effect::{BlockOn, Blocking, Spin};
use super::*;
use macro_rules_attribute::derive;
#[derive(Walk!)]
struct Demo {
a: bool,
b: bool,
}
#[test]
fn demo() {
let value = Demo { a: true, b: false };
let walker = value.into_walker::<Blocking>();
let mut visitor = builders::debug::Walker::<Blocking>::new();
dbg!(Spin::block_on(walker.walk(&mut visitor)));
todo!();
}
}