yadir_derive/
lib.rs

1//! # yadir_derive
2//!
3//! This crate provides helpful procedural macros for the `yadir` crate.
4
5use crate::expand_handlers::expand_di_builder;
6
7mod expand_handlers;
8mod helper_primitives;
9
10/// Derive the `DIBuilder` trait for a struct.
11///
12/// This proc macro is used to automatically derive the `DIBuilder` trait for a struct.
13/// The `DIBuilder` trait is used to build a dependency by specifying the input/dependencies, the output, and the build method for a given dependency.
14///
15/// The `#[derive(DIBuilder)]` macro provides a few helper attributes to customize the behavior of the builder:
16/// - `#[build_as]`: Specifies the output type of the builder. If this attribute is not present, the output type will be the input struct itself.
17/// - `#[build_method]`: Specifies the method to build the dependency, which can be one of the following:
18///    - `new`: Calls the `new` method on the input struct.
19///    - `default`: Calls the `Default` trait implementation for the input struct.
20///    - `None` (the attribute is missing): Directly instantiates the input struct.
21/// - `#[deps]`: Specifies the fields that are input dependencies for the builder.
22///
23/// Rules for attributes usage:
24/// - `#[build_as]` is optional on the struct
25/// - `#[build_method]` is optional on the struct
26/// - `#[deps]` is optional on the fields
27/// - `#[deps]` can only be used on fields and no more than once per field
28/// - `#[build_as]` can only be used once and always before `#[build_method]`
29/// - `#[build_method]` can only be used once and always after `#[build_as]`
30///
31/// # Example
32///
33/// ```ignore
34///
35/// trait Printer: Sync + Send + DynClone {
36///    fn print(&self) -> String;
37/// }
38///
39/// #[derive(Clone, DIBuilder)]
40/// #[build_as(Box<dyn Printer>)]
41/// struct Bar;
42///
43/// impl Printer for Bar {
44///     fn print(&self) -> String {
45///         "bar".to_string()
46///     }
47/// }
48///
49/// #[derive(Default, Clone, DIBuilder)]
50/// #[build_method("default")]
51/// struct Baz;
52///
53/// #[derive(Clone, DIBuilder)]
54/// #[build_method("new")]
55/// struct Qux;
56///
57/// impl Qux {
58///    pub fn new() -> Self {
59///       Self
60///   }
61/// }
62///
63/// #[derive(Clone, DIBuilder)]
64/// #[build_method("new")]
65/// struct Foo {
66///    #[deps]
67///    bar: Box<dyn Printer>,
68///    #[deps]
69///    baz: Baz,
70///    #[deps]
71///    qux: Qux,
72/// }
73///
74/// impl Foo {
75///     pub fn new(bar: Box<dyn Printer>, baz: Baz, qux: Qux) -> Self {
76///        Self { bar, baz, qux }
77///     }
78/// }
79/// ```
80#[proc_macro_derive(DIBuilder, attributes(build_as, build_method, deps))]
81pub fn derive_di_builder(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
82    let input = syn::parse_macro_input!(input as syn::ItemStruct);
83    expand_di_builder(input)
84        .unwrap_or_else(syn::Error::into_compile_error)
85        .into()
86}