annotate 1.0.0

Runtime annotation framework for Rust functions and modules
Documentation

annotate-rs

annotate is a Rust annotation and reflection framework.

  • mark functions and modules with #[pragma(...)]
  • create custom annotations
  • attach structured metadata such as strings, booleans, integers, and Rust types
  • generate a static annotation environment during build.rs
  • query annotated items at runtime with predicates over modules and functions
  • call discovered functions when their signature is known

The workspace is split into:

  • annotate: runtime API and public macro re-exports
  • annotate-build: build-time scanner and code generator
  • annotate-derive: procedural macro implementation

Installation

Add annotate to your crate dependencies and annotate-build to your build dependencies:

[dependencies]
annotate = "x.y.z"

[build-dependencies]
annotate-build = "x.y.z"

Quick Start

Create a build.rs file that scans the crate and generates the annotation environment:

fn main() {
    annotate_build::build();
}

Annotate functions or modules in your crate and include the generated environment:

annotate::environment!();

#[pragma(tag = "math", active = true)]
pub mod operations {
    use annotate::*;

    #[pragma(kind = "sum")]
    fn add(a: i32, b: i32) -> i32 {
        a + b
    }
}

Query the functions at runtime:

use annotate::Value;

fn main() {
    let function = environment()
        .find_functions_such_that(&|function| {
            function.has_attribute_such_that(&|attribute| {
                attribute.name() == "kind" && attribute.is_str("sum")
            })
        })
        .into_iter()
        .next()
        .unwrap();

    assert_eq!(function.name(), "add");

    let value = function.call::<fn(i32, i32) -> i32, _>(|f| f(2, 3));
    assert_eq!(value, 5);
}

Querying modules by associated type:

annotate::environment!();

#[pragma(associated_type = String)]
mod module_with_associated_type {
    
}

fn main() {
    let module = environment()
        .find_modules_such_that(&|module| {
            module.has_attribute_such_that(&|attribute| {
                attribute.name() == "associated_type" && attribute.is_type::<String>()
            })
        })
        .into_iter()
        .next()
        .unwrap();

    assert_eq!(module.name(), "module_with_associated_type");
}

What Gets Generated

At build time, annotate-build scans the crate source and generates a static Environment containing:

  • annotated functions
  • annotated modules
  • their paths
  • their attributes
  • links between modules and functions

The generated Rust code is written into OUT_DIR and included through annotate::environment!().

Limitations

  • #[pragma] currently supports functions and modules only.
  • Calling discovered functions still requires the caller to know the exact function signature.
  • Dynamic return support is limited and primarily intended for zero-argument functions.
  • Build-time code generation is required; this crate is not purely macro-only.

License

Licensed under MIT.