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}