| -rw-r--r-- | src/any.rs | 4 | ||||
| -rw-r--r-- | src/hkt.rs | 91 | ||||
| -rw-r--r-- | src/lib.rs | 1 | ||||
| -rw-r--r-- | src/protocol.rs | 12 | ||||
| -rw-r--r-- | src/protocol/walker/hint.rs | 4 |
5 files changed, 108 insertions, 4 deletions
@@ -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); + } + } +} @@ -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. /// |