rudi-macro-dev 0.1.3

Macros for Rudi.
Documentation
mod commons;
mod field_or_argument_attr;
mod impl_fn_or_enum_variant_attr;
mod item_enum_gen;
mod item_fn_gen;
mod item_impl_gen;
mod item_struct_gen;
mod resource_attr;
mod struct_or_function_attr;
mod util;
mod value_attr;

use from_attr::FromAttr;
use proc_macro::TokenStream;
use rudi_core::Scope;
use syn::{parse_macro_input, spanned::Spanned, Item};

use crate::struct_or_function_attr::StructOrFunctionAttr;

fn generate(attr: TokenStream, item: TokenStream, scope: Scope) -> TokenStream {
    let attr = match StructOrFunctionAttr::from_tokens(attr.into()) {
        Ok(attr) => attr,
        Err(err) => return err.to_compile_error().into(),
    };

    let item = parse_macro_input!(item as Item);

    let result = match item {
        Item::Struct(item_struct) => item_struct_gen::generate(attr, item_struct, scope),
        Item::Enum(item_enum) => item_enum_gen::generate(attr, item_enum, scope),
        Item::Fn(item_fn) => item_fn_gen::generate(attr, item_fn, scope),
        Item::Impl(item_impl) => item_impl_gen::generate(attr, item_impl, scope),
        _ => Err(syn::Error::new(
            item.span(),
            "expected `struct` or `enum` or `function` or `impl block`",
        )),
    };

    result.unwrap_or_else(|e| e.to_compile_error()).into()
}

/// 单例过程宏
///
/// # 参数说明
/// - `name`:           单例名称,默认使用结构体名称(首字符小写)生成, 例如: `TestData` -> `testData`
/// - `eager_create`:   是否在初始化时立即创建实例(预加载)
/// - `condition`:      可选条件闭包或路径,用于控制此单例的 Provider 是否插入 Context 中
/// - `binds`:          绑定路径列表,一般来说这里可以填入结构体的动态实现
/// - `async`:         可选异步标记路径值,指定是否为异步单例(使用 `#[async]` 属性重命名)
/// - `auto_register`:  是否自动注册到容器(仅在启用 `auto-register` 特性时有效,默认为 `DEFAULT_AUTO_REGISTER`)
/// - `default`:        使用结构体实现 `Default` trait 将实例注入仓库中
///
/// # 辅助宏参数说明
/// `resource`
/// - `name`:           单例名称,优先级高
/// - `option`:         表示这个字段是可能找不到的,那么字段类型必须为 `Option<T>`
/// - `default`:        此字段需要保证实现了 `Default` trait,在构建实例时,此字段使用默认值
/// - `vec`:            保证获取到所有此类型的单例,应和 `name` 参数排斥, 字段类型应为 `Vec<T>`
/// - `map`:            保证获取到所有此类型的单例, 前提当前字段实现了 `Singleton` trait, 字段类型应为 `std::collections::HashMap<K, V>`
/// - `ref`:            引用类型, & T
///
/// # 示例
/// ```rust
/// use std::sync::Arc;
///
/// #[singleton(
///     name = "myDataImpl",
///     condition = test_condition,
///     binds = [Self::into_data],
/// )]
/// struct DataImpl {
///     #[resource(name = "testData")]
///     data: String,
///     /// 这里用的是字段名称去仓库找单例并注入 `more_data` -> `moreData`, 若是指定名称则不会这样处理
///     more_data: Option<Vec<u8>>,
/// }
///
/// trait Data {
///     fn call() -> &'static str;
/// }
///
/// impl Data for DataImpl {
///     fn call() -> &'static str {
///         "hello"
///     }
/// }
///
/// impl DataImpl {
///
///     fn into_data(self) -> Arc<dyn Data> {
///         Arc::new(self)
///     }
/// }
///
/// fn test_condition(cx: &ApplicationContext) -> bool {
///    !cx.contains_single_with_name::<i32>("5")
/// }
/// ```
///
/// Single instance process macro
///
/// # Parameter Description
/// - ` name `: singleton name, generated by default using the structure name (lowercase first character), for example: `TestData` -> `testData`
/// - 'eager_create': Whether to immediately create an instance (preloaded) during initialization
/// - ` condition `: Optional conditional closure or path, used to control whether the Provider of this singleton is inserted into the Context
/// - ` bindings `: a list of binding paths, usually where the dynamic implementation of the structure can be filled in
/// - ` async `: Optional asynchronous tag path value, specifying whether it is an asynchronous singleton (rename using the ` # [async] ` property)
/// - ` auto_register `: Whether it is automatically registered to the container (only valid when the ` auto register ` feature is enabled, default is ` DEFAULT_SUTD_RIGIST `)
/// - ` default `: Use a struct to implement the ` Default ` trait and inject instances into the repository
///
/// # Auxiliary Macro Parameter Description
/// `resource`
/// - ` name `: Single instance name, high priority
/// - ` option `: indicates that this field may not be found, so the field type must be ` Option<T>`
/// - ` default `: This field needs to ensure that the ` Default ` trait is implemented. When building instances, this field uses the default value
/// - ` 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>`
/// - ` 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>`
/// - ref: Reference type,&T
///
/// # Example
/// ```rust
/// use std::sync::Arc;
///
/// #[singleton(
///     name = "myDataImpl",
///     condition = test_condition,
///     binds = [Self::into_data],
/// )]
/// struct DataImpl {
///     #[resource(name = "testData")]
///     data: String,
/// 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
///     more_data: Option<Vec<u8>>,
/// }
///
/// trait Data {
///     fn call() -> &'static str;
/// }
///
/// impl Data for DataImpl {
///     fn call() -> &'static str {
///         "hello"
///     }
/// }
///
/// impl DataImpl {
///
///     fn into_data(self) -> Arc<dyn Data> {
///         Arc::new(self)
///     }
/// }
///
/// fn test_condition(cx: &ApplicationContext) -> bool {
///    ! cx.contains_single_with_name::<i32>("5")
/// }
/// ```
#[doc = include_str!("./docs/attribute_macro.md")]
#[proc_macro_attribute]
pub fn singleton(attr: TokenStream, item: TokenStream) -> TokenStream {
    generate(attr, item, Scope::Singleton)
}

/// Define a transient provider.
#[doc = ""]
#[doc = include_str!("./docs/attribute_macro.md")]
#[proc_macro_attribute]
pub fn transient(attr: TokenStream, item: TokenStream) -> TokenStream {
    generate(attr, item, Scope::Transient)
}

/// Define a single owner provider.
#[doc = ""]
#[doc = include_str!("./docs/attribute_macro.md")]
#[proc_macro_attribute]
pub fn singleowner(attr: TokenStream, item: TokenStream) -> TokenStream {
    generate(attr, item, Scope::SingleOwner)
}