Skip to content

๐Ÿ”ฎ Compile-time type reflection for Rust - inspect traits, fields, and methods from proc-macros

Notifications You must be signed in to change notification settings

DrewRidley/bronzite

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

3 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿ”ฎ Bronzite

Compile-time type reflection for Rust โœจ

Crates.io Documentation License

๐Ÿช„ Ever wished you could inspect types, traits, and method bodies at compile time? Now you can!

Bronzite lets your proc-macros see everything about your types - trait implementations, field names, method signatures, even the source code of method bodies. All at compile time. ๐Ÿš€

๐ŸŒŸ Features

  • ๐Ÿ” Discover trait implementations - Find out what traits a type implements
  • ๐Ÿ“‹ Inspect struct fields - Get field names, types, and visibility
  • ๐Ÿ”ง Examine methods - See method signatures and even their bodies
  • ๐Ÿ”— Resolve type aliases - Follow the chain to the underlying type
  • ๐Ÿงญ Navigate type relationships - Fluently explore from types to fields to their definitions
  • โšก Fast & cached - A background daemon caches compilation results
  • ๐Ÿค Proc-macro friendly - Designed to be used from your own macros

๐Ÿ“ฆ Installation

# Install the daemon and tools
cargo install bronzite

# Make sure you have the required nightly toolchain
rustup toolchain install nightly-2025-08-20

๐Ÿš€ Quick Start

High-Level Reflection API (Recommended)

The new v0.2 API provides an ergonomic, navigation-focused interface:

use bronzite_client::Crate;

#[proc_macro]
pub fn my_reflection_macro(input: TokenStream) -> TokenStream {
    // ๐Ÿ”Œ Reflect on a crate (auto-starts daemon if needed!)
    let krate = Crate::reflect("my_crate").unwrap();
    
    // ๐Ÿ” Query items with pattern matching
    let items = krate.items("bevy::prelude::*").unwrap();
    
    // ๐Ÿ—๏ธ Get a struct and explore it
    let user = krate.get_struct("User").unwrap();
    
    // ๐Ÿ“‹ Navigate to fields
    for field in user.fields().unwrap() {
        println!("{}: {}", field.name.unwrap(), field.ty);
        
        // ๐Ÿ”— Navigate to field's type definition
        if let Some(field_type) = field.type_def().unwrap() {
            println!("  -> defined in: {}", field_type.path());
        }
    }
    
    // โœ… Check trait implementations
    if user.implements("Debug").unwrap() {
        println!("User implements Debug!");
    }
    
    // ๐Ÿ”ง Get methods with their signatures
    for method in user.methods().unwrap() {
        println!("Method: {} -> {:?}", 
            method.name, 
            method.parsed_signature.return_ty
        );
        
        // ๐Ÿ“– Even get the method body source!
        if let Some(body) = method.body_source {
            println!("Body: {}", body);
        }
    }
    
    // ... generate code based on what you discovered
    quote! { /* generated code */ }.into()
}

Pattern Matching

The new API supports intuitive glob patterns:

let krate = Crate::reflect("my_crate")?;

// Exact match
let user = krate.get_struct("User")?;

// Single-level wildcard: matches "foo::Bar" but not "foo::bar::Baz"
let items = krate.items("mymod::*")?;

// Recursive wildcard: matches all descendants
let all_items = krate.items("mymod::**")?;

// Prefix matching
let items = krate.items("MyType*")?; // matches MyTypeA, MyTypeB, etc.

Type-Specific Queries

let krate = Crate::reflect("my_crate")?;

// Get only structs
let structs = krate.structs("*")?;

// Get only enums
let enums = krate.enums("*")?;

// Get only traits
let traits = krate.traits("*")?;

Unified Item Enum

All items are represented by a unified Item enum:

use bronzite_client::Item;

for item in krate.items("*")? {
    match item {
        Item::Struct(s) => {
            println!("Struct: {}", s.name);
            for field in s.fields()? {
                println!("  - {}: {}", field.name.unwrap(), field.ty);
            }
        }
        Item::Enum(e) => {
            println!("Enum: {}", e.name);
            if let Some(variants) = e.variants() {
                for variant in variants {
                    println!("  - {}", variant.name);
                }
            }
        }
        Item::Trait(t) => {
            println!("Trait: {}", t.name);
            for method in t.methods() {
                println!("  - {}", method.name);
            }
        }
        Item::TypeAlias(a) => {
            println!("Type alias: {} -> {}", a.path, a.resolved_path);
        }
        Item::Union(u) => {
            println!("Union: {}", u.name);
        }
    }
}

๐Ÿ—๏ธ Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Your Proc-     โ”‚โ”€โ”€โ”€โ”€โ–ถโ”‚  bronzite-daemon โ”‚โ”€โ”€โ”€โ”€โ–ถโ”‚  bronzite-query โ”‚
โ”‚  Macro          โ”‚     โ”‚  (cached)        โ”‚     โ”‚  (rustc plugin) โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
        โ”‚                       โ”‚                        โ”‚
        โ”‚    Unix Socket        โ”‚    Compiles &          โ”‚
        โ”‚    IPC ๐Ÿ”Œ             โ”‚    Extracts ๐Ÿ“Š         โ”‚
        โ–ผ                       โ–ผ                        โ–ผ
   TokenStream            Type Info Cache         rustc Internals
  1. ๐Ÿ”Œ bronzite-client - Your proc-macro uses the high-level Crate API
  2. ๐Ÿ  bronzite-daemon - Background service that caches compilation
  3. ๐Ÿ”ฌ bronzite-query - Rustc plugin that extracts type information
  4. ๐Ÿ“ฆ bronzite-types - Shared protocol types

