Updated to use the new effects
| -rw-r--r-- | Cargo.lock | 105 | ||||
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | src/any.rs | 4 | ||||
| -rw-r--r-- | src/build.rs | 120 | ||||
| -rw-r--r-- | src/build/builders.rs | 4 | ||||
| -rw-r--r-- | src/build/builders/core.rs | 3 | ||||
| -rw-r--r-- | src/build/builders/core/bool.rs | 66 | ||||
| -rw-r--r-- | src/build/builders/core/option.rs | 264 | ||||
| -rw-r--r-- | src/effect.rs | 199 | ||||
| -rw-r--r-- | src/hkt.rs | 134 | ||||
| -rw-r--r-- | src/lib.rs | 3 | ||||
| -rw-r--r-- | src/protocol.rs | 22 | ||||
| -rw-r--r-- | src/protocol/visitor.rs | 13 | ||||
| -rw-r--r-- | src/protocol/visitor/request_hint.rs | 10 | ||||
| -rw-r--r-- | src/protocol/visitor/sequence.rs | 33 | ||||
| -rw-r--r-- | src/protocol/visitor/tagged.rs | 39 | ||||
| -rw-r--r-- | src/protocol/visitor/value.rs | 161 | ||||
| -rw-r--r-- | src/protocol/walker.rs | 4 | ||||
| -rw-r--r-- | src/protocol/walker/hint.rs | 75 | ||||
| -rw-r--r-- | src/transform.rs | 44 | ||||
| -rw-r--r-- | src/walk.rs | 36 | ||||
| -rw-r--r-- | src/walk/walkers/core.rs | 2 | ||||
| -rw-r--r-- | src/walk/walkers/core/bool.rs | 44 | ||||
| -rw-r--r-- | tests/hook.rs | 114 |
24 files changed, 708 insertions, 792 deletions
@@ -109,95 +109,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] -name = "futures" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" - -[[package]] -name = "futures-executor" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" - -[[package]] -name = "futures-macro" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "futures-sink" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" - -[[package]] -name = "futures-task" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" - -[[package]] -name = "futures-util" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] name = "getrandom" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -367,12 +278,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] name = "ppv-lite86" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -560,15 +465,6 @@ dependencies = [ ] [[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] name = "smallvec" version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -642,7 +538,6 @@ dependencies = [ name = "treaty" version = "0.1.0" dependencies = [ - "futures", "macro_rules_attribute", "proptest", "serde", @@ -4,7 +4,6 @@ version = "0.1.0" edition = "2021" [dependencies] -futures = "0.3.30" serde = { version = "1.0", default-features = false, optional = true } [features] @@ -350,7 +350,7 @@ pub trait AnyTrait<'lt> { 'lt: 'a; } -impl<'lt> dyn AnyTrait<'lt> + '_ { +impl<'lt> dyn AnyTrait<'lt> + Send + '_ { /// Upcast a borrow to the given trait object type. /// /// This should be used instead of [`upcast_to_id`][AnyTrait::upcast_to_id] @@ -678,7 +678,7 @@ mod test { } let x = X(42); - let y: &dyn AnyTrait<'_> = &x; + let y: &(dyn AnyTrait<'_> + Send) = &x; let z: &dyn Z = y.upcast().unwrap(); assert_eq!(z.num(), 42); } diff --git a/src/build.rs b/src/build.rs index 7ac87fd..3723392 100644 --- a/src/build.rs +++ b/src/build.rs @@ -1,15 +1,24 @@ pub mod builders; use crate::{ - effect::{AsObj as _, Effect, EffectAnyTrait, SyncEffect, Yield}, + effect::{Effect, Future}, protocol::Visitor, - Walker, }; /// A buildable type. -pub trait Build<'ctx, E: EffectAnyTrait<'ctx>>: Sized { +pub trait Build<'ctx>: BuilderTypes<'ctx, Value = Self> + Send { /// The builder that can be used to build a value of `Self`. - type Builder: Builder<'ctx, E, Value = Self>; + type Builder<E: Effect<'ctx>>: Builder<'ctx, Seed = Self::Seed, Error = Self::Error, Value = Self, Effect = E>; +} + +pub trait BuilderTypes<'ctx> { + type Seed: Send; + + /// Error that can happen during filling the builder with data. + type Error: Send; + + /// Type to be built. + type Value: Send; } /// Builder for a type. @@ -25,112 +34,23 @@ pub trait Build<'ctx, E: EffectAnyTrait<'ctx>>: Sized { /// the builder with data from it's walk. /// - Call [`Self::build()`] to finish building the value and get any errors /// that happened during filling it with data. -pub trait Builder<'ctx, E: EffectAnyTrait<'ctx>>: AsVisitor<'ctx, E> { - type Effect: Effect<'ctx, Result<Self::Value, Self::Error>>; +pub trait Builder<'ctx>: BuilderTypes<'ctx> + Sized + Send { + type Effect: Effect<'ctx>; - type Seed; - - /// Error that can happen during filling the builder with data. - type Error; - - /// Type to be built. - type Value; - - fn from_seed(seed: Self::Seed) -> Self; + fn from_seed<'a>(seed: Self::Seed) -> Future<'a, 'ctx, Self, Self::Effect> + where + Self: 'a; /// Finish the value. /// /// If an error happened with the builder during the walk /// it will be reported here. - fn build<'a>(self) -> Yield<'a, 'ctx, Result<Self::Value, Self::Error>, Self::Effect> + fn build<'a>(self) -> Future<'a, 'ctx, Result<Self::Value, Self::Error>, Self::Effect> where Self: 'a; -} -pub trait AsVisitor<'ctx, E: EffectAnyTrait<'ctx>> { /// Get the builder as a visitor that a walker can use. /// /// This is expected to just be `self`. - fn as_visitor(&mut self) -> Visitor<'_, 'ctx, E>; + fn as_visitor(&mut self) -> Visitor<'_, 'ctx>; } - -pub trait DefaultBuilder<'ctx, E: EffectAnyTrait<'ctx>>: Builder<'ctx, E> { - fn default() -> Self; -} - -impl<'ctx, B: Builder<'ctx, E>, E: EffectAnyTrait<'ctx>> DefaultBuilder<'ctx, E> for B -where - B::Seed: Default, -{ - fn default() -> Self { - Self::from_seed(Default::default()) - } -} - -#[derive(Debug)] -pub enum BuildError<B, W> { - Builder(B), - Walker(W), -} - -#[inline] -pub fn build<'ctx, T: Build<'ctx, SyncEffect>, W: Walker<'ctx, Effect = SyncEffect>>( - walker: W, -) -> Result< - T, - BuildError< - <<T as Build<'ctx, SyncEffect>>::Builder as Builder<'ctx, SyncEffect>>::Error, - W::Error, - >, -> -where - <T as Build<'ctx, SyncEffect>>::Builder: Builder<'ctx, SyncEffect, Effect = SyncEffect>, - <<T as Build<'ctx, SyncEffect>>::Builder as Builder<'ctx, SyncEffect>>::Seed: Default, -{ - let mut builder = T::Builder::from_seed(Default::default()); - - if let Err(err) = walker.walk(builder.as_visitor().as_obj_mut()) { - return Err(BuildError::Walker(err)); - } - - builder.build().map_err(BuildError::Builder) -} - -pub fn build_with< - 'ctx, - B: Builder<'ctx, SyncEffect, Effect = SyncEffect>, - W: Walker<'ctx, Effect = SyncEffect>, ->( - walker: W, -) -> Result<B::Value, BuildError<B::Error, W::Error>> -where - <B as Builder<'ctx, SyncEffect>>::Seed: Default, -{ - let mut builder = B::from_seed(Default::default()); - - if let Err(err) = walker.walk(builder.as_visitor().as_obj_mut()) { - return Err(BuildError::Walker(err)); - } - - builder.build().map_err(BuildError::Builder) -} - -// #[cfg(feature = "alloc")] -// use crate::protocol::AsyncEffect; -// -// #[cfg(feature = "alloc")] -// pub async fn async_build_with< -// 'ctx, -// B: DefaultBuilder<'ctx, AsyncEffect>, -// W: for<'a> Walker<'a, 'ctx, Effect = AsyncEffect>, -// >( -// walker: W, -// ) -> Result<B::Value, BuildError<B::Error, W::Error>> { -// let mut builder = B::default(); -// -// if let core::ops::ControlFlow::Break(err) = walker.walk(builder.as_visitor()).await { -// return Err(BuildError::Walker(err)); -// } -// -// builder.build().map_err(BuildError::Builder) -// } diff --git a/src/build/builders.rs b/src/build/builders.rs index f5eac87..b5d0e43 100644 --- a/src/build/builders.rs +++ b/src/build/builders.rs @@ -1,4 +1,4 @@ pub mod core; -#[cfg(feature = "serde")] -pub mod serde; +// #[cfg(feature = "serde")] +// pub mod serde; diff --git a/src/build/builders/core.rs b/src/build/builders/core.rs index 8b4fb45..e1b3383 100644 --- a/src/build/builders/core.rs +++ b/src/build/builders/core.rs @@ -1,4 +1,5 @@ -pub mod array; +// pub mod array; pub mod bool; pub mod option; + // pub mod variant; diff --git a/src/build/builders/core/bool.rs b/src/build/builders/core/bool.rs index 3becdae..64f6876 100644 --- a/src/build/builders/core/bool.rs +++ b/src/build/builders/core/bool.rs @@ -3,16 +3,12 @@ use core::{marker::PhantomData, ops::ControlFlow}; use crate::{ any::static_wrapper::OwnedStatic, any_trait, - effect::{AsObj, AsyncEffect, Effect, SyncEffect, Yield}, - protocol::visitor::Value, - AsVisitor, + effect::{Effect, Future}, + protocol::{visitor::value::Value, Visitor}, }; -impl<'ctx, E: Effect<'ctx, ControlFlow<(), ()>>> crate::Build<'ctx, E> for bool -where - Builder<E>: AsVisitor<'ctx, E>, -{ - type Builder = Builder<E>; +impl<'ctx> crate::Build<'ctx> for bool { + type Builder<E: Effect<'ctx>> = Builder<E>; } #[derive(Debug)] @@ -22,56 +18,58 @@ pub enum Error { pub struct Builder<E>(Option<bool>, PhantomData<fn() -> E>); -impl<'ctx, E: Effect<'ctx, ControlFlow<(), ()>>> crate::Builder<'ctx, E> for Builder<E> -where - Self: AsVisitor<'ctx, E>, -{ +impl<'ctx> crate::BuilderTypes<'ctx> for bool { + type Seed = (); + type Error = Error; type Value = bool; +} + +impl<'ctx, E: Effect<'ctx>> crate::BuilderTypes<'ctx> for Builder<E> { + type Error = Error; + + type Value = bool; + + type Seed = (); +} + +impl<'ctx, E: Effect<'ctx>> crate::Builder<'ctx> for Builder<E> { + type Effect = E; #[inline] - fn build<'a>(self) -> Result<Self::Value, Self::Error> + fn build<'a>(self) -> Future<'a, 'ctx, Result<Self::Value, Self::Error>, E> where Self: 'a, { - self.0.ok_or(Error::Incomplete) + E::wrap(core::future::ready(self.0.ok_or(Error::Incomplete))) } - type Seed = (); - - fn from_seed(_seed: Self::Seed) -> Self { - Self(None, PhantomData) - } - - type Effect = SyncEffect; -} - -impl<'ctx> AsVisitor<'ctx, SyncEffect> for Builder<SyncEffect> { - fn as_visitor(&mut self) -> crate::protocol::Visitor<'_, 'ctx, SyncEffect> { - self + fn from_seed<'a>(_seed: Self::Seed) -> Future<'a, 'ctx, Self, E> + where + Self: 'a, + { + E::wrap(core::future::ready(Self(None, PhantomData))) } -} -impl<'ctx> AsVisitor<'ctx, AsyncEffect> for Builder<AsyncEffect> { - fn as_visitor(&mut self) -> crate::protocol::Visitor<'_, 'ctx, AsyncEffect> { + fn as_visitor(&mut self) -> Visitor<'_, 'ctx> { self } } any_trait! { impl['a, 'ctx, E] Builder<E> = [ - dyn Value<'a, 'ctx, OwnedStatic<bool>, SyncEffect> + 'a, - ] + dyn Value<'a, 'ctx, OwnedStatic<bool>, E> + 'a, + ] where E: Effect<'ctx> } -impl<'a, 'ctx: 'a, E> Value<'a, 'ctx, OwnedStatic<bool>, SyncEffect> for Builder<E> { +impl<'a, 'ctx: 'a, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<bool>, E> for Builder<E> { #[inline] fn visit( &'a mut self, OwnedStatic(value): OwnedStatic<bool>, - ) -> Yield<'a, 'ctx, ControlFlow<(), ()>, SyncEffect> { + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { self.0 = Some(value); - ControlFlow::Continue(()) + E::wrap(core::future::ready(ControlFlow::Continue(()))) } } diff --git a/src/build/builders/core/option.rs b/src/build/builders/core/option.rs index 00c79c9..cb2e624 100644 --- a/src/build/builders/core/option.rs +++ b/src/build/builders/core/option.rs @@ -3,24 +3,37 @@ use core::{marker::PhantomData, ops::ControlFlow}; use crate::{ any::static_wrapper::{BorrowedStatic, BorrowedStaticValue, OwnedStatic, TempBorrowedStatic}, any_trait, - effect::{AsyncEffect, AsyncSendEffect, EffectAnyTrait, SyncEffect, Yield}, - protocol::visitor::{Tagged, TaggedScope, Value}, - AsVisitor, + effect::{Effect, Future}, + protocol::visitor::{ + tagged::{Tagged, TaggedScope}, + value::Value, + }, }; -impl<'ctx, T, E> crate::Build<'ctx, E> for Option<T> +impl<'ctx, T> crate::Build<'ctx> for Option<T> where - E: EffectAnyTrait<'ctx>, - Builder<'ctx, T::Builder, E>: AsVisitor<'ctx, E>, - T: crate::Build<'ctx, E>, + T: crate::Build<'ctx>, + <T as crate::BuilderTypes<'ctx>>::Seed: Default, { - type Builder = Builder<'ctx, T::Builder, E>; + type Builder<E: Effect<'ctx>> = Builder<'ctx, T::Builder<E>, E>; } -pub struct Builder<'ctx, B: crate::Builder<'ctx, E>, E: EffectAnyTrait<'ctx>> { +impl<'ctx, T> crate::BuilderTypes<'ctx> for Option<T> +where + T: crate::Build<'ctx>, + <T as crate::BuilderTypes<'ctx>>::Seed: Default, +{ + type Error = Error<'ctx, T::Error>; + + type Value = Option<T::Value>; + + type Seed = IgnoreMissing; +} + +pub struct Builder<'ctx, B: crate::Builder<'ctx>, E> { value: Option<Result<Option<B::Value>, Error<'ctx, B::Error>>>, ignore_missing: bool, - _marker: PhantomData<fn() -> (&'ctx (), E)>, + _marker: PhantomData<fn() -> E>, } #[derive(Default)] @@ -40,84 +53,58 @@ pub enum Error<'ctx, T> { NoVariantGiven, } -impl<'ctx, B, E> crate::Builder<'ctx, E> for Builder<'ctx, B, E> +impl<'ctx, B, E: Effect<'ctx>> crate::BuilderTypes<'ctx> for Builder<'ctx, B, E> where - E: EffectAnyTrait<'ctx>, - Self: AsVisitor<'ctx, E>, - B: crate::Builder<'ctx, E>, + B: crate::Builder<'ctx, Effect = E>, + <B as crate::BuilderTypes<'ctx>>::Seed: Default, { type Error = Error<'ctx, B::Error>; type Value = Option<B::Value>; + type Seed = IgnoreMissing; +} + +impl<'ctx, B, E: Effect<'ctx>> crate::Builder<'ctx> for Builder<'ctx, B, E> +where + B: crate::Builder<'ctx, Effect = E>, + <B as crate::BuilderTypes<'ctx>>::Seed: Default, +{ + type Effect = E; + #[inline] - fn build<'a>(self) -> Result<Self::Value, Self::Error> + fn build<'a>(self) -> Future<'a, 'ctx, Result<Self::Value, Self::Error>, E> where Self: 'a, { - match self.value { + E::wrap(core::future::ready(match self.value { Some(value) => value, None if self.ignore_missing => Ok(None), None => Err(Error::Missing), - } + })) } - type Seed = IgnoreMissing; - - fn from_seed(seed: Self::Seed) -> Self { - Self { + fn from_seed<'a>(seed: Self::Seed) -> Future<'a, 'ctx, Self, E> { + E::wrap(core::future::ready(Self { value: None, ignore_missing: match seed { IgnoreMissing::Yes => true, IgnoreMissing::No => false, }, _marker: PhantomData, - } - } - - type Effect = SyncEffect; -} - -impl<'ctx, B: crate::Builder<'ctx, SyncEffect>> AsVisitor<'ctx, SyncEffect> - for Builder<'ctx, B, SyncEffect> -{ - fn as_visitor(&mut self) -> crate::protocol::Visitor<'_, 'ctx, SyncEffect> { - self + })) } -} -impl<'ctx, B: crate::Builder<'ctx, AsyncEffect>> AsVisitor<'ctx, AsyncEffect> - for Builder<'ctx, B, AsyncEffect> -{ - fn as_visitor(&mut self) -> crate::protocol::Visitor<'_, 'ctx, AsyncEffect> { + fn as_visitor(&mut self) -> crate::protocol::Visitor<'_, 'ctx> { self } } -impl<'ctx, B> AsVisitor<'ctx, AsyncSendEffect> for Builder<'ctx, B, AsyncSendEffect> -where - B: crate::Builder<'ctx, AsyncSendEffect>, - <B as crate::Builder<'ctx, AsyncSendEffect>>::Value: Send, - <B as crate::Builder<'ctx, AsyncSendEffect>>::Error: Send, -{ - fn as_visitor(&mut self) -> crate::protocol::Visitor<'_, 'ctx, AsyncSendEffect> { - self - } -} - -any_trait! { - impl['a, 'ctx, B] Builder<'ctx, B, SyncEffect> = [ - ] where B: crate::Builder<'ctx, SyncEffect> -} - -any_trait! { - impl['a, 'ctx, B] Builder<'ctx, B, AsyncEffect> = [ - ] where B: crate::Builder<'ctx, AsyncEffect> -} - any_trait! { - impl['a, 'ctx, B] Builder<'ctx, B, AsyncSendEffect> = [ - ] where B: crate::Builder<'ctx, AsyncSendEffect> + impl['a, 'ctx, B, E] Builder<'ctx, B, E> = [ + dyn Tagged<'ctx, E> + 'a, + ] where B: crate::Builder<'ctx, Effect = E>, E: Effect<'ctx>, + <B as crate::BuilderTypes<'ctx>>::Seed: Default, } pub mod symbol { @@ -128,62 +115,65 @@ pub mod symbol { pub const VARIANT: Symbol = Symbol::new("Variant"); } -impl<'ctx, B> Tagged<'ctx, SyncEffect> for Builder<'ctx, B, SyncEffect> +impl<'ctx, B, E: Effect<'ctx>> Tagged<'ctx, E> for Builder<'ctx, B, E> where - B: crate::DefaultBuilder<'ctx, SyncEffect, Effect = SyncEffect>, + B: crate::Builder<'ctx, Effect = E>, + <B as crate::BuilderTypes<'ctx>>::Seed: Default, { fn visit<'a>( &'a mut self, - scope: &'a mut dyn TaggedScope<'ctx, SyncEffect>, - ) -> Yield<'a, 'ctx, ControlFlow<(), ()>, SyncEffect> - where - 'ctx: 'a, - { - match scope.kind() { - symbol::KEY | symbol::VARIANT => { - // This tag is the variant name/number. - let mut variant = VariantVisitor::<'ctx, B::Error> { value: None }; - scope.tag(&mut variant)?; - let variant = match variant.value { - Some(Ok(value)) => value, - Some(Err(error)) => { - self.value = Some(Err(error)); - return ControlFlow::Break(()); - } - None => { - self.value = Some(Err(Error::NoVariantGiven)); - return ControlFlow::Break(()); - } - }; + scope: &'a mut (dyn TaggedScope<'ctx, E> + Send), + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { + E::wrap(async { + match scope.kind().await { + symbol::KEY | symbol::VARIANT => { + // This tag is the variant name/number. + let mut variant = VariantVisitor::<'ctx, B::Error, E> { + value: None, + _marker: PhantomData, + }; + scope.tag(&mut variant).await?; + let variant = match variant.value { + Some(Ok(value)) => value, + Some(Err(error)) => { + self.value = Some(Err(error)); + return ControlFlow::Break(()); + } + None => { + self.value = Some(Err(Error::NoVariantGiven)); + return ControlFlow::Break(()); + } + }; - match variant { - Variant::None => { - // Nothing more needs to be done. - self.value = Some(Ok(None)); - ControlFlow::Continue(()) - } - Variant::Some => { - // Now build a T. - let mut builder = B::default(); - scope.value(builder.as_visitor())?; - match builder.build() { - Ok(value) => { - self.value = Some(Ok(Some(value))); - ControlFlow::Continue(()) - } - Err(error) => { - self.value = Some(Err(Error::VariantSome(error))); - ControlFlow::Break(()) + match variant { + Variant::None => { + // Nothing more needs to be done. + self.value = Some(Ok(None)); + ControlFlow::Continue(()) + } + Variant::Some => { + // Now build a T. + let mut builder = B::from_seed(Default::default()).await; + scope.value(builder.as_visitor()).await?; + match builder.build().await { + Ok(value) => { + self.value = Some(Ok(Some(value))); + ControlFlow::Continue(()) + } + Err(error) => { + self.value = Some(Err(Error::VariantSome(error))); + ControlFlow::Break(()) + } } } } } + _ => { + // Ignore any other tags and just use the value. + scope.value(self).await + } } - _ => { - // Ignore any other tags and just use the value. - scope.value(self) - } - } + }) } } @@ -192,27 +182,29 @@ enum Variant { Some, } -pub struct VariantVisitor<'ctx, T> { +pub struct VariantVisitor<'ctx, T, E> { value: Option<Result<Variant, Error<'ctx, T>>>, + _marker: PhantomData<fn() -> E>, } any_trait! { - impl['a, 'ctx, T] VariantVisitor<'ctx, T> = [ - dyn Value<'a, 'ctx, TempBorrowedStatic<'a, str>, SyncEffect> + 'a, - dyn Value<'a, 'ctx, BorrowedStatic<'ctx, str>, SyncEffect> + 'a, - dyn Value<'a, 'ctx, OwnedStatic<&'static str>, SyncEffect> + 'a, - dyn Value<'a, 'ctx, OwnedStatic<u8>, SyncEffect> + 'a, - dyn Value<'a, 'ctx, OwnedStatic<u16>, SyncEffect> + 'a, - ] + impl['a, 'ctx, T, E] VariantVisitor<'ctx, T, E> = [ + dyn Value<'a, 'ctx, TempBorrowedStatic<'a, str>, E> + 'a, + dyn Value<'a, 'ctx, BorrowedStatic<'ctx, str>, E> + 'a, + dyn Value<'a, 'ctx, OwnedStatic<&'static str>, E> + 'a, + dyn Value<'a, 'ctx, OwnedStatic<u8>, E> + 'a, + dyn Value<'a, 'ctx, OwnedStatic<u16>, E> + 'a, + ] where E: Effect<'ctx> } -impl<'a, 'ctx: 'a, T> Value<'a, 'ctx, TempBorrowedStatic<'a, str>, SyncEffect> - for VariantVisitor<'ctx, T> +impl<'a, 'ctx: 'a, T, E: Effect<'ctx>> Value<'a, 'ctx, TempBorrowedStatic<'a, str>, E> + for VariantVisitor<'ctx, T, E> { fn visit( &'a mut self, TempBorrowedStatic(value): TempBorrowedStatic<'a, str>, - ) -> Yield<'a, 'ctx, ControlFlow<(), ()>, SyncEffect> { + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { + E::wrap(core::future::ready( match value { "None" => { self.value = Some(Ok(Variant::None)); @@ -226,17 +218,18 @@ impl<'a, 'ctx: 'a, T> Value<'a, 'ctx, TempBorrowedStatic<'a, str>, SyncEffect> self.value = Some(Err(Error::UnknownVariantName(None))); ControlFlow::Break(()) } - } + })) } } -impl<'a, 'ctx: 'a, T> Value<'a, 'ctx, BorrowedStatic<'ctx, str>, SyncEffect> - for VariantVisitor<'ctx, T> +impl<'a, 'ctx: 'a, T, E: Effect<'ctx>> Value<'a, 'ctx, BorrowedStatic<'ctx, str>, E> + for VariantVisitor<'ctx, T, E> { fn visit( &'a mut self, BorrowedStatic(value): BorrowedStatic<'ctx, str>, - ) -> Yield<'a, 'ctx, ControlFlow<(), ()>, SyncEffect> { + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { + E::wrap(core::future::ready( match value { "None" => { self.value = Some(Ok(Variant::None)); @@ -252,17 +245,18 @@ impl<'a, 'ctx: 'a, T> Value<'a, 'ctx, BorrowedStatic<'ctx, str>, SyncEffect> )))); ControlFlow::Break(()) } - } + })) } } -impl<'a, 'ctx: 'a, T> Value<'a, 'ctx, OwnedStatic<&'static str>, SyncEffect> - for VariantVisitor<'ctx, T> +impl<'a, 'ctx: 'a, T, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<&'static str>, E> + for VariantVisitor<'ctx, T, E> { fn visit( &'a mut self, OwnedStatic(value): OwnedStatic<&'static str>, - ) -> Yield<'a, 'ctx, ControlFlow<(), ()>, SyncEffect> { + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { + E::wrap(core::future::ready( match value { "None" => { self.value = Some(Ok(Variant::None)); @@ -278,15 +272,18 @@ impl<'a, 'ctx: 'a, T> Value<'a, 'ctx, OwnedStatic<&'static str>, SyncEffect> )))); ControlFlow::Break(()) } - } + })) } } -impl<'a, 'ctx: 'a, T> Value<'a, 'ctx, OwnedStatic<u8>, SyncEffect> for VariantVisitor<'ctx, T> { +impl<'a, 'ctx: 'a, T, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<u8>, E> + for VariantVisitor<'ctx, T, E> +{ fn visit( &'a mut self, OwnedStatic(value): OwnedStatic<u8>, - ) -> Yield<'a, 'ctx, ControlFlow<(), ()>, SyncEffect> { + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { + E::wrap(core::future::ready( match value { 0 => { self.value = Some(Ok(Variant::None)); @@ -300,15 +297,18 @@ impl<'a, 'ctx: 'a, T> Value<'a, 'ctx, OwnedStatic<u8>, SyncEffect> for VariantVi self.value = Some(Err(Error::UnknownVariantNum(Some(value)))); ControlFlow::Break(()) } - } + })) } } -impl<'a, 'ctx: 'a, T> Value<'a, 'ctx, OwnedStatic<u16>, SyncEffect> for VariantVisitor<'ctx, T> { +impl<'a, 'ctx: 'a, T, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<u16>, E> + for VariantVisitor<'ctx, T, E> +{ fn visit( &'a mut self, OwnedStatic(value): OwnedStatic<u16>, - ) -> Yield<'a, 'ctx, ControlFlow<(), ()>, SyncEffect> { + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { + E::wrap(core::future::ready( match value { 0 => { self.value = Some(Ok(Variant::None)); @@ -322,6 +322,6 @@ impl<'a, 'ctx: 'a, T> Value<'a, 'ctx, OwnedStatic<u16>, SyncEffect> for VariantV self.value = Some(Err(Error::UnknownVariantNum(value.try_into().ok()))); ControlFlow::Break(()) } - } + })) } } diff --git a/src/effect.rs b/src/effect.rs index dd8b971..bb54166 100644 --- a/src/effect.rs +++ b/src/effect.rs @@ -1,110 +1,145 @@ -use crate::{any::AnyTrait, hkt, type_class}; - -pub trait AsObj<'a, 'ctx: 'a> { - fn as_obj(&self) -> &dyn AnyTrait<'ctx>; - fn as_obj_mut(&mut self) -> &mut dyn AnyTrait<'ctx>; - fn into_obj(self) -> &'a mut dyn AnyTrait<'ctx>; -} - -impl<'a, 'ctx: 'a> AsObj<'a, 'ctx> for &'a mut (dyn AnyTrait<'ctx> + 'a) { - fn as_obj(&self) -> &dyn AnyTrait<'ctx> { - *self +use core::{ + marker::PhantomData, + pin::pin, + ptr, + task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, +}; + +use crate::{higher_ranked_trait, higher_ranked_type}; + +higher_ranked_trait! { + pub type class SendFuture['ctx, Output]: [for<'lt> core::future::Future<Output = Output> + Send + 'lt] + where { + Output: Send, } - - fn as_obj_mut(&mut self) -> &mut dyn AnyTrait<'ctx> { - *self - } - - fn into_obj(self) -> &'a mut dyn AnyTrait<'ctx> { - self + for where { + Output: 'lt, } } -impl<'a, 'ctx: 'a> AsObj<'a, 'ctx> for &'a mut (dyn AnyTrait<'ctx> + Send + 'a) { - fn as_obj(&self) -> &dyn AnyTrait<'ctx> { - *self - } - - fn as_obj_mut(&mut self) -> &mut dyn AnyTrait<'ctx> { - *self - } - - fn into_obj(self) -> &'a mut dyn AnyTrait<'ctx> { - self +/// Trait for effects. +pub trait Effect<'ctx>: 'static { + type Future<T: Send>: SendFuture::Trait<'ctx, T>; + + fn wrap<'a, F>(future: F) -> SendFuture::T<'a, 'ctx, Self::Future<F::Output>, F::Output> + where + F: core::future::Future + Send + 'a, + <F as core::future::Future>::Output: Send; + + #[cfg(feature = "alloc")] + #[inline] + fn wrap_boxed<'a, F>( + future: core::pin::Pin<Box<F>>, + ) -> SendFuture::T<'a, 'ctx, Self::Future<F::Output>, F::Output> + where + F: core::future::Future + Send + 'a, + <F as core::future::Future>::Output: Send, + { + Self::wrap(future) } } -type_class!(for<'lt, 'ctx> pub as_obj: AsObj<'lt, 'ctx>); -type_class!(for<'lt, 'ctx> pub any_t); +pub type Future<'a, 'ctx, T, E> = SendFuture::T<'a, 'ctx, <E as Effect<'ctx>>::Future<T>, T>; -pub trait EffectAnyTrait<'ctx>: 'static { - /// The `dyn AnyTrait<'ctx>` for the effect. - /// - /// this allows adding extra bounds to the trait object. - type AnyTrait: as_obj::Hkt<'ctx>; +pub struct Blocking<B = Spin> { + _marker: PhantomData<fn() -> B>, } -/// Trait for effects. -pub trait Effect<'ctx, T>: EffectAnyTrait<'ctx> { - /// The type functions return for this effect. - /// - /// This type should resolve into a `T`. - type Yield: any_t::Hkt<'ctx>; +pub trait BlockOn: 'static { + fn block_on<F>(future: F) -> F::Output + where + F: core::future::Future + Send, + <F as core::future::Future>::Output: Send; } -pub type Yield<'a, 'ctx, T, E> = any_t::T<'a, 'ctx, <E as Effect<'ctx, T>>::Yield>; - -pub enum SyncEffect {} - -hkt!((as_obj): for<'a, 'ctx> pub AnyTraitSendObj => &'a mut (dyn AnyTrait<'ctx> + Send + 'a)); -hkt!((as_obj): for<'a, 'ctx> pub AnyTraitObj => &'a mut (dyn AnyTrait<'ctx> + 'a)); - -hkt!((any_t): for<'a, 'ctx> pub SyncYield[T] => T); - -impl<'ctx, T> Effect<'ctx, T> for SyncEffect { - type Yield = SyncYield<'ctx, T>; +/// [`BlockOn`] implementer that just spins on the future. +/// +/// This is useful for futures that are alwayd ready. +pub enum Spin {} + +impl BlockOn for Spin { + #[inline(always)] + fn block_on<F>(future: F) -> F::Output + where + F: core::future::Future + Send, + { + let waker = noop(); + let mut context = Context::from_waker(&waker); + + let mut future = pin!(future); + loop { + if let Poll::Ready(value) = future.as_mut().poll(&mut context) { + return value; + } + } + } } -impl<'ctx> EffectAnyTrait<'ctx> for SyncEffect { - type AnyTrait = AnyTraitObj<'ctx>; +#[inline] +pub fn noop() -> Waker { + const VTABLE: &'static RawWakerVTable = &RawWakerVTable::new( + // Cloning just returns a new no-op raw waker + |_| RAW, + // `wake` does nothing + |_| {}, + // `wake_by_ref` does nothing + |_| {}, + // Dropping does nothing as we don't allocate anything + |_| {}, + ); + const RAW: RawWaker = RawWaker::new(ptr::null(), &VTABLE); + unsafe { Waker::from_raw(RAW) } } -#[cfg(feature = "alloc")] -hkt!((any_t): for<'a, 'ctx> pub AsyncSendYield[T] => - core::pin::Pin< - Box<dyn core::future::Future<Output = T> + Send + 'a>, - > -); +higher_ranked_type! { + pub type ReadyFuture['ctx, Output]: (SendFuture)[Output] + where { + Output: Send, + } = for<'lt> core::future::Ready<Output> +} -#[cfg(feature = "alloc")] -pub enum AsyncSendEffect {} +impl<'ctx, B: BlockOn> Effect<'ctx> for Blocking<B> { + type Future<T: Send> = ReadyFuture<'ctx, T>; -#[cfg(feature = "alloc")] -impl<'ctx, T> Effect<'ctx, T> for AsyncSendEffect { - type Yield = AsyncSendYield<'ctx, T>; + fn wrap<'a, F>(future: F) -> SendFuture::T<'a, 'ctx, Self::Future<F::Output>, F::Output> + where + F: core::future::Future + Send + 'a, + <F as core::future::Future>::Output: Send, + { + core::future::ready(B::block_on(future)) + } } #[cfg(feature = "alloc")] -impl<'ctx> EffectAnyTrait<'ctx> for AsyncSendEffect { - type AnyTrait = AnyTraitSendObj<'ctx>; +higher_ranked_type! { + pub type BoxFuture['ctx, Output]: (SendFuture)[Output] + where { + Output: Send, + } = for<'lt> core::pin::Pin<Box<dyn core::future::Future<Output = Output> + Send + 'lt>> } #[cfg(feature = "alloc")] -hkt!((any_t): for<'a, 'ctx> pub AsyncYield[T] => - core::pin::Pin< - Box<dyn core::future::Future<Output = T> + 'a>, - > -); - -#[cfg(feature = "alloc")] -pub enum AsyncEffect {} +pub enum Async {} #[cfg(feature = "alloc")] -impl<'ctx, T> Effect<'ctx, T> for AsyncEffect { - type Yield = AsyncYield<'ctx, T>; -} +impl<'ctx> Effect<'ctx> for Async { + type Future<T: Send> = BoxFuture<'ctx, T>; + + fn wrap<'a, F>(future: F) -> SendFuture::T<'a, 'ctx, Self::Future<F::Output>, F::Output> + where + F: core::future::Future + Send + 'a, + <F as core::future::Future>::Output: Send, + { + Box::pin(future) + } -#[cfg(feature = "alloc")] -impl<'ctx> EffectAnyTrait<'ctx> for AsyncEffect { - type AnyTrait = AnyTraitObj<'ctx>; + fn wrap_boxed<'a, F>( + future: core::pin::Pin<Box<F>>, + ) -> SendFuture::T<'a, 'ctx, Self::Future<F::Output>, F::Output> + where + F: core::future::Future + Send + 'a, + <F as core::future::Future>::Output: Send, + { + future + } } @@ -1,79 +1,150 @@ -// Lifetime bound to be used in `for<'lt>` blocks. -pub type Bound<'lt, 'bound> = &'lt &'bound (); - +//! Higher-ranked traits and types. +//! +//! A higher-ranked type is a type that needs a lifetime to be "complete". Consider the following +//! code. +//! ```rs +//! type IntBorrow<'a> = &'a i32; +//! ``` +//! What if we could pass just `IntBorrow` around as a type; without it's lifetime. +//! In Rust syntax, this type would be `for<'a> IntBorrow<'a>`. `'a` can be filled in with any +//! lifetime. Sadly, Rust only allows `for<'a>` in trait objects. However, trait object provide +//! enough for us to implement arbitrary hifher-ranked types with some extra effort. +//! +//! In this module the [`higher_ranked_type!`] macro generates a type that needs a lifetime to +//! be complete. Before a higher-ranked type can be generated we need a higher-ranked trait to +//! describe what behavior the resulting "true" type will have. +//! +//! The [`higher_ranked_trait!`] macro cgenerates a trait that can be used with +//! [`higher_ranked_type!`] and as a bound by code wanting to accept a higher ranked type. +//! Bounding a generic by a higher-ranked trait simultaniously allows any higher-ranked type with +//! a "true" type with the required traits and any lifetime to be given to that "true" type. + +/// Used to cause `'lt` to have extra bounds when using `for<'lt>` syntax. +/// +/// Including this type where a `for<'lt>` is being generated will result in the following bounds +/// being applied. +/// * `'bound: 'lt` - `'lt` will **not** outlive `'bound`. +/// * `T: 'lt` - `T` will outlive `'lt`. +pub type Bound<'lt, 'bound, T = ()> = (&'lt &'bound (), &'lt T); + +/// Generate a higher-ranked trait. #[doc(hidden)] #[macro_export] -macro_rules! type_class { - (for<$lt:lifetime, $ctx:lifetime> $vis:vis $name:ident $(: $($bound:tt)*)?) => { +macro_rules! higher_ranked_trait { + { + $vis:vis type class $name:ident[$ctx:lifetime $(, $($generic:tt)*)?]: [for<$lt:lifetime> $($($provides:tt)+)?] + $(where { + $($bound:tt)* + })? + $(for where { + $($for_bound:tt)* + })? + } => { $vis mod $name { + #![allow(unused, non_snake_case)] + use super::*; - pub trait ForLt<$lt, $ctx: $lt, B> { - type T: $($($bound)*)?; + pub trait ForLt<$lt, $ctx: $lt, B $(, $($generic)*)?> + where $($($bound)*)? $($($for_bound)*)? + + { + type T$(: $($provides)+)?; } - pub trait Hkt<$ctx>: for<$lt> ForLt<$lt, $ctx, $crate::hkt::Bound<$lt, $ctx>> {} + pub trait Trait<$ctx $(, $($generic)*)?>: for<$lt> ForLt<$lt, $ctx, $crate::hkt::Bound<$lt, $ctx $(, $($generic)*)?> $(, $($generic)*)?> + where + $($($bound)*)? + {} - impl<$ctx, T> Hkt<$ctx> for T + impl<$ctx, ____ $(, $($generic)*)?> Trait<$ctx $(, $($generic)*)?> for ____ where - T: for<$lt> ForLt<$lt, $ctx, $crate::hkt::Bound<$lt, $ctx>> + ____: for<$lt> ForLt<$lt, $ctx, $crate::hkt::Bound<$lt, $ctx $(, $($generic)*)?> $(, $($generic)*)?>, + $($($bound)*)? {} - pub type T<$lt, $ctx, H> = <H as ForLt<$lt, $ctx, $crate::hkt::Bound<$lt, $ctx>>>::T; + pub type T<$lt, $ctx, H $(, $($generic)*)?> = <H as ForLt<$lt, $ctx, $crate::hkt::Bound<$lt, $ctx $(, $($generic)*)?> $(, $($generic)*)?>>::T; } }; } #[doc(inline)] -pub use type_class; +pub use higher_ranked_trait; +/// Generate a higher-ranked type. #[doc(hidden)] #[macro_export] -macro_rules! hkt { - ( - ($($type_class:tt)*): - for<$lt:lifetime, $ctx:lifetime> - $vis:vis $name:ident$([$($generic:tt)*])? - $(where {$($bound:tt)*})? => $($type:tt)* - ) => { +macro_rules! higher_ranked_type { + { + $vis:vis type $name:ident[$ctx:lifetime $(, $($generic:tt)*)?]: ($($type_class:tt)*)$([$($type_class_generic:tt)*])? + $(where {$($bound:tt)*})? + = for<$lt:lifetime> $for_lt_type:ty + $(where {$($higher_bound:tt)*})? + } => { $vis struct $name<$ctx $(, $($generic)*)?>(core::marker::PhantomData<fn() -> (&$ctx (), $($($generic)*)?)>); - impl<$lt, $ctx $(, $($generic)*)?> $($type_class)*::ForLt<$lt, $ctx, $crate::hkt::Bound<$lt, $ctx>> for $name<$ctx $(, $($generic)*)?> - $(where $($bound)*)? + impl<$lt, $ctx $(, $($generic)*)?> $($type_class)*::ForLt<$lt, $ctx, $crate::hkt::Bound<$lt, $ctx $(, $($generic)*)?> $(, $($type_class_generic)*)?> for $name<$ctx $(, $($generic)*)?> + where $($($bound)*)? $($($higher_bound)*)? { - type T = $($type)*; + type T = $for_lt_type; } } } #[doc(inline)] -pub use hkt; +pub use higher_ranked_type; + +higher_ranked_trait! { + pub type class AnySend['ctx]: [for<'lt> Send] +} #[cfg(test)] mod test { use super::*; - trait Demo<'lt, 'ctx> { + /// Some trait with two lifetimes and a generic. + trait Demo<'lt, 'ctx, T: Send + 'lt> { fn add(&self, x: &'lt &'ctx i32) -> i32; } - impl<'lt, 'ctx> Demo<'lt, 'ctx> for i32 { + impl<'lt, 'ctx, T: Send + 'lt> Demo<'lt, 'ctx, T> for i32 { fn add(&self, x: &'lt &'ctx i32) -> i32 { self + **x } } - impl<'lt, 'ctx> Demo<'lt, 'ctx> for &'lt (dyn Demo<'lt, 'ctx> + 'lt) { + impl<'lt, 'ctx, T: Send + 'lt> Demo<'lt, 'ctx, T> for &'lt (dyn Demo<'lt, 'ctx, T> + 'lt) { fn add(&self, x: &'lt &'ctx i32) -> i32 { (**self).add(x) } } - type_class!(for<'lt, 'ctx> any_t: Demo<'lt, 'ctx>); + // Higher-ranked trait that requires the "true" type to implement Demo. + higher_ranked_trait! { + type class Any['ctx, T]: [for<'lt> Demo<'lt, 'ctx, T>] + where { + T: Send, + } + for where { + T: 'lt + } + } - hkt!((any_t): for<'lt, 'ctx> X => &'lt (dyn Demo<'lt, 'ctx> + 'lt)); + // Higher-ranked type with a "true" type of a borrow of a trait object. + // The complex part to support here is the `+ 'lt`. + // This entire module is specialized to support this usecase because that is what treaty needs + // for it's API. + higher_ranked_type! { + type X['ctx, T]: (Any)[T] + where { + T: Send, + } = for<'lt> &'lt (dyn Demo<'lt, 'ctx, T> + 'lt) + } - fn demo<'lt, 'ctx, T: any_t::Hkt<'ctx>>(x: any_t::T<'lt, 'ctx, T>, y: &'lt &'ctx i32) { + // We bound the generic T by the higher-ranked trait Any. + // + // We then inject a 'lt into the higher-ranked type to get a "true" type. + fn demo<'lt, 'ctx, T: Any::Trait<'ctx, i32>>(x: Any::T<'lt, 'ctx, T, i32>, y: &'lt &'ctx i32) { assert_eq!(x.add(y), 10); } @@ -83,9 +154,10 @@ mod test { let ctx = &ctx; { + // The lifetimes here can't be 'static because local isn't static even though z could be. let local = &ctx; - let z: &dyn Demo<'_, '_> = &8i32; - demo::<X<'_>>(z, local); + let z: &dyn Demo<'_, '_, i32> = &8i32; + demo::<X<'_, i32>>(z, local); } } } @@ -16,7 +16,7 @@ pub mod symbol; mod walk; // pub mod impls; -// pub mod transform; +mod transform; // pub use build::Build; // pub use build::Builder; @@ -25,6 +25,7 @@ mod walk; // pub use walk::Walker; pub use build::*; +pub use transform::*; pub use walk::*; #[macro_export] diff --git a/src/protocol.rs b/src/protocol.rs index 605551a..33d73be 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -52,26 +52,10 @@ //! This is done via the help of the [`AnyImpl`] type. This is not required for the core //! idea of DIDETs. -use core::{ - future::Future, - marker::PhantomData, - pin::{pin, Pin}, - ptr, - task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, -}; - -use crate::hkt::{hkt, type_class}; -use crate::{ - any::AnyTrait, - effect::{as_obj, EffectAnyTrait}, -}; - pub mod visitor; pub mod walker; -#[cfg(all(feature = "alloc", not(feature = "std")))] -use alloc::boxed::Box; +use crate::any::AnyTrait; -pub type Visitor<'a, 'ctx, Effect> = - as_obj::T<'a, 'ctx, <Effect as EffectAnyTrait<'ctx>>::AnyTrait>; -pub type Walker<'a, 'ctx, Effect> = as_obj::T<'a, 'ctx, <Effect as EffectAnyTrait<'ctx>>::AnyTrait>; +pub type Visitor<'a, 'ctx> = &'a mut (dyn AnyTrait<'ctx> + Send + 'a); +pub type Walker<'a, 'ctx> = &'a mut (dyn AnyTrait<'ctx> + Send + 'a); diff --git a/src/protocol/visitor.rs b/src/protocol/visitor.rs index 7b91c7a..1f69862 100644 --- a/src/protocol/visitor.rs +++ b/src/protocol/visitor.rs @@ -1,9 +1,4 @@ -mod request_hint; -mod sequence; -mod tagged; -mod value; - -pub use request_hint::*; -pub use sequence::*; -pub use tagged::*; -pub use value::*; +pub mod request_hint; +pub mod sequence; +pub mod tagged; +pub mod value; diff --git a/src/protocol/visitor/request_hint.rs b/src/protocol/visitor/request_hint.rs index c7aa847..8bd8431 100644 --- a/src/protocol/visitor/request_hint.rs +++ b/src/protocol/visitor/request_hint.rs @@ -1,27 +1,27 @@ use core::ops::ControlFlow; use crate::{ - effect::{Effect, SyncEffect, Yield}, + effect::{Effect, Future}, nameable, protocol::Walker, }; /// Protocol for requesting a hint from a visitor. -pub trait RequestHint<'a, 'ctx: 'a, E: Effect<'ctx, ControlFlow<(), ()>>> { +pub trait RequestHint<'a, 'ctx: 'a, E: Effect<'ctx>> { /// Call this to request a hint. /// /// `walker` is what the visitor (`self`) will call to give a hint using the /// [`Hint`][crate::builtins::walker::Hint] protocol. fn request_hint( &'a mut self, - walker: Walker<'a, 'ctx, E>, - ) -> Yield<'a, 'ctx, ControlFlow<(), ()>, E>; + walker: Walker<'a, 'ctx>, + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E>; } nameable! { pub struct Name['a, 'ctx, E]; impl [E] for dyn RequestHint<'a, 'ctx, E> + 'a where { - E: Effect<'ctx, ControlFlow<(), ()>>, + E: Effect<'ctx>, 'ctx: 'a } } diff --git a/src/protocol/visitor/sequence.rs b/src/protocol/visitor/sequence.rs index 2a5f9f3..46c8e71 100644 --- a/src/protocol/visitor/sequence.rs +++ b/src/protocol/visitor/sequence.rs @@ -1,45 +1,42 @@ use core::ops::ControlFlow; use crate::{ - effect::{any_t, Effect, SyncEffect, Yield}, - hkt::hkt, + effect::{Effect, Future}, + higher_ranked_type, + hkt::AnySend, nameable, - protocol::{walker::HintMeta, Visitor}, + protocol::{walker::hint::HintMeta, Visitor}, }; -pub trait Sequence<'ctx, E: Effect<'ctx, ControlFlow<(), ()>>> { +pub trait Sequence<'ctx, E: Effect<'ctx>> { fn visit<'a>( &'a mut self, scope: &'a mut dyn SequenceScope<'ctx, E>, - ) -> Yield<'a, 'ctx, ControlFlow<(), ()>, E> - where - 'ctx: 'a; + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E>; } nameable! { pub struct Name['a, 'ctx, E]; impl [E] for dyn Sequence<'ctx, E> + 'a where { - E: Effect<'ctx, ControlFlow<(), ()>> + Effect<'ctx, ControlFlow<(), Status>>, + E: Effect<'ctx>, 'ctx: 'a } impl [E] where dyn Sequence<'ctx, E> + 'a { - E: Effect<'ctx, ControlFlow<(), ()>> + Effect<'ctx, ControlFlow<(), Status>>, + E: Effect<'ctx>, 'ctx: 'a } } pub trait SequenceScope<'ctx, E> where - E: Effect<'ctx, ControlFlow<(), Status>>, + E: Effect<'ctx>, { fn next<'a>( &'a mut self, - visitor: Visitor<'a, 'ctx, E>, - ) -> Yield<'a, 'ctx, ControlFlow<(), Status>, E> - where - 'ctx: 'a; + visitor: Visitor<'a, 'ctx>, + ) -> Future<'a, 'ctx, ControlFlow<(), Status>, E>; } #[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Debug)] @@ -48,7 +45,9 @@ pub enum Status { Continue, } -hkt!((any_t): for<'a, 'ctx> pub KnownHkt => Known); +higher_ranked_type! { + pub type KnownHkt['ctx]: (AnySend) = for<'lt> Known +} #[derive(Default)] pub struct Known { @@ -59,9 +58,7 @@ pub struct Hint { pub len: (usize, Option<usize>), } -impl<'a, 'ctx: 'a, E: Effect<'ctx, ControlFlow<(), ()>>> HintMeta<'ctx> - for dyn Sequence<'ctx, E> + '_ -{ +impl<'a, 'ctx: 'a, E: Effect<'ctx>> HintMeta<'ctx> for dyn Sequence<'ctx, E> + '_ { type Known = KnownHkt<'ctx>; type Hint = Hint; diff --git a/src/protocol/visitor/tagged.rs b/src/protocol/visitor/tagged.rs index 9b5caf5..1622f4d 100644 --- a/src/protocol/visitor/tagged.rs +++ b/src/protocol/visitor/tagged.rs @@ -1,55 +1,52 @@ use core::ops::ControlFlow; use crate::{ - effect::{any_t, Effect, SyncEffect, Yield}, - hkt::hkt, + effect::{Effect, Future}, + higher_ranked_type, + hkt::AnySend, nameable, - protocol::{walker::HintMeta, Visitor}, + protocol::{walker::hint::HintMeta, Visitor}, symbol::Symbol, }; -pub trait Tagged<'ctx, E: Effect<'ctx, ControlFlow<(), ()>>> { +pub trait Tagged<'ctx, E: Effect<'ctx>> { fn visit<'a>( &'a mut self, - scope: &'a mut dyn TaggedScope<'ctx, E>, - ) -> Yield<'a, 'ctx, ControlFlow<(), ()>, E> - where - 'ctx: 'a; + scope: &'a mut (dyn TaggedScope<'ctx, E> + Send), + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E>; } nameable! { pub struct Name['a, 'ctx, E]; impl [E] for dyn Tagged<'ctx, E> + 'a where { - E: Effect<'ctx, ControlFlow<(), ()>>, + E: Effect<'ctx>, 'ctx: 'a } impl [E] where dyn Tagged<'ctx, E> + 'a { - E: Effect<'ctx, ControlFlow<(), ()>>, + E: Effect<'ctx>, 'ctx: 'a } } -pub trait TaggedScope<'ctx, E: Effect<'ctx, ControlFlow<(), ()>>> { - fn kind(&mut self) -> Symbol; +pub trait TaggedScope<'ctx, E: Effect<'ctx>> { + fn kind<'a>(&mut self) -> Future<'a, 'ctx, Symbol, E>; fn tag<'a>( &'a mut self, - visitor: Visitor<'a, 'ctx, E>, - ) -> Yield<'a, 'ctx, ControlFlow<(), ()>, E> - where - 'ctx: 'a; + visitor: Visitor<'a, 'ctx>, + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E>; fn value<'a>( &'a mut self, - visitor: Visitor<'a, 'ctx, E>, - ) -> Yield<'a, 'ctx, ControlFlow<(), ()>, E> - where - 'ctx: 'a; + visitor: Visitor<'a, 'ctx>, + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E>; } -hkt!((any_t): for<'a, 'ctx> pub KnownHkt => Known); +higher_ranked_type! { + pub type KnownHkt['ctx]: (AnySend) = for<'lt> Known +} pub struct Known { pub kind_available: Option<bool>, diff --git a/src/protocol/visitor/value.rs b/src/protocol/visitor/value.rs index 20c55d9..5628eac 100644 --- a/src/protocol/visitor/value.rs +++ b/src/protocol/visitor/value.rs @@ -6,16 +6,17 @@ use core::ops::ControlFlow; use crate::{ any::{TypeName, TypeNameable}, - effect::{any_t, Effect, SyncEffect, Yield}, - hkt::hkt, + effect::{Effect, Future}, + higher_ranked_type, + hkt::AnySend, nameable, - protocol::walker::HintMeta, + protocol::walker::hint::HintMeta, }; /// Trait object for the [`Value`] protocol. /// /// Types implementing the [`Value`] protocol will implement this trait. -pub trait Value<'a, 'ctx: 'a, T, E: Effect<'ctx, ControlFlow<(), ()>>> { +pub trait Value<'a, 'ctx: 'a, T, E: Effect<'ctx>> { /// Visit a value of type `T`. /// /// Use this to give a value to a visitor. Its expected that a walker @@ -25,7 +26,7 @@ pub trait Value<'a, 'ctx: 'a, T, E: Effect<'ctx, ControlFlow<(), ()>>> { /// If a [`ControlFlow::Break`] is returned then the walker /// should stop walking as soon as possible as there has likely been /// and error. - fn visit(&'a mut self, value: T) -> Yield<'a, 'ctx, ControlFlow<(), ()>, E>; + fn visit(&'a mut self, value: T) -> Future<'a, 'ctx, ControlFlow<(), ()>, E>; } nameable! { @@ -33,31 +34,31 @@ nameable! { impl [T::Name, E] for dyn Value<'a, 'ctx, T, E> + 'a where { T: TypeNameable<'a, 'ctx> + ?Sized, - E: Effect<'ctx, ControlFlow<(), ()>>, + E: Effect<'ctx>, 'ctx: 'a, } impl [T, E] where dyn Value<'a, 'ctx, T::Nameable, E> + 'a { T: TypeName<'a, 'ctx> + ?Sized, - E: Effect<'ctx, ControlFlow<(), ()>>, + E: Effect<'ctx>, 'ctx: 'a, } } -hkt!((any_t): for<'a, 'ctx> pub KnownHkt => ()); +higher_ranked_type! { + pub type Known['ctx]: (AnySend) = for<'lt> () +} // This enrolls the Value protocol into the walker hint system. -impl<'a, 'ctx: 'a, T, E: Effect<'ctx, ControlFlow<(), ()>>> HintMeta<'ctx> - for dyn Value<'a, 'ctx, T, E> + 'a -{ - type Known = KnownHkt<'ctx>; +impl<'a, 'ctx: 'a, T, E: Effect<'ctx>> HintMeta<'ctx> for dyn Value<'a, 'ctx, T, E> + 'a { + type Known = Known<'ctx>; type Hint = (); } #[cfg(test)] mod test { - use core::ops::ControlFlow; + use core::{marker::PhantomData, ops::ControlFlow}; use crate::{ any::{ @@ -65,87 +66,110 @@ mod test { AnyTrait, }, any_trait, + effect::{BlockOn, Blocking, Spin}, }; use super::*; #[test] fn visit() { - struct Visitor(Option<i32>); + struct Visitor<E>(Option<i32>, PhantomData<fn() -> E>); - impl<'a, 'ctx: 'a> Value<'a, 'ctx, OwnedStatic<i32>, SyncEffect> for Visitor { + impl<'a, 'ctx: 'a, E> Value<'a, 'ctx, OwnedStatic<i32>, E> for Visitor<E> + where + E: Effect<'ctx>, + { fn visit( &'a mut self, OwnedStatic(value): OwnedStatic<i32>, - ) -> core::ops::ControlFlow<()> { - self.0 = Some(value); - ControlFlow::Continue(()) + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { + E::wrap(async move { + self.0 = Some(value); + ControlFlow::Continue(()) + }) } } - impl<'a, 'ctx: 'a> Value<'a, 'ctx, BorrowedStatic<'ctx, i32>, SyncEffect> for Visitor { + impl<'a, 'ctx: 'a, E> Value<'a, 'ctx, BorrowedStatic<'ctx, i32>, E> for Visitor<E> + where + E: Effect<'ctx>, + { fn visit( &'a mut self, BorrowedStatic(value): BorrowedStatic<'ctx, i32>, - ) -> core::ops::ControlFlow<()> { - self.0 = Some(*value); - ControlFlow::Continue(()) + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { + E::wrap(async { + self.0 = Some(*value); + ControlFlow::Continue(()) + }) } } any_trait! { - impl['a, 'ctx] Visitor = [ - dyn Value<'ctx, OwnedStatic<i32>> + 'a, - dyn Value<'ctx, BorrowedStatic<'ctx, i32>> + 'a, - ] + impl['a, 'ctx, E] Visitor<E> = [ + dyn Value<'a, 'ctx, OwnedStatic<i32>, E> + 'a, + dyn Value<'a, 'ctx, BorrowedStatic<'ctx, i32>, E> + 'a, + ] where E: Effect<'ctx>, } - let mut v = Visitor(None); - let object: &mut dyn AnyTrait<'_> = &mut v; - object - .upcast_mut::<dyn Value<'_, OwnedStatic<i32>>>() - .unwrap() - .visit(OwnedStatic(42)); + let mut v = Visitor::<Blocking>(None, PhantomData); + let object: &mut (dyn AnyTrait<'_> + Send) = &mut v; + Spin::block_on( + object + .upcast_mut::<dyn Value<'_, '_, OwnedStatic<i32>, Blocking>>() + .unwrap() + .visit(OwnedStatic(42)), + ); assert_eq!(v.0, Some(42)); - let object: &mut dyn AnyTrait<'_> = &mut v; - object - .upcast_mut::<dyn Value<'_, BorrowedStatic<'_, i32>>>() - .unwrap() - .visit(BorrowedStatic(&101)); + let object: &mut (dyn AnyTrait<'_> + Send) = &mut v; + Spin::block_on( + object + .upcast_mut::<dyn Value<'_, '_, BorrowedStatic<'_, i32>, Blocking>>() + .unwrap() + .visit(BorrowedStatic(&101)), + ); assert_eq!(v.0, Some(101)); } #[test] fn visit_borrowed() { - struct Visitor<'ctx>(Option<&'ctx mut String>); + struct Visitor<'ctx, E>(Option<&'ctx mut String>, PhantomData<fn() -> E>); - impl<'a, 'ctx> Value<'a, 'ctx, BorrowedMutStatic<'ctx, String>, SyncEffect> for Visitor<'ctx> { + impl<'a, 'ctx: 'a, E> Value<'a, 'ctx, BorrowedMutStatic<'ctx, String>, E> for Visitor<'ctx, E> + where + E: Effect<'ctx>, + { fn visit( &'a mut self, BorrowedMutStatic(value): BorrowedMutStatic<'ctx, String>, - ) -> ControlFlow<()> { - self.0 = Some(value); - ControlFlow::Continue(()) + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { + E::wrap(async { + self.0 = Some(value); + + ControlFlow::Continue(()) + }) } } any_trait! { - impl['a, 'ctx] Visitor<'ctx> = [ - dyn Value<'ctx, BorrowedMutStatic<'ctx, String>> + 'a, - ] + impl['a, 'ctx, E] Visitor<'ctx, E> = [ + dyn Value<'a, 'ctx, BorrowedMutStatic<'ctx, String>, E> + 'a, + ] where E: Effect<'ctx> } - let mut v = Visitor(None); + let mut v = Visitor::<Blocking>(None, PhantomData); let mut y = String::from("abc"); - let object: &mut dyn AnyTrait<'_> = &mut v; - object - .upcast_mut::<dyn Value<'_, _>>() - .unwrap() - .visit(BorrowedMutStatic(&mut y)); + let object: &mut (dyn AnyTrait<'_> + Send) = &mut v; + Spin::block_on( + object + .upcast_mut::<dyn Value<'_, '_, _, Blocking>>() + .unwrap() + .visit(BorrowedMutStatic(&mut y)), + ); v.0.unwrap().push_str("def"); assert_eq!(y, "abcdef"); @@ -153,32 +177,39 @@ mod test { #[test] fn visit_borrowed_unsized() { - struct Visitor<'ctx>(Option<&'ctx str>); + struct Visitor<'ctx, E>(Option<&'ctx str>, PhantomData<fn() -> E>); - impl<'a, 'ctx: 'a> Value<'a, 'ctx, BorrowedStatic<'ctx, str>, SyncEffect> for Visitor<'ctx> { + impl<'a, 'ctx: 'a, E> Value<'a, 'ctx, BorrowedStatic<'ctx, str>, E> for Visitor<'ctx, E> + where + E: Effect<'ctx>, + { fn visit( &'a mut self, BorrowedStatic(value): BorrowedStatic<'ctx, str>, - ) -> ControlFlow<()> { - self.0 = Some(value); - ControlFlow::Continue(()) + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { + E::wrap(async { + self.0 = Some(value); + ControlFlow::Continue(()) + }) } } any_trait! { - impl['a, 'ctx] Visitor<'ctx> = [ - dyn Value<'ctx, BorrowedStatic<'ctx, str>> + 'a, - ] + impl['a, 'ctx, E] Visitor<'ctx, E> = [ + dyn Value<'a, 'ctx, BorrowedStatic<'ctx, str>, E> + 'a, + ] where E: Effect<'ctx> } - let mut v = Visitor(None); + let mut v = Visitor::<Blocking>(None, PhantomData); let y = String::from("abc"); - let object: &mut dyn AnyTrait<'_> = &mut v; - object - .upcast_mut::<dyn Value<'_, BorrowedStatic<'_, str>> + '_>() - .unwrap() - .visit(BorrowedStatic(&y)); + let object: &mut (dyn AnyTrait<'_> + Send) = &mut v; + Spin::block_on( + object + .upcast_mut::<dyn Value<'_, '_, BorrowedStatic<'_, str>, Blocking> + '_>() + .unwrap() + .visit(BorrowedStatic(&y)), + ); assert_eq!(v.0, Some("abc")); } diff --git a/src/protocol/walker.rs b/src/protocol/walker.rs index 27ee8c5..a0216be 100644 --- a/src/protocol/walker.rs +++ b/src/protocol/walker.rs @@ -1,3 +1 @@ -mod hint; - -pub use hint::*; +pub mod hint; diff --git a/src/protocol/walker/hint.rs b/src/protocol/walker/hint.rs index 46ad675..2d723e4 100644 --- a/src/protocol/walker/hint.rs +++ b/src/protocol/walker/hint.rs @@ -8,7 +8,8 @@ use core::ops::ControlFlow; use crate::{ any::{TypeName, TypeNameable}, - effect::{any_t, Effect, EffectAnyTrait, SyncEffect, Yield}, + effect::{Effect, Future}, + hkt::AnySend, nameable, protocol::Visitor, }; @@ -21,36 +22,34 @@ pub trait HintMeta<'ctx> { /// /// This should be information easy to get without changing the state of the walker /// in an irreversible way. - type Known: any_t::Hkt<'ctx>; + type Known: AnySend::Trait<'ctx>; /// Extra information the visitor can give to the walker about what it is expecting. type Hint; } -pub type Known<'a, 'ctx, Protocol> = any_t::T<'a, 'ctx, <Protocol as HintMeta<'ctx>>::Known>; +pub type Known<'a, 'ctx, Protocol> = AnySend::T<'a, 'ctx, <Protocol as HintMeta<'ctx>>::Known>; /// Object implementing the [`Hint`] protocol. pub trait Hint<'ctx, Protocol: ?Sized + HintMeta<'ctx>, E> where - for<'a> E: Effect<'ctx, ControlFlow<(), ()>> - + Effect<'ctx, ControlFlow<(), Known<'a, 'ctx, Protocol>>>, + E: Effect<'ctx>, + E: for<'a> Effect<'ctx>, { /// Hint to the walker to use the `P` protocol. /// /// This should only be called once per [`RequestHint`]. fn hint<'a>( &'a mut self, - visitor: Visitor<'a, 'ctx, E>, + visitor: Visitor<'a, 'ctx>, hint: <Protocol as HintMeta<'ctx>>::Hint, - ) -> Yield<'a, 'ctx, ControlFlow<(), ()>, E>; + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E>; /// Ask the walker for information about it's support of the protocol. fn known<'a>( &'a mut self, hint: &'a <Protocol as HintMeta<'ctx>>::Hint, - ) -> Yield<'a, 'ctx, ControlFlow<(), Known<'a, 'ctx, Protocol>>, E> - where - 'ctx: 'a; + ) -> Future<'a, 'ctx, ControlFlow<(), Known<'a, 'ctx, Protocol>>, E>; } nameable! { @@ -58,13 +57,13 @@ nameable! { impl [Protocol::Name, E] for dyn Hint<'ctx, Protocol, E> + 'a where { Protocol: TypeNameable<'a, 'ctx> + ?Sized, - E: Effect<'ctx, ControlFlow<(), ()>>, + E: Effect<'ctx>, 'ctx: 'a, } impl [Protocol, E] where dyn Hint<'ctx, Protocol::Nameable, E> + 'a { Protocol: TypeName<'a, 'ctx> + ?Sized, - E: Effect<'ctx, ControlFlow<(), ()>>, + E: Effect<'ctx>, 'ctx: 'a, } } @@ -73,14 +72,19 @@ nameable! { mod test { use core::ops::ControlFlow; - use crate::any::{LtTypeId, TypeNameable}; - use crate::hkt::hkt; + use crate::{ + any::TypeNameable, + effect::{BlockOn, Blocking, Spin}, + higher_ranked_type, + }; use super::*; #[test] fn demo() { - struct X; + struct X<'ctx>(&'ctx mut i32); + + #[derive(Debug)] struct Y; nameable! { @@ -88,27 +92,29 @@ mod test { impl for Y where {} } - impl<'ctx, X> Hint<'ctx, Y> for X { + impl<'ctx, E> Hint<'ctx, Y, E> for X<'ctx> + where + E: Effect<'ctx>, + { fn hint<'a>( &'a mut self, - visitor: Visitor<'a, 'ctx, SyncEffect>, - hint: <Y as HintMeta<'ctx>>::Hint, - ) -> ControlFlow<()> { + _visitor: Visitor<'a, 'ctx>, + _hint: <Y as HintMeta<'ctx>>::Hint, + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { todo!() } fn known<'a>( &'a mut self, - hint: &'a <Y as HintMeta<'ctx>>::Hint, - ) -> ControlFlow<(), Known<'a, 'ctx, SyncEffect>> - where - 'ctx: 'a, - { - todo!() + _hint: &'a <Y as HintMeta<'ctx>>::Hint, + ) -> Future<'a, 'ctx, ControlFlow<(), Known<'a, 'ctx, Y>>, E> { + E::wrap(async { ControlFlow::Continue(&mut *self.0) }) } } - hkt!((any_t): for<'a, 'ctx> KnownHkt => ()); + higher_ranked_type! { + type KnownHkt['ctx]: (AnySend) = for<'lt> &'lt mut i32 + } impl<'ctx> HintMeta<'ctx> for Y { type Known = KnownHkt<'ctx>; @@ -116,13 +122,18 @@ mod test { type Hint = (); } - let x = X; - let y: &dyn Hint<'_, Y> = &x; - - fn id<'a, 'ctx, T: ?Sized + TypeNameable<'a, 'ctx>>(x: &T) { - dbg!(LtTypeId::of::<T>()); - } + let mut z = 42; + let mut x = X(&mut z); + let y: &mut dyn Hint<'_, Y, Blocking> = &mut x; + fn id<'a, 'ctx, T: ?Sized + TypeNameable<'a, 'ctx>>(_x: &T) {} id(y); + + let x = Spin::block_on(y.known(&())); + match x { + ControlFlow::Continue(value) => *value += 1, + ControlFlow::Break(_) => todo!(), + } + assert_eq!(z, 43); } } diff --git a/src/transform.rs b/src/transform.rs index 5fbcb79..2e3d14b 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -1,28 +1,30 @@ use crate::{ - build::{Build, Builder}, - walk::Walk, + build::Builder, + effect::{Effect, Future}, Walker, }; -#[derive(thiserror::Error, Debug)] -pub enum Either<A, B> { - #[error(transparent)] - A(A), +#[inline] +pub fn transform< + 'a, + 'ctx, + B: Builder<'ctx, Effect = E> + 'a, + W: Walker<'ctx, Effect = E> + 'a, + E: Effect<'ctx>, +>( + seed: B::Seed, + walker: W, +) -> Future<'a, 'ctx, (Result<B::Value, B::Error>, Result<W::Output, W::Error>), E> { + E::wrap(async { + // Create builder from seed value; + let mut builder = B::from_seed(seed).await; - #[error(transparent)] - B(B), -} + // Walk the walker with the builder as the visitor. + let walker_result = walker.walk(builder.as_visitor()).await; + + // Finish building the value. + let builder_result = builder.build().await; -pub fn from<'ctx, U, T>( - value: T, -) -> Result<U, Either<<T::Walker as Walker<'ctx>>::Error, <U::Builder as Builder<'ctx>>::Error>> -where - T: Walk<'ctx>, - U: Build<'ctx>, -{ - let mut builder = U::Builder::default(); - T::Walker::from(value) - .walk(builder.as_visitor()) - .map_err(Either::A)?; - builder.build().map_err(Either::B) + (builder_result, walker_result) + }) } diff --git a/src/walk.rs b/src/walk.rs index 582af96..f0c5c65 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -1,18 +1,25 @@ pub mod walkers; use crate::{ - effect::{Effect, Yield}, + effect::{Effect, Future}, protocol::Visitor, }; /// A type that can be walked. -pub trait Walk<'ctx>: Sized { +pub trait Walk<'ctx>: WalkerTypes<'ctx> + Sized { /// The walker for the type. - type Walker: Walker<'ctx> + From<Self>; + type Walker<E: Effect<'ctx>>: Walker<'ctx, Error = Self::Error, Output = Self::Output, Effect = E>; + + fn into_walker<E: Effect<'ctx>>(self) -> Self::Walker<E>; } -pub fn into_walker<'ctx, T: Walk<'ctx>>(value: T) -> T::Walker { - <T as Walk<'ctx>>::Walker::from(value) +pub trait WalkerTypes<'ctx> { + type Error: Send; + + /// An arbitrary type the walker is left with after walking. + /// + /// Its recommended that this is `Self` if the walker is repeatable. + type Output: Send; } /// Walker for a type. @@ -24,25 +31,16 @@ pub fn into_walker<'ctx, T: Walk<'ctx>>(value: T) -> T::Walker { /// - Call [From::from()] with a value to be walked to make a walker. /// - Call [Self::walk()] to walk the value. Data will be sent to the provided /// visitor. -pub trait Walker<'ctx> { - type Effect: Effect<'ctx, Result<Self::Output, Self::Error>>; - - type Error; - - /// An arbitrary type the walker is left with after walking. - /// - /// Its recommended that this is `Self` if the walker is repeatable. - type Output; +pub trait Walker<'ctx>: WalkerTypes<'ctx> + Send { + type Effect: Effect<'ctx>; /// Walk the value. /// /// The walker should send data to the `visitor` as it walks the value. - #[must_use] fn walk<'a>( self, - visitor: Visitor<'a, 'ctx, Self::Effect>, - ) -> Yield<'a, 'ctx, Result<Self::Output, Self::Error>, Self::Effect> + visitor: Visitor<'a, 'ctx>, + ) -> Future<'a, 'ctx, Result<Self::Output, Self::Error>, Self::Effect> where - Self: 'a, - 'ctx: 'a; + Self: 'a; } diff --git a/src/walk/walkers/core.rs b/src/walk/walkers/core.rs index 7ea094a..6e4822f 100644 --- a/src/walk/walkers/core.rs +++ b/src/walk/walkers/core.rs @@ -1,2 +1,2 @@ -pub mod array; +// pub mod array; pub mod bool; diff --git a/src/walk/walkers/core/bool.rs b/src/walk/walkers/core/bool.rs index 0fd9cbd..b61f75b 100644 --- a/src/walk/walkers/core/bool.rs +++ b/src/walk/walkers/core/bool.rs @@ -1,51 +1,55 @@ -use crate::{any::static_wrapper::OwnedStatic, protocol::visitor::Value}; -use core::{mem::MaybeUninit, ops::ControlFlow}; +use crate::{any::static_wrapper::OwnedStatic, protocol::visitor::value::Value}; +use core::{marker::PhantomData, mem::MaybeUninit, ops::ControlFlow}; use crate::{ any_trait, - effect::{Effect, SyncEffect, Yield}, + effect::{Effect, Future}, protocol::{ - visitor::{RequestHint, Sequence, SequenceScope, Status}, - walker::{Hint, HintMeta}, + walker::hint::{Hint, HintMeta}, Visitor, }, }; impl<'ctx> crate::Walk<'ctx> for bool { - type Walker = Walker; -} - -pub struct Walker(bool); + type Walker<E: Effect<'ctx>> = Walker<E>; -impl<'ctx> From<bool> for Walker { - fn from(value: bool) -> Self { - Self(value) + fn into_walker<E: Effect<'ctx>>(self) -> Self::Walker<E> { + Walker(self, PhantomData) } } -impl<'ctx> crate::Walker<'ctx> for Walker { - type Effect = SyncEffect; +pub struct Walker<E>(bool, PhantomData<fn() -> E>); + +impl<'ctx> crate::WalkerTypes<'ctx> for bool { + type Error = (); + + type Output = (); +} +impl<'ctx, E: Effect<'ctx>> crate::WalkerTypes<'ctx> for Walker<E> { type Error = (); type Output = (); +} +impl<'ctx, E: Effect<'ctx>> crate::Walker<'ctx> for Walker<E> { + type Effect = E; #[inline] fn walk<'a>( self, - visitor: Visitor<'a, 'ctx, SyncEffect>, - ) -> Yield<'a, 'ctx, Result<Self::Output, Self::Error>, Self::Effect> + visitor: Visitor<'a, 'ctx>, + ) -> Future<'a, 'ctx, Result<Self::Output, Self::Error>, E> where 'ctx: 'a, { - { + E::wrap(async move { if let Some(object) = - visitor.upcast_mut::<dyn Value<'_, '_, OwnedStatic<bool>, SyncEffect> + '_>() + visitor.upcast_mut::<dyn Value<'_, 'ctx, OwnedStatic<bool>, E> + '_>() { - object.visit(OwnedStatic(self.0)); + object.visit(OwnedStatic(self.0)).await; } Ok(()) - } + }) } } diff --git a/tests/hook.rs b/tests/hook.rs index 9dacb62..ebdf728 100644 --- a/tests/hook.rs +++ b/tests/hook.rs @@ -1,69 +1,72 @@ -use std::{ - future::Future, marker::PhantomData, ops::ControlFlow, pin::Pin, thread::yield_now, - time::Duration, -}; +use std::{marker::PhantomData, ops::ControlFlow, pin::Pin, thread::yield_now, time::Duration}; use treaty::{ any::{any_trait, static_wrapper::OwnedStatic, AnyTrait, IndirectLtAny, LtTypeId}, - build_with, - effect::{any_t, as_obj, AsObj, AsyncEffect, Effect, EffectAnyTrait, SyncEffect, Yield}, - into_walker, - protocol::{visitor::Value, Visitor}, - Build, Builder, Walker, + effect::{BlockOn, Blocking, Effect, Future, Spin}, + protocol::visitor::value::Value, + protocol::Visitor, + transform, Build, Builder, Walk, Walker, builders::core::option::IgnoreMissing, WalkerTypes, }; #[test] fn demo() { - let hook = Hook { - inner: into_walker(true), + let hook = Hook::<_, Blocking> { + inner: true.into_walker::<Blocking>(), _marker: PhantomData, }; // let x = build_with::<<bool as Build<_>>::Builder, _>(hook).unwrap(); // dbg!(x); - let x = build_with::<<Option<bool> as Build<_>>::Builder, _>(hook).unwrap(); + // let x = Spin::block_on(transform::<<Option<bool> as Build>::Builder<_>, _, Blocking>(IgnoreMissing::No, hook)); + let x = Spin::block_on(transform::<<bool as Build>::Builder<_>, _, Blocking>((), hook)); dbg!(x); todo!(); } #[no_mangle] fn invert(x: bool) -> bool { - let hook = Hook { - inner: into_walker(x), + let hook = Hook::<_, Blocking> { + inner: x.into_walker::<Blocking>(), _marker: PhantomData, }; - build_with::<<bool as Build<_>>::Builder, _>(hook).unwrap() + Spin::block_on(transform::<<bool as Build>::Builder<_>, _, Blocking>( + (), + hook, + )) + .0 + .unwrap() } -struct Hook<T, Effect> { +struct Hook<T, E> { inner: T, - _marker: PhantomData<fn() -> Effect>, + _marker: PhantomData<fn() -> E>, } -struct VisitorHook<'a, 'ctx: 'a, E: EffectAnyTrait<'ctx>> { - inner: as_obj::T<'a, 'ctx, E::AnyTrait>, +struct VisitorHook<'a, 'ctx: 'a, E> { + inner: Visitor<'a, 'ctx>, + _marker: PhantomData<fn() -> E>, } -impl<'ctx, T: Walker<'ctx, Effect = AsyncEffect> + Send> Walker<'ctx> for Hook<T, AsyncEffect> -where - <T as Walker<'ctx>>::Error: Send, - <T as Walker<'ctx>>::Output: Send, -{ - type Effect = T::Effect; - +impl<'ctx, T: Walker<'ctx, Effect = E>, E: Effect<'ctx>> WalkerTypes<'ctx> for Hook<T, E> { type Error = T::Error; type Output = T::Output; +} + +impl<'ctx, T: Walker<'ctx, Effect = E>, E: Effect<'ctx>> Walker<'ctx> for Hook<T, E> { + type Effect = E; fn walk<'a>( self, - visitor: Visitor<'a, 'ctx, T::Effect>, - ) -> Yield<'a, 'ctx, Result<Self::Output, Self::Error>, Self::Effect> + visitor: Visitor<'a, 'ctx>, + ) -> Future<'a, 'ctx, Result<Self::Output, Self::Error>, E> where Self: 'a, - 'ctx: 'a, { - Box::pin(async move { - let mut visitor = VisitorHook::<Self::Effect> { inner: visitor }; + E::wrap(async { + let mut visitor = VisitorHook::<E> { + inner: visitor, + _marker: PhantomData, + }; let flow = self.inner.walk(&mut visitor); @@ -72,30 +75,7 @@ where } } -impl<'ctx, T: Walker<'ctx, Effect = SyncEffect>> Walker<'ctx> for Hook<T, SyncEffect> { - type Effect = T::Effect; - - type Error = T::Error; - - type Output = T::Output; - - fn walk<'a>( - self, - visitor: Visitor<'a, 'ctx, T::Effect>, - ) -> Yield<'a, 'ctx, Result<Self::Output, Self::Error>, Self::Effect> - where - Self: 'a, - 'ctx: 'a, - { - let mut visitor = VisitorHook::<Self::Effect> { inner: visitor }; - let flow = self.inner.walk(&mut visitor); - flow - } -} - -impl<'b, 'ctx: 'b, E: Effect<'ctx, ControlFlow<(), ()>>> AnyTrait<'ctx> - for VisitorHook<'b, 'ctx, E> -{ +impl<'b, 'ctx: 'b, E: Effect<'ctx>> AnyTrait<'ctx> for VisitorHook<'b, 'ctx, E> { fn upcast_to_id<'a>( &'a self, id: treaty::any::LtTypeId<'ctx>, @@ -104,7 +84,7 @@ impl<'b, 'ctx: 'b, E: Effect<'ctx, ControlFlow<(), ()>>> AnyTrait<'ctx> 'ctx: 'a, { match id { - id => self.inner.as_obj().upcast_to_id(id), + id => self.inner.upcast_to_id(id), } } @@ -117,34 +97,32 @@ impl<'b, 'ctx: 'b, E: Effect<'ctx, ControlFlow<(), ()>>> AnyTrait<'ctx> 'ctx: 'a, { match id { - id if id == LtTypeId::of::<dyn Value<'_, 'ctx, OwnedStatic<bool>, E> + 'a>() => { - if self.inner.as_obj_mut().upcast_to_id_mut(id).is_some() { + id if id == LtTypeId::of::<dyn Value<'a, 'ctx, OwnedStatic<bool>, E> + 'a>() => { + // println!("hook: {:?}", id); + if self.inner.upcast_to_id_mut(id).is_some() { Some(IndirectLtAny::<'a, 'ctx, _>::new::< - dyn Value<'_, 'ctx, OwnedStatic<bool>, E> + 'a, + dyn Value<'a, 'ctx, OwnedStatic<bool>, E> + 'a, >(self as _)) } else { None } } - id => self.inner.as_obj_mut().upcast_to_id_mut(id), + id => { + // println!("fallback: {:?}", id); + self.inner.upcast_to_id_mut(id) + }, } } } -impl<'a, 'b, 'ctx: 'b + 'a, E: Effect<'ctx, ControlFlow<(), ()>>> Value<'a, 'ctx, OwnedStatic<bool>, E> - for VisitorHook<'b, 'ctx, E> -{ +impl<'a, 'b, 'ctx: 'a + 'b, E: Effect<'ctx>> Value<'a, 'ctx, OwnedStatic<bool>, E> for VisitorHook<'b, 'ctx, E> { #[inline] fn visit( &'a mut self, OwnedStatic(value): OwnedStatic<bool>, - ) -> Yield<'a, 'ctx, ControlFlow<(), ()>, E> - where - 'ctx: 'a, - { + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, E> { let visitor = self .inner - .as_obj_mut() .upcast_mut::<dyn Value<'a, 'ctx, OwnedStatic<bool>, E> + 'a>() .unwrap(); |