dipper_macros/lib.rs
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
//! This crate provides dipper::dyn_mod's derive macros.
#![allow(dead_code)]
#[macro_use]
extern crate quote;
use proc_macro::TokenStream;
use proc_macro2::{Ident, Span};
use utils::dipper_crate;
use crate::structures::module::ModuleData;
mod consts;
mod macros;
mod parser;
mod structures;
mod utils;
#[proc_macro_attribute]
pub fn dipper(args: TokenStream, input: TokenStream) -> TokenStream {
use macros::salvo_craft;
use quote::ToTokens;
use syn::Item;
let item = syn::parse_macro_input!(input as Item);
match item {
Item::Struct(_) | Item::Enum(_) => {
let i = Ident::new(args.to_string().as_str(), Span::call_site());
let m = dipper_crate();
let code1 = quote! {
#[#m(#i)]
#item
};
let mut code2 = TokenStream::from(item.into_token_stream());
code2.extend(component(code1.into_token_stream().into()));
code2
}
_ => match salvo_craft::generate(args, item) {
Ok(stream) => stream.into(),
Err(e) => e.to_compile_error().into(),
},
}
}
#[proc_macro_derive(Component, attributes(dipper))]
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(dipper))]
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:
/// ```ignore
/// #[macro_use]
/// use dipper::dyn_mod::{Component, Interface, HasComponent};
/// use dipper_macros::dipper;
///
/// trait MyComponent<T: Interface>: Interface {}
///
/// #[dipper(MyComponent)]
/// 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.
///
///
/// [`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()
}
/// 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)
}