Updated to use the new effects
Konnor Andrews 2024-04-07
parent e9679b9 · commit f250905
-rw-r--r--Cargo.lock105
-rw-r--r--Cargo.toml1
-rw-r--r--src/any.rs4
-rw-r--r--src/build.rs120
-rw-r--r--src/build/builders.rs4
-rw-r--r--src/build/builders/core.rs3
-rw-r--r--src/build/builders/core/bool.rs66
-rw-r--r--src/build/builders/core/option.rs264
-rw-r--r--src/effect.rs199
-rw-r--r--src/hkt.rs134
-rw-r--r--src/lib.rs3
-rw-r--r--src/protocol.rs22
-rw-r--r--src/protocol/visitor.rs13
-rw-r--r--src/protocol/visitor/request_hint.rs10
-rw-r--r--src/protocol/visitor/sequence.rs33
-rw-r--r--src/protocol/visitor/tagged.rs39
-rw-r--r--src/protocol/visitor/value.rs161
-rw-r--r--src/protocol/walker.rs4
-rw-r--r--src/protocol/walker/hint.rs75
-rw-r--r--src/transform.rs44
-rw-r--r--src/walk.rs36
-rw-r--r--src/walk/walkers/core.rs2
-rw-r--r--src/walk/walkers/core/bool.rs44
-rw-r--r--tests/hook.rs114
24 files changed, 708 insertions, 792 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 6acb13a..1b0bfc2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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",
diff --git a/Cargo.toml b/Cargo.toml
index cb45b3d..09cb979 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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]
diff --git a/src/any.rs b/src/any.rs
index e45ec8b..9bddfda 100644
--- a/src/any.rs
+++ b/src/any.rs
@@ -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
+ }
}
diff --git a/src/hkt.rs b/src/hkt.rs
index 8a7a48c..466d358 100644
--- a/src/hkt.rs
+++ b/src/hkt.rs
@@ -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);
}
}
}
diff --git a/src/lib.rs b/src/lib.rs
index fd78f63..fd458fa 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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();