1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#![allow(clippy::needless_doctest_main)]
#![doc = include_str!("../README.md")]
mod core;
mod inject;
mod injectable;
mod module;
mod provider;
use inject::handle_inject;
use injectable::handle_injectable;
use module::handle_module;
use proc_macro::TokenStream;
use provider::handle_provider;

/// For internal purposes only. Should not be used.
#[proc_macro_derive(InjectableHelperAttr, attributes(inject))]
pub fn injectable_helper_attr(_item: TokenStream) -> TokenStream {
    TokenStream::new()
}

/// For internal purposes only. Should not be used.
#[proc_macro_derive(ModuleHelperAttr, attributes(export))]
pub fn module_helper_attr(_item: TokenStream) -> TokenStream {
    TokenStream::new()
}

/// For internal purposes only. Should not be used.
#[proc_macro_derive(ProviderHelperAttr, attributes(import, provide, scope))]
pub fn provider_helper_attr(_item: TokenStream) -> TokenStream {
    TokenStream::new()
}

/// For internal purposes only. Should not be used.
#[proc_macro_derive(ScopeHelperAttr, attributes(arg))]
pub fn scope_helper_attr(_item: TokenStream) -> TokenStream {
    TokenStream::new()
}

/// Mark a struct as injectable.
/// ```rust
/// use nject::{injectable, provider};
///
/// #[injectable]
/// struct Facade;
///
/// #[provider]
/// struct Provider;
///
/// let facade: Facade = Provider.provide();
/// ```
#[proc_macro_attribute]
pub fn injectable(_attr: TokenStream, item: TokenStream) -> TokenStream {
    handle_injectable(item).unwrap_or_else(|e| e.to_compile_error().into())
}

/// Use the given value to inject.
/// ```rust
/// use nject::{inject, injectable, provider};
///
/// #[inject(Self { value: 42 })]
/// struct DepOne {
///     value: i32,
/// }
///
/// #[inject(|injectable_dep: DepOne| Self(12, injectable_dep))]
/// struct DepTwo(i32, DepOne);
///
/// #[injectable]
/// struct Facade(DepOne, DepTwo, #[inject(123)] i32);
///
/// #[provider]
/// struct Provider;
///
/// let facade: Facade = Provider.provide();
/// ```
#[proc_macro_attribute]
pub fn inject(attr: TokenStream, item: TokenStream) -> TokenStream {
    handle_inject(item, attr).unwrap_or_else(|e| e.to_compile_error().into())
}

/// Provide a value for a specific type.
/// ```rust
/// use nject::{injectable, provider};
///
/// struct Dependency {
///     value: i32,
/// }
///
/// struct SharedDependency {
///     value: i32,
/// }
///
/// #[injectable]
/// struct Facade<'a>(Dependency, &'a SharedDependency);
///
/// #[provider]
/// #[provide(Dependency, Dependency { value: 123 })]
/// struct Provider {
///     #[provide]
///     shared: SharedDependency
/// }
///
/// let provider = Provider { shared: SharedDependency { value: 456 } };
/// let dependency: Dependency = provider.provide();
/// let facade: Facade = provider.provide();
/// ```
#[proc_macro_attribute]
pub fn provider(_attr: TokenStream, item: TokenStream) -> TokenStream {
    handle_provider(item).unwrap_or_else(|e| e.to_compile_error().into())
}

/// Declare a module to export internal types.
/// ```rust
/// use nject::{injectable, provider};
///
/// mod sub {
///     use nject::{injectable, module};
///     use std::rc::Rc;
///
///     #[injectable]
///     struct InternalType(#[inject(123)] i32); // Not visible outside of module.
///
///     #[injectable]
///     pub struct Facade<'a> {
///         hidden: &'a InternalType,
///         public: Rc<i32>,
///     }
///
///     #[injectable]
///     // The absolute public path to access the module.
///     // If no path is given, the struct name will be used and must be unique across all modules.
///     // Keywords like `crate` and `Self` will be substituted accordingly.
///     #[module(crate::sub::Self)]
///     // Public type exports must be made on the struct (not the fields).
///     // To prevent name collisions, use absolute paths in types.
///     #[export(std::rc::Rc<i32>, self.public.clone())]
///     pub struct Module {
///         #[export] // Fields exports are for internal types.
///         hidden: InternalType,
///         #[inject(Rc::new(456))]
///         public: Rc<i32>,
///     }
/// }
///
/// #[injectable]
/// #[provider]
/// struct Provider {
///     #[import]
///     // To import module public exports, use the absolute path given in its definition.
///     sub_mod: crate::sub::Module,
/// }
///
/// #[provider]
/// struct InitProvider;
///
/// fn main() {
///     let provider = InitProvider.provide::<Provider>();
///     let facade = provider.provide::<sub::Facade>();
/// }
/// ```
#[proc_macro_attribute]
pub fn module(attr: TokenStream, item: TokenStream) -> TokenStream {
    handle_module(attr, item).unwrap_or_else(|e| e.to_compile_error().into())
}