//! # 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 macros::TagError;
use protocol::Visitor;
use symbol::Symbol;
pub use transform::*;
pub use walk::*;
// #[doc(hidden)]
pub mod macros;
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");
pub const TAG_SEQ_INDEX: Symbol = Symbol::new("Seq Index");
pub const TAG_SEQ_LEN: Symbol = Symbol::new("Seq Length");
pub const TAG_STRUCT: Symbol = Symbol::new("Struct");
pub const TAG_ENUM: Symbol = Symbol::new("Enum");
#[derive(Debug)]
pub enum StructWalkError {
Tag(TagError),
}
#[must_use]
pub enum Flow<Error> {
/// Processing should continue as normal.
Continue,
/// Processing should stop, but there is no direct error to report.
Break,
/// Processing should stop with this error.
Err(Error),
}
#[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 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 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
match $crate::macros::visit_tag::<{ $crate::TAG_STRUCT.to_int() }, E, _>(
visitor,
$crate::walkers::core::tag::NoopWalker::new()
).await {
$crate::Flow::Continue => {},
$crate::Flow::Break => return Ok(()),
$crate::Flow::Err(_) => unreachable!(),
}
match $crate::macros::visit_tag::<{ $crate::TAG_TYPE_NAME.to_int() }, E, _>(
visitor,
$crate::walkers::core::tag::ValueWalker::new(stringify!($name))
).await {
$crate::Flow::Continue => {},
$crate::Flow::Break => return Ok(()),
$crate::Flow::Err(err) => return Err(StructWalkError::Tag(err)),
}
match $crate::macros::visit_tag::<{ $crate::TAG_TYPE_ID.to_int() }, E, _>(
visitor,
$crate::walkers::core::tag::ValueWalker::new(::core::any::TypeId::of::<$name>())
).await {
$crate::Flow::Continue => {},
$crate::Flow::Break => return Ok(()),
$crate::Flow::Err(err) => return Err(StructWalkError::Tag(err)),
}
match $crate::macros::visit_tag::<{ $crate::TAG_FIELD_NAMES.to_int() }, E, _>(
visitor,
$crate::walkers::core::tag::NamesWalker::new(&[$(
stringify!($field)
),*])
).await {
$crate::Flow::Continue => {},
$crate::Flow::Break => return Ok(()),
$crate::Flow::Err(err) => return Err(StructWalkError::Tag(err)),
}
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>
}
};
};
}
#[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::Visitor::<Blocking>::new();
dbg!(Spin::block_on(walker.walk(&mut visitor)));
todo!();
}
}