modi_macros 0.1.1

Code generation for the modi dependency injection framework
Documentation
//! This crate provides modi::dyn_mod's derive macros.

#![allow(dead_code)]

extern crate proc_macro;
#[macro_use]
extern crate quote;

use crate::structures::module::ModuleData;
use proc_macro::TokenStream;

mod consts;
mod debug;
mod macros;
mod parser;
mod structures;

#[proc_macro_derive(Component, attributes(modi))]
pub fn component(input: TokenStream) -> TokenStream {
    let input = syn::parse_macro_input!(input as syn::DeriveInput);

    macros::component
        ::expand_derive_component(&input)
        .unwrap_or_else(|e| e.to_compile_error())
        .into()
}

#[proc_macro_derive(Provider, attributes(modi))]
pub fn provider(input: TokenStream) -> TokenStream {
    let input = syn::parse_macro_input!(input as syn::DeriveInput);

    macros::provider
        ::expand_derive_provider(&input)
        .unwrap_or_else(|e| e.to_compile_error())
        .into()
}

/// Create a [`Module`] which is associated with some components and providers.
///
/// ## Builder
/// A `fn builder(submodules...) -> ModuleBuilder<Self>` associated function will be created to make
/// instantiating the module convenient. The arguments are the submodules the module uses.
///
/// ## Module interfaces
/// After the module name, you can add `: MyModuleInterface` where `MyModuleInterface` is the trait
/// that you want this module to implement (ex. `trait MyModuleInterface: HasComponent<MyComponent> {}`).
/// The macro will implement this trait for the module automatically. That is, it is the same as
/// manually adding the line: `impl MyModuleInterface for MyModule {}`. See `MyModuleImpl` in the
/// example below. See also [`ModuleInterface`].
///
/// ## Submodules
/// A module can use components/providers from other modules by explicitly listing the interfaces
/// from each submodule they want to use. Submodules can be abstracted by depending on traits
/// instead of implementations. See `MySecondModule` in the example below.
///
/// See also the [submodules getting started guide].
///
/// ## Generics
/// This macro supports generics at the module level:
/// ```rust
/// use modi::dyn_mod::{module, Component, Interface, HasComponent};
///
/// trait MyComponent<T: Interface>: Interface {}
///
/// #[derive(Component)]
/// #[modi(interface = MyComponent<T>)]
/// struct MyComponentImpl<T: Interface + Default> {
///     value: T
/// }
/// impl<T: Interface + Default> MyComponent<T> for MyComponentImpl<T> {}
///
/// // MyModuleImpl implements Module and HasComponent<dyn MyComponent<T>>
/// module! {
///     MyModule<T: Interface> where T: Default {
///         components = [MyComponentImpl<T>],
///         providers = []
///     }
/// }
/// # fn main() {}
/// ```
///
/// ## Circular dependencies
/// This macro will detect circular dependencies at compile time. The error that is thrown will be
/// something like
/// "overflow evaluating the requirement `TestModule: HasComponent<(dyn Component1Trait + 'static)>`".
///
/// It is still possible to compile with a circular dependency if the module is manually implemented
/// in a certain way. In that case, there will be a panic during module creation with more details.
///
/// ## Lazy Components
/// Components can be lazily created by annotating them with `#[lazy]` in the module declaration.
/// The component will not be built until it is required, such as when `resolve_ref` is called for
/// the first time.
///
/// ```rust
/// use modi::dyn_mod::{module, Component, Interface};
///
/// trait Service: Interface {}
///
/// #[derive(Component)]
/// #[modi(interface = Service)]
/// struct ServiceImpl;
/// impl Service for ServiceImpl {}
///
/// module! {
///     MyModule {
///         components = [#[lazy] ServiceImpl],
///         providers = []
///     }
/// }
/// # fn main() {}
/// ```
///
/// # Examples
/// ```
/// use modi::dyn_mod::{module, Component, Interface, HasComponent};
///
/// trait MyComponent: Interface {}
/// trait MyModule: HasComponent<dyn MyComponent> {}
///
/// #[derive(Component)]
/// #[modi(interface = MyComponent)]
/// struct MyComponentImpl;
/// impl MyComponent for MyComponentImpl {}
///
/// // MyModuleImpl implements Module, MyModule, and HasComponent<dyn MyComponent>
/// module! {
///     MyModuleImpl: MyModule {
///         components = [MyComponentImpl],
///         providers = []
///     }
/// }
///
/// // MySecondModule implements HasComponent<dyn MyComponent> by using
/// // MyModule's implementation.
/// module! {
///     MySecondModule {
///         components = [],
///         providers = [],
///
///         use MyModule {
///             components = [MyComponent],
///             providers = []
///         }
///     }
/// }
/// # fn main() {}
/// ```
///
/// [`Module`]: trait.Module.html
/// [`ModuleInterface`]: trait.ModuleInterface.html
/// [submodules getting started guide]: guide/submodules/index.html
#[proc_macro]
pub fn module(input: TokenStream) -> TokenStream {
    let module = syn::parse_macro_input!(input as ModuleData);

    macros::module
        ::expand_module_macro(module)
        .unwrap_or_else(|e| e.to_compile_error())
        .into()
}

/// # Examples
/// ```
/// dyn_modules![ConsoleOutput, TodayWriter];
/// ```
/// Then, you will get `DynModules` struct.
#[proc_macro]
pub fn dyn_modules(input: TokenStream) -> TokenStream {
    let input_parsed = syn::parse_macro_input!(input as proc_macro2::TokenStream);
    let input: TokenStream = (
        quote! {
            DynModules {
                components = [
                    #input_parsed
                ],
                providers = []
            }
    }
    ).into();

    module(input)
}