Compile-time type reflection for Rust โจ
๐ช 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. ๐
- ๐ 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
# Install the daemon and tools
cargo install bronzite
# Make sure you have the required nightly toolchain
rustup toolchain install nightly-2025-08-20The 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()
}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.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("*")?;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);
}
}
}โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
โ Your Proc- โโโโโโถโ bronzite-daemon โโโโโโถโ bronzite-query โ
โ Macro โ โ (cached) โ โ (rustc plugin) โ
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
โ โ โ
โ Unix Socket โ Compiles & โ
โ IPC ๐ โ Extracts ๐ โ
โผ โผ โผ
TokenStream Type Info Cache rustc Internals
- ๐ bronzite-client - Your proc-macro uses the high-level
CrateAPI - ๐ bronzite-daemon - Background service that caches compilation
- ๐ฌ bronzite-query - Rustc plugin that extracts type information
- ๐ฆ bronzite-types - Shared protocol types
| 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 |
| 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 |
| 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 | 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 |
| 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 |
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 runOutput:
=== 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 ===
- 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
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.
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")?;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")?;- Single connection -
Crate::reflect()handles daemon startup and connection - Navigation - Types hold references to the client, enabling fluent navigation
- Type-safe - Unified
Itemenum instead of string-based queries - Pattern matching - Intuitive glob patterns for querying types
- Source code - Most types now include their source code
- Ergonomic - Chaining methods instead of multiple client calls
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.
Bronzite is a mineral known for its reflective, bronze-like sheen. Just like how bronzite reflects light, this crate reflects your types! ๐ชจโจ
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Contributions are welcome! Feel free to:
- ๐ Report bugs
- ๐ก Suggest features
- ๐ง Submit PRs
Made with ๐ and a lot of โ