Available on advanced only.
Expand description

Niche and advanced, you can ignore this to begin with. Module for type-equality hacks.

In certain scenarios, you may have a T : ForLt in scope which you want to constrain to match some specific type when fed some specific lifetime; e.g.

//! pseudo-code
<'r, T : ForLt>
where
    T::Of<'r> = &'r str

In that case, you can actually just write the corresponding real code:

fn f<'s, T : ForLt>(s: &'s str)
where
    T : ForLt<Of<'s> = &'s str>,
{
    let _: T::Of<'s> = s;
}

which does work 🙂.

It even works with higher-order lifetimes!

fn f<T : ForLt>(s: String)
where
    T : for<'local> ForLt<Of<'local> = &'local str>,
{
    let _local: T::Of<'_> = &s;
}

But in other more contrived situations, potentially outside of HKTs altogether, these type equality bounds may be unusable or buggy.

In that case, the workaround is to replace type equality constraints, with good old trait bounds, but with a trait designed so as to nonetheless signify type equality:

Hence the trait Is. Alas, it does come with some caveats, since when

T : Is<EqTo = U>,

Rust will nonetheless still be treating T and U as distinct types.

Which is why this module provides helper cast_right() and cast_left() functions:

use ::higher_kinded_types::{ForLt, type_eq::{self, Is}};

fn f<'a, T : ForLt>(a: &'a str)
where
    T::Of<'a> : Is<EqTo = &'a str>,
{
    let _: T::Of<'a> = type_eq::cast_left::<T::Of<'a>>(a);
}

But perhaps more interestingly, cast_right() and cast_left() are unable to handle types depending on T, such as Vec<T> vs. Vec<U>.

That’s when we’d like to use “generic-over-a-type generics”, that is, type GATs!

…ish: while they’re not fully supported (no ergonomic instantiation), it can be intellectually interesting to notice that once we let go of ergonomics, there can be actual usages of type “HKTs” GATs.

See, for instance, cast_wrapper_right and its documentation example.

Traits

Functions