const-reify 0.1.0

Safe runtime-to-const-generic dispatch via match tables
Documentation
# const-reify Design Document

## Overview

`const-reify` provides a runtime-to-const-generic bridge: given a runtime `u64`
value, it dispatches to a monomorphized function parameterized by a const generic
matching that value. This enables "reification" — lifting runtime data into the
type system.

## Approach

Rather than vtable fabrication (which is fragile and relies on undocumented
compiler internals), we use a **match-table dispatch** strategy:

1. Pre-monomorphize a trait impl for `Modular<N>` for `N` in `0..=255`.
2. At runtime, match the provided `u64` against this table and dispatch to the
   correct monomorphization.
3. The dispatch is generated by a macro to avoid writing 256 match arms by hand.

This approach is:
- **Sound**: No transmute, no raw pointer arithmetic, no vtable assumptions.
- **Portable**: Works on any Rust compiler that supports const generics (stable since 1.51).
- **Predictable**: The monomorphization cost is bounded and explicit.

## Why Not Vtable Fabrication?

The original plan called for inspecting and fabricating vtables at runtime.
This approach has severe drawbacks:

1. **Vtable layout is not stabilized.** Rustc makes no guarantees about vtable
   structure, entry ordering, or even whether vtables exist in the expected form.
   Different optimization levels, LTO settings, and compiler versions can change
   the layout.

2. **Transmuting vtable pointers is instant UB.** Creating a trait object from
   fabricated pointers violates Rust's aliasing and provenance rules.

3. **No mitigation is reliable.** Compile-time assertions can detect *some*
   layout changes, but cannot guarantee soundness. A passing assertion today
   does not prevent UB tomorrow.

The match-table approach achieves the same user-facing API with zero unsafe code
in the dispatch path.

## Rustc Version Compatibility

- **Minimum:** Rust 1.75.0 (MSRV of the workspace)
- **Tested on:** Current stable (1.94.0)
- **Const generics:** Stabilized since Rust 1.51.0 for primitive types

No compiler-internal assumptions are made. This crate should work on any
stable Rust >= 1.51.

## Threat Model

| Threat | Risk | Mitigation |
|--------|------|------------|
| Compiler changes vtable layout | N/A | We don't use vtables |
| Monomorphization explosion | Low | Bounded to 256 variants |
| Value out of supported range | Low | Runtime panic with clear message |
| Const generic type mismatch | None | Enforced by trait bounds |

## Supported Range

Initial implementation: `u64` values in `0..=255`.

This keeps compile times reasonable (256 monomorphizations). The range can be
extended in the future by:
- Increasing the match table (linear compile-time cost)
- Using a two-level dispatch (high byte + low byte) for larger ranges
- Using build-script-generated dispatch tables

## API Surface

```rust
// The core trait
pub trait HasModulus {
    fn modulus(&self) -> u64;
}

// Auto-implemented for Modular<N>
pub struct Modular<const N: u64>;

// Safe dispatch
pub fn reify_const<F, R>(val: u64, f: F) -> R
where
    F: FnOnce(&dyn HasModulus) -> R;

// Convenience macro
reify!(42u64 as Modular, |m: &dyn HasModulus| {
    println!("modulus = {}", m.modulus());
});
```

## Unsafe Code Policy

This crate was originally designated as the "unsafe core" of the workspace.
However, the match-table approach eliminates the need for unsafe code entirely.
The crate now uses `#![deny(unsafe_code)]` like all other crates in the
workspace, except for the test harness in `tests/vtable_inspection.rs` which
documents vtable layout for educational purposes only.