Skip to main content

nject_macro/
lib.rs

1#![allow(clippy::needless_doctest_main)]
2#![doc = include_str!("../README.md")]
3mod core;
4mod finalize;
5mod init;
6mod inject;
7mod injectable;
8mod module;
9mod provider;
10use finalize::handle_finalize_imports;
11use init::handle_init;
12use inject::handle_inject;
13use injectable::handle_injectable;
14use module::handle_module;
15use proc_macro::TokenStream;
16use provider::handle_provider;
17
18/// For internal purposes only. Should not be used.
19#[proc_macro_derive(InjectableHelperAttr, attributes(inject))]
20pub fn injectable_helper_attr(_item: TokenStream) -> TokenStream {
21    TokenStream::new()
22}
23
24/// For internal purposes only. Should not be used.
25#[proc_macro_derive(ModuleHelperAttr, attributes(export))]
26pub fn module_helper_attr(_item: TokenStream) -> TokenStream {
27    TokenStream::new()
28}
29
30/// For internal purposes only. Should not be used.
31#[proc_macro_derive(ProviderHelperAttr, attributes(import, provide, scope))]
32pub fn provider_helper_attr(_item: TokenStream) -> TokenStream {
33    TokenStream::new()
34}
35
36/// For internal purposes only. Should not be used.
37#[proc_macro_derive(ScopeHelperAttr, attributes(arg))]
38pub fn scope_helper_attr(_item: TokenStream) -> TokenStream {
39    TokenStream::new()
40}
41
42/// Mark a struct as injectable.
43/// ```rust
44/// use nject::{injectable, provider};
45///
46/// #[injectable]
47/// struct Facade;
48///
49/// #[provider]
50/// struct Provider;
51///
52/// let facade: Facade = Provider.provide();
53/// ```
54#[proc_macro_attribute]
55pub fn injectable(_attr: TokenStream, item: TokenStream) -> TokenStream {
56    handle_injectable(item).unwrap_or_else(|e| e.to_compile_error().into())
57}
58
59/// Use the given value to inject.
60/// ```rust
61/// use nject::{inject, injectable, provider};
62///
63/// #[inject(Self { value: 42 })]
64/// struct DepOne {
65///     value: i32,
66/// }
67///
68/// #[inject(|injectable_dep: DepOne| Self(12, injectable_dep))]
69/// struct DepTwo(i32, DepOne);
70///
71/// #[injectable]
72/// struct Facade(DepOne, DepTwo, #[inject(123)] i32);
73///
74/// #[provider]
75/// struct Provider;
76///
77/// let facade: Facade = Provider.provide();
78/// ```
79#[proc_macro_attribute]
80pub fn inject(attr: TokenStream, item: TokenStream) -> TokenStream {
81    handle_inject(item, attr).unwrap_or_else(|e| e.to_compile_error().into())
82}
83
84/// Provide a value for a specific type.
85/// ```rust
86/// use nject::{injectable, provider};
87///
88/// struct Dependency {
89///     value: i32,
90/// }
91///
92/// struct SharedDependency {
93///     value: i32,
94/// }
95///
96/// #[injectable]
97/// struct Facade<'a>(Dependency, &'a SharedDependency);
98///
99/// #[provider]
100/// #[provide(Dependency, Dependency { value: 123 })]
101/// struct Provider {
102///     #[provide]
103///     shared: SharedDependency
104/// }
105///
106/// let provider = Provider { shared: SharedDependency { value: 456 } };
107/// let dependency: Dependency = provider.provide();
108/// let facade: Facade = provider.provide();
109/// ```
110#[proc_macro_attribute]
111pub fn provider(_attr: TokenStream, item: TokenStream) -> TokenStream {
112    handle_provider(item).unwrap_or_else(|e| e.to_compile_error().into())
113}
114
115/// Declare a module to export internal types.
116/// ```rust
117/// use nject::{injectable, provider};
118///
119/// mod sub {
120///     use nject::{injectable, module};
121///     use std::rc::Rc;
122///
123///     #[injectable]
124///     struct InternalType(#[inject(123)] i32); // Not visible outside of module.
125///
126///     #[injectable]
127///     pub struct Facade<'a> {
128///         hidden: &'a InternalType,
129///         public: Rc<i32>,
130///     }
131///
132///     #[injectable]
133///     #[module]
134///     // Public type exports must be made on the struct (not the fields).
135///     // To prevent name collisions, use absolute paths in types.
136///     #[export(std::rc::Rc<i32>, self.public.clone())]
137///     pub struct Module {
138///         #[export] // Fields exports are for internal types.
139///         hidden: InternalType,
140///         #[inject(Rc::new(456))]
141///         public: Rc<i32>,
142///     }
143/// }
144///
145/// #[injectable]
146/// #[provider]
147/// struct Provider {
148///     #[import]
149///     // To import module public exports, use the absolute path to its definition.
150///     sub_mod: crate::sub::Module,
151/// }
152///
153/// #[provider]
154/// struct InitProvider;
155///
156/// fn main() {
157///     let provider = InitProvider.provide::<Provider>();
158///     let facade = provider.provide::<sub::Facade>();
159/// }
160/// ```
161#[proc_macro_attribute]
162pub fn module(attr: TokenStream, item: TokenStream) -> TokenStream {
163    handle_module(attr, item).unwrap_or_else(|e| e.to_compile_error().into())
164}
165
166/// Simplify provider initialisation by automatically creating the chain of intermediate providers.
167///
168/// Instead of manually defining intermediate providers and chaining `.provide()` calls,
169/// use `init!` with the list of module types in dependency order.
170///
171/// # Expression form
172///
173/// Returns the provider as an owned value. Works with struct-level `#[export]` (owned values).
174///
175/// ```rust
176/// use nject::{init, injectable, module, provider};
177///
178/// #[injectable]
179/// #[module]
180/// #[export(i32, 42)]
181/// struct ConfigModule;
182///
183/// #[injectable]
184/// #[module]
185/// #[export(String, |x: i32| format!("value: {}", x))]
186/// struct FormatModule;
187///
188/// #[injectable]
189/// #[provider]
190/// struct AppProvider(#[import] ConfigModule, #[import] FormatModule);
191///
192/// let provider: AppProvider = init!(ConfigModule, FormatModule);
193/// let greeting: String = provider.provide();
194/// assert_eq!(greeting, "value: 42");
195/// ```
196///
197/// # Block form
198///
199/// Expands `let` declarations into the enclosing scope, keeping intermediate providers alive.
200/// This supports field-level `#[export]` (references) and multiple declarations (like `lazy_static!`).
201///
202/// ```rust
203/// use nject::{init, injectable, module, provider};
204///
205/// #[derive(Debug)]
206/// #[injectable]
207/// struct Secret(#[inject(42)] i32);
208///
209/// #[injectable]
210/// #[module]
211/// struct SecretModule {
212///     #[export]
213///     secret: Secret,
214/// }
215///
216/// #[injectable]
217/// struct Consumer<'a>(&'a Secret);
218///
219/// #[injectable]
220/// #[provider]
221/// struct AppProvider(#[import] SecretModule);
222///
223/// init! {
224///     let provider: AppProvider = SecretModule;
225/// }
226/// let consumer: Consumer = provider.provide();
227/// assert_eq!(consumer.0.0, 42);
228/// ```
229#[proc_macro]
230pub fn init(item: TokenStream) -> TokenStream {
231    handle_init(item).unwrap_or_else(|e| e.to_compile_error().into())
232}
233
234/// For internal purposes only. Should not be used.
235#[doc(hidden)]
236#[proc_macro]
237pub fn __nject_finalize_imports(item: TokenStream) -> TokenStream {
238    handle_finalize_imports(item).unwrap_or_else(|e| e.to_compile_error().into())
239}