generic_std/
plug.rs

1//! Implementation of higher-kinded types in Rust using associated types.
2//!
3//! This is a variation of
4//! [Edmund Smith's](https://gist.github.com/edmundsmith/855fcf0cb35dd467c29a9350481f0ecf)
5//! method where instead of unplugging and plugging generic arguments between
6//! fully defined types (i.e. `Vec<X>` <-> `Vec<Y>`), higher-kinded types are
7//! represented as structs that implement either `PlugLifetime` or
8//! `PlugType`. We refer to these structs as *HKT forms*. To be explicit,
9//! sometimes we refer to types that are not HKT forms as *concrete types* or
10//! `H0` types.
11//!
12//! For example, `H1Vec`, the higher-kinded form of `Vec`, implements
13//! `PlugType`. Then, to get the concrete `Vec<T>` for a type `T`:
14//!
15//! ```text
16//! <H1Vec as PlugType<T>>::T
17//! ```
18//!
19//! # Conventions for HTK Forms
20//!
21//! As a convention, all HKT forms must be zero-sized structs, only implement
22//! `PlugLifetime` or `PlugType` and respect the following naming convention:
23//!
24//! ```text
25//! H<n><t>
26//! ```
27//!
28//! Where `<n>` is the number of lifetype + type arguments left to be filled,
29//! also referred to as slots, and `<t>` is the name of the concrete type. For
30//! example, `Cow` has two HKT forms:
31//!
32//! - `H2Cow` which implements `PlugLifetime`, yielding `H1Cow<'a>`
33//! - `H1Cow<'a>` which implements `PlugType`, yielding a concrete `Cow<'a, T>`
34//!
35//! The generic arguments are always filled from left to right, lifetimes
36//! first. In some cases it might be useful to plug those out of order. In
37//! those cases we prepend something descriptive to the type name. See for
38//! example [`TypedH1Reference`](../reference/struct.TypedH1Reference.html).
39//!
40//! # HKT-Compatible Concrete Types
41//!
42//! The `PlugLifetime` and `PlugType` may also be implemented for concrete
43//! types, in which case `Type` is just itself. This is useful to implement
44//! streaming iterators and similar constructs. [`H0`](struct.H0.html) is a
45//! type wrapper for exactly this case.
46
47use std::marker::PhantomData;
48
49/// Trait enabling a lifetime to plugged to HKT forms.
50pub trait PlugLifetime<'a> {
51    /// The resulting type after plugging the lifetime parameter `'a`.
52    type T;
53}
54
55/// Trait enabling a type to be plugged to HKT forms.
56pub trait PlugType<T>
57where
58    T: ?Sized,
59{
60    /// The resulting type after plugging the type parameter `T`.
61    type T;
62}
63
64/// Type-level wrapper that yields `T` unmodified when `PlugLifetime` or
65/// `PlugType` are applied.
66pub struct H0<T>(PhantomData<T>);
67
68impl<'dummy, T> PlugLifetime<'dummy> for H0<T> {
69    type T = T;
70}
71
72impl<Dummy, T> PlugType<Dummy> for H0<T> {
73    type T = T;
74}