reify-reflect-core 0.1.1

Core Reflect/Reify traits and RuntimeValue types
Documentation
  • Coverage
  • 100%
    12 out of 12 items documented6 out of 7 items with examples
  • Size
  • Source code size: 13.44 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 1.89 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 1m 36s Average build duration of successful builds.
  • all releases: 1m 9s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • Homepage
  • joshburgess/reify-reflect
    1 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • joshburgess

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, with reflect() 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 a [Reified] token branded with an invariant lifetime that cannot escape the callback.
  • [RuntimeValue]: a small, structural enum used as the standard payload type for [Reflect] implementations 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 [Reflect] for them.
  • You want a Haskell-reflection-style scoping primitive in Rust: use [reify] to thread a runtime value into a callback as if it were a compile-time fact.
  • You're writing a downstream crate (such as reflect-nat or reflect-derive) that produces [Reflect] implementations: depend on this crate for the trait and the [RuntimeValue] vocabulary.

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 -> a

In 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.