Advanced Generics and Type-Level Programming

const fn

A const fn is a function or method marked with the const qualifier that can be called both in compile-time const contexts (such as const / static initializers, array lengths, and const { ... } blocks) and at runtime like an ordinary function.

Dual Execution Mode of const fn

Marking a function const fn does not force every call to run at compile time:

  • When called inside a const context (const X: u32 = compute(5); or let x = const { compute(5) };), the compiler evaluates it at compile time.
  • When called in a runtime expression (let x = compute(user_input);), it executes at runtime like a normal fn.
const fn fnv1a_hash(bytes: &[u8]) -> u64 {
    let mut hash: u64 = 0xcbf2_9ce4_8422_2325;
    let mut i = 0;
    while i < bytes.len() {
        hash ^= bytes[i] as u64;
        hash = hash.wrapping_mul(0x0100_0000_01b3);
        i += 1;
    }
    hash
}

// 1. Evaluated at compile time inside a `const` item:
const ROUTE_HEALTH_HASH: u64 = fnv1a_hash(b"/api/health");

fn main() {
    // 2. Evaluated at runtime on dynamic input:
    let dynamic_path = String::from("/api/health");
    let runtime_hash = fnv1a_hash(dynamic_path.as_bytes());

    println!("compile-time hash: {:#018x}", ROUTE_HEALTH_HASH);
    println!("runtime hash:      {:#018x}", runtime_hash);
    println!("matches:           {}", ROUTE_HEALTH_HASH == runtime_hash);
}
compile-time hash: 0x05288ce2d004bc35
runtime hash:      0x05288ce2d004bc35
matches:           true

Capabilities Supported Inside const fn (Current Stable Rust / 2024 Edition)

Modern Rust supports almost all deterministic, allocation-free control flow inside const fn:

Feature Allowed in const fn? Notes
Arithmetic, bitwise, and logical operators Yes Checked for overflow at compile time
if, if let, match, loop, while, while let Yes for x in iter is not yet allowed because IntoIterator::into_iter is a trait method; use while i < slice.len() instead
Local mutable variables and mutable references (&mut T) Yes Full borrow checking inside const fn
Calling other const fn functions and intrinsics Yes Standard library integer, slice, pointer, and Option/Result constructors are const fn
panic!("...") and assert!(...) Yes Halts compilation with custom diagnostic message if reached during CTFE
Floating-point arithmetic (f32, f64) Yes (stabilized in Rust 1.82) Deterministic IEEE 754 operations
&raw const / &raw mut and raw pointer dereferencing Yes Validated by the CTFE Miri engine
Heap allocations (Box::new, Vec::push, String::from) No Dynamic heap allocations cannot yet escape into runtime memory
Trait method calls (T::method()) No Calling methods through generic trait bounds is not yet stable in const fn
I/O, system calls, threads, or FFI (extern "C") No Compile-time evaluation must be deterministic and sandboxed

Why while Loops Replace for Loops in const fn

Because for item in slice desugars to calling the trait method IntoIterator::into_iter and Iterator::next—and trait methods are not yet const—iterating over a slice or array inside a const fn uses an index while loop or slice pattern matching (while let [first, rest @ ..] = slice):

const fn max_in_slice(mut slice: &[i32]) -> Option<i32> {
    let [mut current_max, ref tail @ ..] = *slice else {
        return None;
    };
    slice = tail;

    while let [head, ref rest @ ..] = *slice {
        if head > current_max {
            current_max = head;
        }
        slice = rest;
    }
    Some(current_max)
}

const PEAK: Option<i32> = max_in_slice(&[14, 92, 37, 88, 5]);

fn main() {
    println!("compile-time PEAK = {:?}", PEAK);
}
compile-time PEAK = Some(92)