Skip to main content

rudi_macro_dev/
lib.rs

1mod commons;
2mod field_or_argument_attr;
3mod impl_fn_or_enum_variant_attr;
4mod item_enum_gen;
5mod item_fn_gen;
6mod item_impl_gen;
7mod item_struct_gen;
8mod resource_attr;
9mod struct_or_function_attr;
10mod util;
11mod value_attr;
12
13use from_attr::FromAttr;
14use proc_macro::TokenStream;
15use rudi_core::Scope;
16use syn::{parse_macro_input, spanned::Spanned, Item};
17
18use crate::struct_or_function_attr::StructOrFunctionAttr;
19
20fn generate(attr: TokenStream, item: TokenStream, scope: Scope) -> TokenStream {
21    let attr = match StructOrFunctionAttr::from_tokens(attr.into()) {
22        Ok(attr) => attr,
23        Err(err) => return err.to_compile_error().into(),
24    };
25
26    let item = parse_macro_input!(item as Item);
27
28    let result = match item {
29        Item::Struct(item_struct) => item_struct_gen::generate(attr, item_struct, scope),
30        Item::Enum(item_enum) => item_enum_gen::generate(attr, item_enum, scope),
31        Item::Fn(item_fn) => item_fn_gen::generate(attr, item_fn, scope),
32        Item::Impl(item_impl) => item_impl_gen::generate(attr, item_impl, scope),
33        _ => Err(syn::Error::new(
34            item.span(),
35            "expected `struct` or `enum` or `function` or `impl block`",
36        )),
37    };
38
39    result.unwrap_or_else(|e| e.to_compile_error()).into()
40}
41
42/// 单例过程宏
43///
44/// # 参数说明
45/// - `name`:           单例名称,默认使用结构体名称(首字符小写)生成, 例如: `TestData` -> `testData`
46/// - `eager_create`:   是否在初始化时立即创建实例(预加载)
47/// - `condition`:      可选条件闭包或路径,用于控制此单例的 Provider 是否插入 Context 中
48/// - `binds`:          绑定路径列表,一般来说这里可以填入结构体的动态实现
49/// - `async`:         可选异步标记路径值,指定是否为异步单例(使用 `#[async]` 属性重命名)
50/// - `auto_register`:  是否自动注册到容器(仅在启用 `auto-register` 特性时有效,默认为 `DEFAULT_AUTO_REGISTER`)
51/// - `default`:        使用结构体实现 `Default` trait 将实例注入仓库中
52///
53/// # 辅助宏参数说明
54/// `resource`
55/// - `name`:           单例名称,优先级高
56/// - `option`:         表示这个字段是可能找不到的,那么字段类型必须为 `Option<T>`
57/// - `default`:        此字段需要保证实现了 `Default` trait,在构建实例时,此字段使用默认值
58/// - `vec`:            保证获取到所有此类型的单例,应和 `name` 参数排斥, 字段类型应为 `Vec<T>`
59/// - `map`:            保证获取到所有此类型的单例, 前提当前字段实现了 `Singleton` trait, 字段类型应为 `std::collections::HashMap<K, V>`
60/// - `ref`:            引用类型, & T
61///
62/// # 示例
63/// ```rust
64/// use std::sync::Arc;
65///
66/// #[singleton(
67///     name = "myDataImpl",
68///     condition = test_condition,
69///     binds = [Self::into_data],
70/// )]
71/// struct DataImpl {
72///     #[resource(name = "testData")]
73///     data: String,
74///     /// 这里用的是字段名称去仓库找单例并注入 `more_data` -> `moreData`, 若是指定名称则不会这样处理
75///     more_data: Option<Vec<u8>>,
76/// }
77///
78/// trait Data {
79///     fn call() -> &'static str;
80/// }
81///
82/// impl Data for DataImpl {
83///     fn call() -> &'static str {
84///         "hello"
85///     }
86/// }
87///
88/// impl DataImpl {
89///
90///     fn into_data(self) -> Arc<dyn Data> {
91///         Arc::new(self)
92///     }
93/// }
94///
95/// fn test_condition(cx: &ApplicationContext) -> bool {
96///    !cx.contains_single_with_name::<i32>("5")
97/// }
98/// ```
99///
100/// Single instance process macro
101///
102/// # Parameter Description
103/// - ` name `: singleton name, generated by default using the structure name (lowercase first character), for example: `TestData` -> `testData`
104/// - 'eager_create': Whether to immediately create an instance (preloaded) during initialization
105/// - ` condition `: Optional conditional closure or path, used to control whether the Provider of this singleton is inserted into the Context
106/// - ` bindings `: a list of binding paths, usually where the dynamic implementation of the structure can be filled in
107/// - ` async `: Optional asynchronous tag path value, specifying whether it is an asynchronous singleton (rename using the ` # [async] ` property)
108/// - ` auto_register `: Whether it is automatically registered to the container (only valid when the ` auto register ` feature is enabled, default is ` DEFAULT_SUTD_RIGIST `)
109/// - ` default `: Use a struct to implement the ` Default ` trait and inject instances into the repository
110///
111/// # Auxiliary Macro Parameter Description
112/// `resource`
113/// - ` name `: Single instance name, high priority
114/// - ` option `: indicates that this field may not be found, so the field type must be ` Option<T>`
115/// - ` default `: This field needs to ensure that the ` Default ` trait is implemented. When building instances, this field uses the default value
116/// - ` vec `: Ensure to obtain all singleton of this type, which should be excluded from the ` name ` parameter, and the field type should be ` Vec<T>`
117/// - ` map `: Ensure that all singleton instances of this type are obtained, provided that the current field implements the ` Singleton ` trait and the field type should be ` std:: collections: HashMap<K, V>`
118/// - ref: Reference type,&T
119///
120/// # Example
121/// ```rust
122/// use std::sync::Arc;
123///
124/// #[singleton(
125///     name = "myDataImpl",
126///     condition = test_condition,
127///     binds = [Self::into_data],
128/// )]
129/// struct DataImpl {
130///     #[resource(name = "testData")]
131///     data: String,
132/// Here, the field name is used to search for a single instance in the warehouse and inject 'more_data' ->'moreData'. If a name is specified, it will not be processed in this way
133///     more_data: Option<Vec<u8>>,
134/// }
135///
136/// trait Data {
137///     fn call() -> &'static str;
138/// }
139///
140/// impl Data for DataImpl {
141///     fn call() -> &'static str {
142///         "hello"
143///     }
144/// }
145///
146/// impl DataImpl {
147///
148///     fn into_data(self) -> Arc<dyn Data> {
149///         Arc::new(self)
150///     }
151/// }
152///
153/// fn test_condition(cx: &ApplicationContext) -> bool {
154///    ! cx.contains_single_with_name::<i32>("5")
155/// }
156/// ```
157#[doc = include_str!("./docs/attribute_macro.md")]
158#[proc_macro_attribute]
159pub fn singleton(attr: TokenStream, item: TokenStream) -> TokenStream {
160    generate(attr, item, Scope::Singleton)
161}
162
163/// Define a transient provider.
164#[doc = ""]
165#[doc = include_str!("./docs/attribute_macro.md")]
166#[proc_macro_attribute]
167pub fn transient(attr: TokenStream, item: TokenStream) -> TokenStream {
168    generate(attr, item, Scope::Transient)
169}
170
171/// Define a single owner provider.
172#[doc = ""]
173#[doc = include_str!("./docs/attribute_macro.md")]
174#[proc_macro_attribute]
175pub fn singleowner(attr: TokenStream, item: TokenStream) -> TokenStream {
176    generate(attr, item, Scope::SingleOwner)
177}