Expand description
Core traits and types for type-level reification and reflection in Rust.
This is the foundation crate. It defines:
Reflect: a trait for types that carry a compile-time value, withreflect()extracting that value at runtime.reify: a function that takes any runtime value and lifts it into a scoped type-level context, where it is available through aReifiedtoken branded with an invariant lifetime that cannot escape the callback.RuntimeValue: a small, structural enum used as the standard payload type forReflectimplementations across the workspace.
Everything is fully safe (#![deny(unsafe_code)]), with scoping
enforced by the borrow checker.
§When should I use this crate?
- You’re writing a library where types encode values (Peano numbers,
type-level flags, dimensional units, etc.) and want a uniform way to
surface those values at runtime: implement
Reflectfor them. - You want a Haskell-
reflection-style scoping primitive in Rust: usereifyto thread a runtime value into a callback as if it were a compile-time fact. - You’re writing a downstream crate (such as
reflect-natorreflect-derive) that producesReflectimplementations: depend on this crate for the trait and theRuntimeValuevocabulary.
§The reification / reflection pattern
This implements the pattern from Kiselyov & Shan’s Functional Pearl:
Implicit Configurations, popularized by Kmett’s Haskell reflection
library, adapted to Rust with branded lifetimes for scoping safety.
In Haskell:
reify :: a -> (forall s. Reifies s a => Proxy s -> r) -> r
reflect :: Reifies s a => proxy s -> aIn Rust, the forall s is modeled by an invariant lifetime 'brand
on Reified. The higher-rank bound for<'brand> on the callback
ensures the token cannot escape, just as Haskell’s rank-2 type
prevents s from escaping.
Unlike Haskell’s reflection library (which uses unsafeCoerce to
fabricate typeclass dictionaries from GHC internals), this
implementation is safe all the way down: no unsafe code, no
compiler-internal assumptions. Scoping is enforced mechanically by
the borrow checker.
§Examples
Lift a runtime value into a scoped type-level context:
use reify_reflect_core::reify;
let result = reify(&42i32, |token| {
let val: &i32 = token.reflect();
*val + 1
});
assert_eq!(result, 43);Implement Reflect for a type that carries a compile-time value:
use reify_reflect_core::{Reflect, RuntimeValue};
struct Pi;
impl Reflect for Pi {
type Value = RuntimeValue;
fn reflect() -> Self::Value {
RuntimeValue::Nat(3) // close enough
}
}
assert_eq!(Pi::reflect(), RuntimeValue::Nat(3));See also: reflect-nat for ready-made
Reflect implementations on Peano naturals, booleans, and HLists,
and reflect-derive for
#[derive(Reflect)] on user types.
Structs§
- Reified
- A branded token carrying a reified value.
Enums§
- Runtime
Value - Runtime representation of type-level values.
Traits§
- Reflect
- Converts a type-level value into a runtime value.
Functions§
- reify
- Reify a runtime value into a scoped type-level context.