//! 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 [`bijective_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 [`bijective_higher_ranked_trait!`] macro cgenerates a trait that can be used with
//! [`bijective_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.
#[derive(Debug, Default, Copy, Clone)]
#[repr(transparent)]
pub struct Invariant<'a>(PhantomData<fn(&'a ()) -> &'a ()>);
#[repr(transparent)]
pub struct Marker<T>(PhantomData<fn() -> T>);
impl<T> Copy for Marker<T> {}
impl<T> Clone for Marker<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> core::fmt::Debug for Marker<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("Marker").finish()
}
}
impl<T> Default for Marker<T> {
fn default() -> Self {
Self(PhantomData)
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! bijective_higher_ranked_trait {
{
$(#[$($meta:tt)*])*
$vis:vis type class $name:ident[
$($lifetimes:lifetime),*
][
$($generic:ident),*
]: $({$($self_provides:tt)*})? [for<$lt:lifetime> $($($provides:tt)+)?]
$(where {
$($bound:tt)*
})?
$(for where {
$($for_bound:tt)*
})?
} => {
$(#[$($meta)*])*
$vis mod $name {
#![allow(unused, non_snake_case)]
use super::*;
/// Trait for lowering a higher ranked type to a lower type.
///
/// Do not use this trait directly instead use the [`MemberType`] trait and [`T`]
/// type alias.
///
/// This acts to inject a lifetime into the higher ranked type to make it concrete.
pub trait LowerForLt<
$lt,
$($lifetimes: $lt,)*
B: $lt,
$($generic: $lt),*
>
$(: $($self_provides)*)?
where
$($($bound)*)?
$($($for_bound)*)?
{
/// The lower type for this higher ranked type.
///
/// The lower type must live for a minimum of the injected lifetime.
///
/// Note this type must be raisable back to the same higher ranked type to make
/// this a bijective mapping.
type T: ?Sized + RaiseForLt<
$lt,
$($lifetimes,)*
&$lt ($(&$lifetimes (),)* $(*const $generic,)*),
$($generic,)*
HigherRanked = Self
> $(+ $($provides)+)? + $lt;
}
/// Trait for raising a lower type to it's higher ranked form.
///
/// Do not use this trait directly instead use the [`LowerType`] trait and [`HigherRanked`]
/// type alias.
///
/// this acts to remove a lifetime from the lower type.
pub trait RaiseForLt<$lt, $($lifetimes: $lt,)* B: $lt, $($generic: $lt),*>
where
$($($bound)*)?
$($($for_bound)*)?
{
/// The higher ranked type for this lower type.
///
/// Note this type must be lowerable back to the same lower type to make
/// this a bijective mapping.
type HigherRanked: ?Sized + LowerForLt<
$lt,
$($lifetimes,)*
&$lt ($(&$lifetimes (),)* $(*const $generic,)*),
$($generic,)*
T = Self
> $(+ $lifetimes)*;
}
/// Trait for higher ranked types of this form.
///
/// A higher ranked type can have a lifetime injected to form a lower type.
/// To perform this operation use the [`T`] type alias.
///
/// This is basically a trait alias for the bound `for<'a> LowerForLt<'a, ...>`.
pub trait MemberType<$($lifetimes,)* $($generic),*>:
for<$lt> LowerForLt<
$lt,
$($lifetimes,)*
// Use a implied bound to make sure the lifetime from the for syntax is
// correctly bounded.
&$lt ($(&$lifetimes (),)* $(*const $generic,)*),
$($generic),*
>
where
$($($bound)*)?
{}
// Impl the higher ranked trait for all higher ranked types with the ability to lower.
impl<
$($lifetimes,)*
__: ?Sized,
$($generic),*
> MemberType<$($lifetimes,)* $($generic),*> for __
where
__: for<$lt> LowerForLt<
$lt,
$($lifetimes,)*
&$lt ($(&$lifetimes (),)* $(*const $generic,)*),
$($generic),*
>,
$($($bound)*)?
{}
/// Inject a lifetime into a higher ranked type to form its lower type.
pub type T<$lt, $($lifetimes,)* __, $($generic),*> =
<__ as LowerForLt<
$lt,
$($lifetimes,)*
&$lt ($(&$lifetimes (),)* $(*const $generic,)*),
$($generic),*
>>::T;
/// Trait for lower types with a higher ranked form.
///
/// A lower type can have a lifetime removed to form a higher ranked type.
/// To perform this operation use the [`HigherRanked`] type alias.
///
/// This is basically a trait alias for the bound `RaiseForLt<'a, ...>`.
pub trait LowerType<
$lt,
$($lifetimes: $lt,)*
$($generic: $lt),*
>: RaiseForLt<
$lt,
$($lifetimes,)*
&$lt ($(&$lifetimes (),)* $(*const $generic,)*),
$($generic),*
> $(+ $($provides)+)?
where
$($($bound)*)?
{}
// Impl the lower type trait for all lower types with the ability to raise.
impl<
$lt,
$($lifetimes: $lt,)*
__: ?Sized,
$($generic: $lt),*
> LowerType<$lt, $($lifetimes,)* $($generic),*> for __
where
__: RaiseForLt<
$lt,
$($lifetimes,)*
&$lt ($(&$lifetimes (),)* $(*const $generic,)*),
$($generic),*
> $(+ $($provides)+)?,
$($($bound)*)?
{}
/// Remove a lifetime into a lower type to form its higher ranked type.
pub type HigherRanked<$lt, $($lifetimes,)* __, $($generic),*> =
<__ as RaiseForLt<
$lt,
$($lifetimes,)*
&$lt ($(&$lifetimes (),)* $(*const $generic,)*),
$($generic),*
>>::HigherRanked;
}
};
}
use core::marker::PhantomData;
#[doc(inline)]
pub use bijective_higher_ranked_trait;
/// Generate a higher-ranked type.
#[doc(hidden)]
#[macro_export]
macro_rules! bijective_higher_ranked_type {
{
$(for[$($extra_lt:lifetime)*])? use $name:ident[
$($ctx:lifetime),*
][
$($generic:ident),*
]$([
$($forwarding_generic:ident[$($forward_lt:lifetime),*][$($forward_generic:ident),*]),*
])?: $type_class:ident[$($type_class_lifetime:lifetime)*][$($type_class_generic:ident)*]
for<$lt:lifetime>
($for_lt_type:ty)
($higher_ranked_type:ty)
$(where {$($bound:tt)*})?
} => {
impl<
$lt,
$($($extra_lt,)*)?
$($ctx,)*
$($generic,)*
$($($forwarding_generic),*)?
> $type_class::LowerForLt<
$lt,
$($type_class_lifetime,)*
&$lt (
$(&$type_class_lifetime (),)*
$(*const $type_class_generic,)*
),
$($type_class_generic),*
> for $name<
$($ctx,)*
$($generic,)*
$($($forwarding_generic),*)?
>
where
$($(
$forwarding_generic: $type_class::LowerForLt<
$lt,
$($forward_lt,)*
&$lt (
$(&$forward_lt (),)*
$(*const $forward_generic,)*
),
$($forward_generic,)*
>,
)*)?
$($($bound)*)?
{
type T = $for_lt_type;
}
impl<
$lt,
$($($extra_lt,)*)?
$($ctx,)*
$($generic,)*
$($($forwarding_generic),*)?
> $type_class::RaiseForLt<
$lt,
$($type_class_lifetime,)*
&$lt (
$(&$type_class_lifetime (),)*
$(*const $type_class_generic,)*
),
$($type_class_generic),*
> for $higher_ranked_type
where
$($(
$forwarding_generic: $type_class::RaiseForLt<
$lt,
$($forward_lt,)*
&$lt (
$(&$forward_lt (),)*
$(*const $forward_generic,)*
),
$($forward_generic,)*
>,
)*)?
$($($bound)*)?
{
type HigherRanked = $name<
$($ctx,)*
$($generic,)*
$($(
<$forwarding_generic as $type_class::RaiseForLt<
$lt,
$($forward_lt,)*
&$lt (
$(&$forward_lt (),)*
$(*const $forward_generic,)*
),
$($forward_generic,)*
>>::HigherRanked
),*)?
>;
}
};
{
$(#[$($meta:tt)*])*
$vis:vis $(for[$($extra_lt:lifetime)*])? type $name:ident[
$($ctx:lifetime),*
][
$($generic:ident),*
]$([
$($forwarding_generic:ident[$($forward_lt:lifetime),*][$($forward_generic:ident),*]),*
])?: $type_class:ident[$($type_class_lifetime:lifetime)*][$($type_class_generic:ident)*]
for<$lt:lifetime>
($for_lt_type:ty)
($higher_ranked_type:ty)
$(where {$($bound:tt)*})?
} => {
$(#[$($meta)*])*
$vis struct $name<
$($ctx,)*
$($generic: ?Sized,)*
$($($forwarding_generic: ?Sized),*)?
>(
core::marker::PhantomData<fn() -> (
$(&$ctx (),)*
$(*const $generic,)*
$($(*const $forwarding_generic,)*)?
)>
);
$crate::hkt::bijective_higher_ranked_type! {
$(for[$($extra_lt)*])? use $name[
$($ctx),*
][
$($generic),*
]$([
$($forwarding_generic[$($forward_lt),*][$($forward_generic),*]),*
])?: $type_class[$($type_class_lifetime)*][$($type_class_generic)*]
for<$lt>
($for_lt_type)
($higher_ranked_type)
$(where {$($bound)*})?
}
};
{
$vis:vis $(for[$($extra_lt:lifetime)*])? type [
$($ctx:lifetime),*
][
$($generic:ident),*
]$([
$($forwarding_generic:ident[$($forward_lt:lifetime),*][$($forward_generic:ident),*]),*
])?: $type_class:ident[$($type_class_lifetime:lifetime)*][$($type_class_generic:ident)*]
for<$lt:lifetime>
($for_lt_type:ty)
$(($higher_ranked_type:ty))?
$(where {$($bound:tt)*})?
} => {
const _: () = {
$crate::hkt::bijective_higher_ranked_type! {
$vis $(for[$($extra_lt)*])? type __HigherRanked[
$($ctx),*
][
$($generic),*
]$([
$($forwarding_generic[$($forward_lt),*][$($forward_generic),*]),*
])?: $type_class[$($type_class_lifetime)*][$($type_class_generic)*]
for<$lt>
($for_lt_type)
$(($higher_ranked_type))?
$(where {$($bound)*})?
}
};
};
{
$(#[$($meta:tt)*])*
$vis:vis $(for[$($extra_lt:lifetime)*])? type $name:ident[
$($ctx:lifetime),*
][
$($generic:ident),*
]$([
$($forwarding_generic:ident[$($forward_lt:lifetime),*][$($forward_generic:ident),*]),*
])?: $type_class:ident[$($type_class_lifetime:lifetime)*][$($type_class_generic:ident)*]
for<$lt:lifetime>
($for_lt_type:ty)
$(where {$($bound:tt)*})?
} => {
$crate::hkt::bijective_higher_ranked_type! {
$(#[$($meta)*])*
$vis $(for[$($extra_lt)*])? type $name[
$($ctx),*
][
$($generic),*
]$([
$($forwarding_generic[$($forward_lt),*][$($forward_generic),*]),*
])?: $type_class[$($type_class_lifetime)*][$($type_class_generic)*]
for<$lt>
($for_lt_type)
($for_lt_type)
$(where {$($bound)*})?
}
};
{
$(for[$($extra_lt:lifetime)*])? use $name:ident[
$($ctx:lifetime),*
][
$($generic:ident),*
]$([
$($forwarding_generic:ident[$($forward_lt:lifetime),*][$($forward_generic:ident),*]),*
])?: $type_class:ident[$($type_class_lifetime:lifetime)*][$($type_class_generic:ident)*]
for<$lt:lifetime>
($for_lt_type:ty)
$(where {$($bound:tt)*})?
} => {
$crate::hkt::bijective_higher_ranked_type! {
$(for[$($extra_lt)*])? use $name[
$($ctx),*
][
$($generic),*
]$([
$($forwarding_generic[$($forward_lt),*][$($forward_generic),*]),*
])?: $type_class[$($type_class_lifetime)*][$($type_class_generic)*]
for<$lt>
($for_lt_type)
($for_lt_type)
$(where {$($bound)*})?
}
}
}
#[doc(inline)]
pub use bijective_higher_ranked_type;
bijective_higher_ranked_trait! {
pub type class AnySizedSend[][]: [for<'lt> Send + Sized]
}
// #[cfg(test)]
// mod test {
// use super::*;
//
// /// 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, T: Send + 'lt> Demo<'lt, 'ctx, T> for i32 {
// fn add(&self, x: &'lt &'ctx i32) -> i32 {
// self + **x
// }
// }
//
// 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)
// }
// }
//
// // Higher-ranked trait that requires the "true" type to implement Demo.
// bijective_higher_ranked_trait! {
// type class Any['ctx, T]: [for<'lt> Demo<'lt, 'ctx, T>]
// where {
// T: Send,
// }
// for where {
// T: '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)
// }
//
// // 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);
// }
//
// #[test]
// fn can_use_hkt() {
// let ctx = 2;
// 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<'_, '_, i32> = &8i32;
// demo::<X<'_, i32>>(z, local);
// }
// }
// }