Skip to main content

nest_rs_macros/
lib.rs

1//! Surface-agnostic nestrs decorators (`#[injectable]`, `#[hooks]`,
2//! `#[module]`), re-exported by `nestrs-core`. Each `#[proc_macro_attribute]`
3//! entry below is a thin delegation to its implementation module.
4
5use proc_macro::TokenStream;
6
7mod hooks;
8mod injectable;
9mod module;
10
11/// Mark a struct as a DI provider built from the container.
12///
13/// `#[inject]` fields resolve via `container.get()` (or `get_dyn` for
14/// `Arc<dyn Trait>`); other fields fall back to `Default::default()`. A struct
15/// with no `#[inject]` field uses `<Self as Default>::default()` so a custom
16/// `Default` impl is preserved.
17///
18/// Emits `impl Discoverable for Self` so the struct can appear directly in
19/// `#[module(providers = [...])]`.
20///
21/// `#[injectable(scope = request)]` registers a per-request factory built once
22/// per request (and resolved through a `RequestScope` — e.g. the HTTP
23/// `Scoped<T>` extractor). A request-scoped provider may depend on singletons
24/// but not on other request-scoped providers.
25///
26/// `#[injectable(scope = transient)]` registers a factory rebuilt on every
27/// resolution: each `container.get::<T>()` (or `Scoped<T>` extraction) yields
28/// a fresh instance. A transient may depend on singletons and request-scoped
29/// providers; a transient depending (transitively) on itself panics with a
30/// cycle diagnostic at resolution time.
31#[proc_macro_attribute]
32pub fn injectable(args: TokenStream, input: TokenStream) -> TokenStream {
33    injectable::injectable(args, input)
34}
35
36/// Declare application lifecycle hooks on a provider's impl block, for the
37/// module/application init and shutdown phases.
38///
39/// Each method tagged with a phase attribute is invoked by
40/// [`App`](nest_rs_core::App):
41///
42/// - `#[on_module_init]` / `#[on_application_bootstrap]` — after wiring,
43///   before serving. An error aborts boot.
44/// - `#[on_module_destroy]` / `#[before_application_shutdown]` /
45///   `#[on_application_shutdown]` — after transports stop, best-effort.
46///
47/// A hook is `async fn(&self)` returning `()` or
48/// `Result<(), E: Into<anyhow::Error>>`. Hooks are submitted to a link-time
49/// registry, so the provider keeps its single `impl Discoverable`.
50#[proc_macro_attribute]
51pub fn hooks(args: TokenStream, input: TokenStream) -> TokenStream {
52    hooks::hooks(args, input)
53}
54
55/// `#[module(imports = [...], providers = [...])]`.
56///
57/// `imports` is either a type (a static [`Module`](nest_rs_core::Module)) or a
58/// call expression (a configured [`DynamicModule`](nest_rs_core::DynamicModule)
59/// built at its import site). `providers` lists what this module
60/// declares.
61///
62/// Each provider entry is `Foo` (a `Discoverable` type) or
63/// `Foo as dyn Trait` (a trait-object binding stored via `provide_dyn`).
64///
65/// Registration is idempotent: a diamond import builds its providers exactly
66/// once. Dynamic imports carry their own config and are not deduplicated.
67///
68/// Imports register first, then providers register via a fixpoint pass — each
69/// declares its dependencies through `Discoverable::dependencies` and the
70/// macro registers whatever is resolvable, repeating until done. A provider
71/// whose dependencies never resolve (missing or cyclic) panics at boot.
72#[proc_macro_attribute]
73pub fn module(args: TokenStream, input: TokenStream) -> TokenStream {
74    module::module(args, input)
75}