added hkt module
Konnor Andrews 2024-03-17
parent d0f31f2 · commit 4c065b4
-rw-r--r--src/any.rs4
-rw-r--r--src/hkt.rs91
-rw-r--r--src/lib.rs1
-rw-r--r--src/protocol.rs12
-rw-r--r--src/protocol/walker/hint.rs4
5 files changed, 108 insertions, 4 deletions
diff --git a/src/any.rs b/src/any.rs
index b069043..e45ec8b 100644
--- a/src/any.rs
+++ b/src/any.rs
@@ -648,7 +648,7 @@ mod test {
any_trait! {
impl['a, 'ctx, T: Clone] X<T> = [
dyn Z + 'a
- ];
+ ]
}
}
@@ -674,7 +674,7 @@ mod test {
any_trait! {
impl['a, 'ctx] X = [
dyn Z + 'a
- ];
+ ]
}
let x = X(42);
diff --git a/src/hkt.rs b/src/hkt.rs
new file mode 100644
index 0000000..d41a7ae
--- /dev/null
+++ b/src/hkt.rs
@@ -0,0 +1,91 @@
+// Lifetime bound to be used in `for<'lt>` blocks.
+pub type Bound<'lt, 'bound> = &'lt &'bound ();
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! type_class {
+ (for<$lt:lifetime, $ctx:lifetime> $vis:vis $name:ident $(: $($bound:tt)*)?) => {
+ $vis mod $name {
+ use super::*;
+
+ pub trait ForLt<$lt, $ctx: $lt, B> {
+ type T: $($($bound)*)?;
+ }
+
+ pub trait Hkt<$ctx>: for<$lt> ForLt<$lt, $ctx, $crate::hkt::Bound<$lt, $ctx>> {}
+
+ impl<$ctx, T> Hkt<$ctx> for T
+ where
+ T: for<$lt> ForLt<$lt, $ctx, $crate::hkt::Bound<$lt, $ctx>>
+ {}
+
+ pub type T<$lt, $ctx, H> = <H as ForLt<$lt, $ctx, $crate::hkt::Bound<$lt, $ctx>>>::T;
+ }
+ };
+}
+
+#[doc(inline)]
+pub use type_class;
+
+#[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)*
+ ) => {
+ $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)*)?
+ {
+ type T = $($type)*;
+ }
+ }
+}
+
+#[doc(inline)]
+pub use hkt;
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ trait Demo<'lt, 'ctx> {
+ fn add(&self, x: &'lt &'ctx i32) -> i32;
+ }
+
+ impl<'lt, 'ctx> Demo<'lt, 'ctx> 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) {
+ fn add(&self, x: &'lt &'ctx i32) -> i32 {
+ (**self).add(x)
+ }
+ }
+
+ type_class!(for<'lt, 'ctx> any_t: Demo<'lt, 'ctx>);
+
+ hkt!((any_t): for<'lt, 'ctx> X => &'lt (dyn Demo<'lt, 'ctx> + 'lt));
+
+ fn demo<'lt, 'ctx, T: any_t::Hkt<'ctx>>(x: any_t::T<'lt, 'ctx, T>, y: &'lt &'ctx i32) {
+ assert_eq!(x.add(y), 10);
+ }
+
+ #[test]
+ fn can_use_hkt() {
+ let ctx = 2;
+ let ctx = &ctx;
+
+ {
+ let local = &ctx;
+ let z: &dyn Demo<'_, '_> = &8i32;
+ demo::<X<'_>>(z, local);
+ }
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 26e1bc6..f76bf33 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -11,6 +11,7 @@ pub mod any;
// mod build;
pub mod protocol;
pub mod symbol;
+pub mod hkt;
// mod walk;
// pub mod impls;
diff --git a/src/protocol.rs b/src/protocol.rs
index fccb8ed..c4a7f7a 100644
--- a/src/protocol.rs
+++ b/src/protocol.rs
@@ -159,6 +159,18 @@ impl<'ctx, C, B> Effect<'ctx, C, B> for SyncEffect {
type WalkerHkt = AnyTraitSendObjHkt<'ctx>;
}
+macro_rules! hkt {
+ (for<$lt:lifetime bound by $bound:lifetime> $name:ident$([$($generic:tt)*])? = $($type:tt)*) => {
+ pub struct $name<$bound $(, $($generic)*)?>(core::marker::PhantomData<fn() -> (&$bound () $(, $($generic)*)?)>);
+
+ impl<$lt, $bound $(, $($generic)*)?> crate::protocol::ForLt<$lt, $bound, Bound<$lt, $bound>> for $name<$bound $(, $($generic)*)?> {
+ type T = $($type)*;
+ }
+ }
+}
+
+hkt!(for<'a bound by 'ctx> Demo = &'a &'ctx ());
+
#[cfg(feature = "alloc")]
pub struct AsyncControlFlowHkt<'ctx, C, B>(PhantomData<fn() -> (&'ctx (), C, B)>);
diff --git a/src/protocol/walker/hint.rs b/src/protocol/walker/hint.rs
index 57eaa1a..06c8794 100644
--- a/src/protocol/walker/hint.rs
+++ b/src/protocol/walker/hint.rs
@@ -25,9 +25,9 @@ pub trait HintMeta<'a, 'ctx: 'a> {
}
/// Object implementing the [`Hint`] protocol.
-pub trait Hint<'ctx, Protocol: ?Sized + for<'a> HintMeta<'a, 'ctx>, E = SyncEffect>
+pub trait Hint<'ctx, Protocol: ?Sized + for<'a> HintMeta<'a, 'ctx>, E = SyncEffect>
where
- E: Effect<'ctx> + Effect<'ctx, <Protocol as HintMeta<'a, 'ctx>>::Known>,
+ E: Effect<'ctx> + Effect<'ctx, <Protocol as HintMeta<'a, 'ctx>>::Known>
{
/// Hint to the walker to use the `P` protocol.
///