Skip to main content

rust_dix_macros/
lib.rs

1//! Procedural macros for [`rust-dix`](https://docs.rs/rust-dix)
2//! (`rust-dix-macros`).
3//!
4//! This crate is an implementation detail of `rust-dix`; depend on
5//! `rust-dix`, which re-exports these macros (do not depend on this crate
6//! directly unless you have a specific reason).
7//!
8//! # Macros
9//!
10//! - [`macro@Inject`] — `#[derive(Inject)]` generates constructor injection
11//!   code from struct fields (fields marked `#[inject]`,
12//!   `#[inject(owned)]`, `#[inject(provider)]`, `#[inject(key = <expr>)]` or
13//!   `#[inject(owned, key = <expr>)]`). Key expressions accept string literals,
14//!   typed `ServiceKey` values, or downstream key types implementing
15//!   `From<LocalKey> for ServiceKey` (extension path instead of duplicating
16//!   macros). `#[inject(provider)]` cannot be combined with `key`
17//!   (compile error; resolve through the injected provider instead).
18//! - [`macro@inject`] — attribute macro placed on structs or trait impls to
19//!   auto-register services with the container.
20//! - [`macro@module`] — compile-time module scan that collects
21//!   `register!()` declarations.
22//! - [`macro@register`] — function-like placeholder used inside
23//!   `#[rust_dix::module]`.
24//!
25//! # Example
26//!
27//! Illustrative only (this proc-macro crate's doctests cannot link the core
28//! crate; the same patterns are compiled in `rust-dix`' test suite and in
29//! `tests/rename.rs`). Expansions reference `rust-dix` through its *real*
30//! dependency name (`proc-macro-crate`), so a renamed dependency such as
31//! `dix = { package = "rust-dix" }` needs no `extern crate` shim:
32//!
33//! ```rust,ignore
34//! use rust_dix::{inject, Inject};
35//! use std::sync::Arc;
36//!
37//! struct Config;
38//! trait IWorker: Send + Sync {}
39//!
40//! #[derive(Inject)]
41//! struct Worker {
42//!     #[inject]
43//!     config: Arc<Config>,
44//! }
45//!
46//! #[inject(singleton)]
47//! impl IWorker for Worker {}
48//! ```
49//!
50//! # Engineering baseline
51//!
52//! MSRV **Rust 1.95**; `#![forbid(unsafe_code)]`; errors are emitted as
53//! compile errors instead of panics where possible. See the
54//! [repository security policy](https://github.com/Rust-Framework/rust-dix/blob/main/SECURITY.md).
55
56#![forbid(unsafe_code)]
57
58use proc_macro::TokenStream;
59use quote::quote;
60use syn::parse_macro_input;
61
62mod crate_path;
63mod field_init;
64mod inject_attr;
65mod inject_derive;
66mod module;
67
68// ───────────────────────────────────────────────────────────────────────────
69// #[derive(Inject)] — auto-generate constructor from struct fields
70// ───────────────────────────────────────────────────────────────────────────
71
72#[proc_macro_derive(Inject, attributes(inject))]
73pub fn inject_derive(input: TokenStream) -> TokenStream {
74    inject_derive::expand_inject_derive(parse_macro_input!(input as syn::DeriveInput))
75        .unwrap_or_else(|e| e.to_compile_error())
76        .into()
77}
78
79// ───────────────────────────────────────────────────────────────────────────
80// register!() — function-like placeholder macro for use inside #[module]
81// ───────────────────────────────────────────────────────────────────────────
82
83#[proc_macro]
84pub fn register(_: TokenStream) -> TokenStream {
85    quote! {}.into()
86}
87
88// ───────────────────────────────────────────────────────────────────────────
89// #[module] — compile-time module scanning for register!() declarations
90// ───────────────────────────────────────────────────────────────────────────
91
92#[proc_macro_attribute]
93pub fn module(_: TokenStream, item: TokenStream) -> TokenStream {
94    module::expand_md(parse_macro_input!(item as syn::ItemMod))
95        .unwrap_or_else(|e| e.to_compile_error())
96        .into()
97}
98
99// ───────────────────────────────────────────────────────────────────────────
100// #[inject] — attribute macro for auto-registration
101// ───────────────────────────────────────────────────────────────────────────
102
103#[proc_macro_attribute]
104pub fn inject(attr: TokenStream, item: TokenStream) -> TokenStream {
105    inject_attr::expand_inject(
106        parse_macro_input!(attr as inject_attr::InjectArgs),
107        parse_macro_input!(item as syn::Item),
108    )
109    .unwrap_or_else(|e| e.to_compile_error())
110    .into()
111}