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 (the macros generate code that references `rust_dix`, so
28//! this proc-macro crate's doctests cannot link the core crate; the same
29//! patterns are compiled in `rust-dix`' test suite):
30//!
31//! ```rust,ignore
32//! use rust_dix::{inject, Inject};
33//! use std::sync::Arc;
34//!
35//! struct Config;
36//! trait IWorker: Send + Sync {}
37//!
38//! #[derive(Inject)]
39//! struct Worker {
40//! #[inject]
41//! config: Arc<Config>,
42//! }
43//!
44//! #[inject(singleton)]
45//! impl IWorker for Worker {}
46//! ```
47//!
48//! # Engineering baseline
49//!
50//! MSRV **Rust 1.95**; `#![forbid(unsafe_code)]`; errors are emitted as
51//! compile errors instead of panics where possible. See the
52//! [repository security policy](https://github.com/Rust-Framework/rust-dix/blob/main/SECURITY.md).
53
54#![forbid(unsafe_code)]
55
56use proc_macro::TokenStream;
57use quote::quote;
58use syn::parse_macro_input;
59
60mod field_init;
61mod inject_attr;
62mod inject_derive;
63mod module;
64
65// ───────────────────────────────────────────────────────────────────────────
66// #[derive(Inject)] — auto-generate constructor from struct fields
67// ───────────────────────────────────────────────────────────────────────────
68
69#[proc_macro_derive(Inject, attributes(inject))]
70pub fn inject_derive(input: TokenStream) -> TokenStream {
71 inject_derive::expand_inject_derive(parse_macro_input!(input as syn::DeriveInput))
72 .unwrap_or_else(|e| e.to_compile_error())
73 .into()
74}
75
76// ───────────────────────────────────────────────────────────────────────────
77// register!() — function-like placeholder macro for use inside #[module]
78// ───────────────────────────────────────────────────────────────────────────
79
80#[proc_macro]
81pub fn register(_: TokenStream) -> TokenStream {
82 quote! {}.into()
83}
84
85// ───────────────────────────────────────────────────────────────────────────
86// #[module] — compile-time module scanning for register!() declarations
87// ───────────────────────────────────────────────────────────────────────────
88
89#[proc_macro_attribute]
90pub fn module(_: TokenStream, item: TokenStream) -> TokenStream {
91 module::expand_md(parse_macro_input!(item as syn::ItemMod))
92 .unwrap_or_else(|e| e.to_compile_error())
93 .into()
94}
95
96// ───────────────────────────────────────────────────────────────────────────
97// #[inject] — attribute macro for auto-registration
98// ───────────────────────────────────────────────────────────────────────────
99
100#[proc_macro_attribute]
101pub fn inject(attr: TokenStream, item: TokenStream) -> TokenStream {
102 inject_attr::expand_inject(
103 parse_macro_input!(attr as inject_attr::InjectArgs),
104 parse_macro_input!(item as syn::Item),
105 )
106 .unwrap_or_else(|e| e.to_compile_error())
107 .into()
108}