// 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);
}
}
}