Crates.io | injectables |
lib.rs | injectables |
version | 0.1.0 |
source | src |
created_at | 2024-10-25 23:45:18.776351 |
updated_at | 2024-10-25 23:45:18.776351 |
description | A procedural macro library that enables field injection between Rust structs through #[injectable] and #[inject_fields] attributes. The library handles visibility rules, generic type resolution, and detects circular dependencies during compile time to ensure safe composition. This enables a declarative approach to struct composition where fields from one or more source structs can be automatically injected into target structs while respecting Rust's ownership and visibility rules. |
homepage | |
repository | https://github.com/paulxtiseo/injectables |
max_upload_size | |
id | 1423393 |
size | 426,944 |
A Rust procedural macro library that enables field injection between structs through declarative attributes. This library allows you to compose structs by automatically injecting fields from one or more source structs while respecting Rust's visibility rules and ownership semantics.
pub
, pub(crate)
, private)Add this to your Cargo.toml
:
[dependencies]
injectables = "0.1.0"
use injectables::{injectable, inject_fields};
// Mark source struct as injectable
#[injectable]
pub struct Base {
pub id: u64,
}
// Inject fields from Base into Document
#[inject_fields(Base)]
pub struct Document {
pub title: String,
}
fn main() {
let doc = Document {
title: "Test".to_string(),
id: 1, // Field injected from Base
};
assert_eq!(doc.id, 1);
assert_eq!(doc.title, "Test");
}
The library handles generic types with concrete type specifications:
#[injectable]
pub struct GenericBase<T> {
pub data: T,
}
#[inject_fields(GenericBase<String>)]
pub struct Container {
pub name: String,
}
let container = Container {
name: "Test".to_string(),
data: "Hello".to_string(), // Injected with concrete String type
};
Fields can be injected transitively through multiple structs:
#[injectable]
pub struct A {
pub id: u64,
}
#[injectable]
#[inject_fields(A)]
pub struct B {
pub name: String,
}
#[inject_fields(B)]
pub struct C {
pub description: String,
}
// C will have fields: description, name (from B), and id (from A)
The library respects Rust's visibility rules:
mod inner {
#[injectable]
pub struct Private {
id: u64, // private field
pub name: String, // public field
pub(crate) age: u32, // crate-visible field
}
}
// Can only inject visible fields based on module boundaries
#[inject_fields(inner::Private)]
pub struct Public {
pub value: String,
// Can access `name` and `age`, but not `id`
}
The library performs several compile-time checks to ensure correct usage:
#[injectable]
#[injectable]
before being used in inject_fields
inject_fields
The library provides clear compile-time error messages:
When attempting circular injections:
error: Circular injection chain detected: A already depends on B
When accessing private fields from invalid module:
error: Cannot access private field 'id' from struct 'Private' defined in module 'other_module'
Contributions are welcome! Please feel free to submit a Pull Request.
Licensed under either of:
at your option.
This crate uses #![forbid(unsafe_code)]
to ensure 100% safe Rust.