Feedback for more unrestricted compile time reflection work around

โš“ Rust    ๐Ÿ“… 2026-05-30    ๐Ÿ‘ค surdeus    ๐Ÿ‘๏ธ 1      

surdeus

Hello, Iโ€™m trying to create work around for compile time reflection that has more access and possible code opened, more unrestricted flexibility

The Key Insight

Unlike other approaches that spin up separate project environments, it leverages Rust's own test harness as its execution engine. So if code can be written in a standard Rust test, it can also be executed at compile time and embed the output back to the code. This design alone remove many limitations that I will explain more below

Key Features

  • Unrestricted Compile Time Power: Run loops, dynamic allocations, complex file system I/O, or networking tasks at compile time. "No scope limitation"
  • Zero Duplication: Call library from the main crate without duplicating compilation artifacts that saves SSD space.
  • No Proc Macro Difficulty: Generate values, tokens, or types dynamically with normal Rust syntax.

Comparison to Crabtime

While libraries like Crabtime solve a similar problem, this approach idea solves several of the limitations:

Feature F_Comptime Crabtime
Accessibility Full Access. Can use any code, functions, and structs from the project just like normal Rust code. Isolated. Can not use code outside the macro scope due to running in a separate project context.
Partial Embedding Supported. Can partially embed raw tokens into the code. Not Supported. Cannot embed partially.
Async Support Native. Works easily out of the box using standard attributes like #[tokio::test]. Complex. Requires setting up manual async dependencies and runtime creation for every macro scope.
Dependency Cache Shared. Reuses the exact same compilation cache as the main crate. Duplicated. Copies dependencies to a new project, consuming extra SSD space to store duplicate compilation artifacts.

Example code for demonstration:

use fcomptime::{
    init_comptime, 
    comptime, 
    source, 
    output, 
    call_scope, 
    call,
    comptime_source
};

init_comptime!();

call!(full, "struct_data");

call!(partial, "my_data", 
    trait A {
      fn b();
    }
    trait B {
      fn c();
    }
    
    struct MyImpl;
    impl A for MyImpl {
      fn b() {
        
      }
    }
    
    struct MyData<T: #1>( #2 );
    impl<T: #1> MyData<T> {
      fn new(a: T) -> Self {
        Self(a)
      }
    }
);

fn shared_code_to_other_runtime_code(a: i32) -> i32 {
  a * 2
}

#[comptime]
fn calculate() {
  let res = shared_code_to_other_runtime_code(2);
  source! {
      output!(raw, res, "calculated");
  }
}

#[comptime]
fn main() {
    let a = 10;
    source! {
      let res = shared_code_to_other_runtime_code(a);
      if res == 20 {
        output!(raw, "A, MyImpl", "my_data");
      }
    }

    call_scope! {
        let item = Data {
            id: 1,
            name: String::from("Name"),
        };

        println!("id: {}, name: {}", item.id, item.name);
        
        let res = call!("calculated");
        println!("calculated: {}", res);
    }
    
}

// comptime code that does not depend on function's local code, separated here for cleaner code base
comptime_source! {
  struct_data {
        let raw_content = std::fs::read_to_string("./tes.txt").unwrap_or_default();
        let mut lines = raw_content.lines().filter(|l| !l.trim().is_empty());

        let headers: Vec<&str> = lines.next()
            .unwrap_or("")
            .split(',')
            .map(|s| s.trim())
            .collect();

        let first_data: Vec<&str> = lines.next()
            .unwrap_or("")
            .split(',')
            .map(|s| s.trim())
            .collect();

        let mut fields = Vec::new();
        for (i, header) in headers.iter().enumerate() {
            let val = first_data.get(i).unwrap_or(&"");
            let type_name = if val.parse::<u32>().is_ok() { "u32" } else { "String" };
            fields.push(format!("{}: {}", header, type_name));
        }

        let tokens = format!("struct Data {{ {} }}", fields.join(", "));
        output!(raw, tokens, "struct_data");
  }
}

The repository : GitHub - fuji-184/F_Comptime ยท GitHub

I would love to get your thoughts on this approach!

How to make the execution is ordered so that comptime output can be used in another comptime output?

Currently I have idea about making the test run by its name, since it is possible to run certain single test in Rust. But the problem is all macros are always run no matter whether I just certain test or not

Does anyone has any idea?

1 post - 1 participant

Read full topic

๐Ÿท๏ธ Rust_feed