Diffstat (limited to 'src/lib.rs')
| -rw-r--r-- | src/lib.rs | 268 |
1 files changed, 210 insertions, 58 deletions
@@ -24,12 +24,42 @@ mod transform; // 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! Build { +macro_rules! Walk { { $(#[$($attr:tt)*])* $vis:vis struct $name:ident {$( @@ -37,79 +67,201 @@ macro_rules! Build { ),* $(,)?} } => { const _: () = { - impl<'ctx> $crate::Build<'ctx> for $name { - type Builder = StructBuilder; - } - - #[derive(Default)] - $vis struct StructBuilder {$( - $field: Option<$type> - ),*} + impl<'ctx> $crate::Walk<'ctx> for &'ctx $name { + type Walker<E: $crate::effect::Effect<'ctx>> = Walker<'ctx, E>; - impl<'ctx> $crate::Builder<'ctx> for StructBuilder { - type Error = (); - - type Value = $name; - - fn as_visitor(&mut self) -> &mut dyn $crate::protocol::Implementer<'ctx> { - self - } - - fn build(self) -> Result<Self::Value, Self::Error> { - if let StructBuilder {$($field: Some($field)),*} = self { - Ok($name {$($field),*}) - } else { - Err(()) + fn into_walker<E: $crate::effect::Effect<'ctx>>(self) -> Self::Walker<E> { + Walker { + value: self, + _marker: ::core::marker::PhantomData, } } } - $crate::protocol::implementer! { - impl['ctx] StructBuilder = [ - - ]; + impl<'ctx> $crate::WalkerTypes<'ctx> for &'ctx $name { + type Error = $crate::StructWalkError; + type Output = (); } - impl<'ctx> $crate::Walk<'ctx> for $name { - type Walker = StructWalker; + pub struct Walker<'ctx, E> { + value: &'ctx $name, + _marker: ::core::marker::PhantomData<fn() -> E>, } - $vis struct StructWalker { - value: Option<$name>, - hint_given: bool, + impl<'ctx, E> $crate::WalkerTypes<'ctx> for Walker<'ctx, E> { + type Error = $crate::StructWalkError; + type Output = (); } - impl From<$name> for StructWalker { - fn from(value: $name) -> Self { - Self { - value: Some(value), - hint_given: false - } - } - } + impl<'ctx, E: $crate::effect::Effect<'ctx>> $crate::Walker<'ctx> for Walker<'ctx, E> { + type Effect = E; - impl<'ctx> $crate::Walker<'ctx> for StructWalker { - type Error = (); + 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(()); + }, + } + } - type Output = (); + // Follow the standard set of protocols for a struct. + // - Tagged: struct name + // - Tagged: struct type + // - Tagged: struct field names + // - Sequence: the fields - fn walk( - &mut self, - visitor: &mut dyn $crate::protocol::Implementer<'ctx> - ) -> Result<Self::Output, Self::Error> { - use $crate::protocol::ImplementerExt; - // Want kinds for tags. - if let Some(interface) = visitor.interface_for:: - <$crate::builtins::visitor::request_hint>() { - interface.as_object().visit(&mut self); - } - $( - <$type as $crate::Walk>::Walker::from(self.0.$field) - .walk(visitor); - )* - todo!() + 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!(); + } +} |