๐Ÿ“š API Overview

Main Entry Point

Method Description
Crate::reflect(name) ๐Ÿ”Œ Connect to daemon and reflect on a crate
krate.items(pattern) ๐Ÿ“ฆ Get all items matching a pattern
krate.structs(pattern) ๐Ÿ—๏ธ Get all structs
krate.enums(pattern) ๐Ÿ“‹ Get all enums
krate.traits(pattern) ๐Ÿ”— Get all traits
krate.get_struct(path) ๐ŸŽฏ Get a specific struct
krate.get_enum(path) ๐ŸŽฏ Get a specific enum
krate.get_trait(path) ๐ŸŽฏ Get a specific trait

Struct Methods

Method Description
struct.fields() ๐Ÿ“‹ Get all fields
struct.methods() ๐Ÿ”ง Get inherent methods
struct.trait_impls() ๐Ÿ”— Get trait implementations
struct.implements(trait) โœ… Check if implements a trait
struct.layout() ๐Ÿ“ Get memory layout info
struct.source() ๐Ÿ“– Get source code
struct.docs() ๐Ÿ“ Get doc comments

Field Methods

Method Description
field.type_def() ๐Ÿ”— Navigate to field's type definition
field.name ๐Ÿ“› Field name (Option for tuple fields)
field.ty ๐Ÿท๏ธ Type as string
field.size ๐Ÿ“ Size in bytes (if available)
field.offset ๐Ÿ“ Offset in bytes (if available)

Method Methods

Method Description
method.return_type_def() ๐Ÿ”— Navigate to return type
method.param_types() ๐Ÿ”— Navigate to parameter types
method.body_source ๐Ÿ“– Method body source code
method.parsed_signature ๐Ÿ” Parsed signature details

Trait Methods

Method Description
trait.methods() ๐Ÿ”ง Get all trait methods
trait.associated_types() ๐Ÿท๏ธ Get associated types
trait.associated_consts() ๐Ÿ”ข Get associated constants
trait.implementors() ๐Ÿ“‹ Get all implementing types

๐ŸŽฎ Example

Check out the examples/ directory for a complete working example:

cd examples

# Start the daemon pointing at the types crate
../target/release/bronzite-daemon --manifest-path my-types &

# Run the example app
cd my-app && cargo run

Output:

=== Bronzite Compile-Time Reflection Demo ===

Traits implemented by User (discovered at compile time):
  - Debug
  - Clone
  - Serialize
  - HasId

Methods on User (discovered at compile time):
  - new()
  - deactivate()
  - is_active()

Compile-time trait checks:
  User implements Serialize: true
  Product implements Serialize: true

=== Demo Complete ===

๐Ÿ”ง Requirements

  • Rust nightly-2025-08-20 - Required for the rustc plugin (the daemon handles this automatically)
  • Unix-like OS or Windows - Uses Unix sockets on Unix, TCP on Windows

๐Ÿ”„ Migration Guide (v0.1 โ†’ v0.2)

Breaking Changes

The v0.2 release introduces a completely redesigned API focused on ergonomics and navigation. The low-level client methods are still available, but the new high-level API is recommended.

Before (v0.1)

use bronzite_client::{BronziteClient, ensure_daemon_running};

ensure_daemon_running()?;
let mut client = BronziteClient::connect()?;

let impls = client.get_trait_impls("my_crate", "User")?;
let fields = client.get_fields("my_crate", "User")?;
let (implements, _) = client.check_impl("my_crate", "User", "Debug")?;

After (v0.2)

use bronzite_client::Crate;

let krate = Crate::reflect("my_crate")?;
let user = krate.get_struct("User")?;

let impls = user.trait_impls()?;
let fields = user.fields()?;
let implements = user.implements("Debug")?;

Key Improvements

  1. Single connection - Crate::reflect() handles daemon startup and connection
  2. Navigation - Types hold references to the client, enabling fluent navigation
  3. Type-safe - Unified Item enum instead of string-based queries
  4. Pattern matching - Intuitive glob patterns for querying types
  5. Source code - Most types now include their source code
  6. Ergonomic - Chaining methods instead of multiple client calls

Low-Level API Still Available

If you need the low-level API, it's still available:

use bronzite_client::BronziteClient;

let mut client = BronziteClient::connect()?;
let items = client.list_items("my_crate")?;

But we recommend the new high-level API for most use cases.

๐Ÿค” Why "Bronzite"?

Bronzite is a mineral known for its reflective, bronze-like sheen. Just like how bronzite reflects light, this crate reflects your types! ๐Ÿชจโœจ

๐Ÿ“„ License

Licensed under either of:

at your option.

๐Ÿค Contributing

Contributions are welcome! Feel free to:

  • ๐Ÿ› Report bugs
  • ๐Ÿ’ก Suggest features
  • ๐Ÿ”ง Submit PRs

Made with ๐Ÿ’œ and a lot of โ˜•

About

๐Ÿ”ฎ Compile-time type reflection for Rust - inspect traits, fields, and methods from proc-macros

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages