Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs268
1 files changed, 210 insertions, 58 deletions
diff --git a/src/lib.rs b/src/lib.rs
index fd458fa..753ac7c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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!();
+ }
+}