tylift
Lift enum variants to the type-level simply by adding the attribute tylift
. This comes in handy for type-level programming.
Important note: This library provides mechanisms nearly identical to the experimental feature const generics/min const genercis which has not been fully implemented yet. See the respective section below for more information.
The attribute promotes enum variants to their own types. The enum type becomes a kind – the type of a type – emulated by a trait, replacing the original type declaration. In Rust, the syntax of trait bounds (:
) beautifully mirror the syntax of type annotations. Thus, the snippet B: Bool
can also be read as "type parameter B
of kind Bool
".
Traits representing kinds are sealed, which means nobody is able to add new types to the kind. Variants can hold (unnamed) fields of types of a given kind. Attributes (notably documentation comments) applied to the item itself and its variants will be preserved. Expanded code works in #![no_std]
-environments.
As of right now, there is no automated way to reify the lifted variants (i.e. map them to their term-level counterpart). Lifted enum types can not be generic over kinds.
First Example
use tylift;
use PhantomData;
Installation
Add these lines to your Cargo.toml
:
[]
= "0.3.5"
Compatibility with older rustc
versions is currently not verified. Older versions of this crate (≤ 0.3.2) only
relied on features of rustc
1.32. So you might want to check them out.
Cargo Features
The feature-flag span_errors
drastically improves error messages by taking advantage of the span information of a token. It uses the experimental feature proc_macro_diagnostic
and thus requires a nightly rustc
.
More Examples
Code before the macro expansion:
use tylift;
pub
// put all 3 items into the module `Power`
// put all 3 items into the module `direction`
pub
And after expansion below. It's partially hygienic; generated identifiers which are unhygienic because of current limitations of the proc_macro
API are prefixed with double underscores (__
) to lower the change of name collisions.
use tylift;
pub use *;
pub use *;
use *;
pub
Manually Writing a Type-Level Function
Type-level function Not
from kind Bool
to Bool
(kind defined in previous section):
type Not<B> = Result;
Type-level function Add
from two Nat
s to Nat
(kind defined in previous section):
type Add<N, M> = Result;
tylift Versus Const Generics
Advantages of this crate over const generics:
- recursive kinds which cannot be represented with const generics right now. The latter would also require explicit boxing
- compatibility with older rust versions
Obviously, these are not that convincing arguments. Consider this crate as a study rather than something of value. Maybe you can learn from its code.
Disadvantages:
- requires an additional dependency (
tylift
) with a heavy transitive dependency onsyn
- worse tooling
- atrociously hairy type-level functions compared to
const fn
s which are compatible with const generics, see const evaluatable checked
Future Plans
- replacing the introductery example with something more reasonable
- creating tests
- adding additional features like
- an attribute to lift functions to type-level ones
- generating reification functions
- removing the feature-gate
span_errors
onceproc_macro_diagnostic
becomes stable