nject_macro/
inject.rs

1use crate::core::{DeriveInput, FactoryExpr, error};
2use proc_macro::TokenStream;
3use quote::quote;
4use syn::{
5    Error, Expr, PatType, Token,
6    parse::{Parse, ParseStream},
7};
8
9struct InjectExpr(Box<Expr>, Vec<PatType>);
10impl Parse for InjectExpr {
11    fn parse(input: ParseStream) -> syn::Result<Self> {
12        if input.peek(Token![|]) {
13            let expr = FactoryExpr::parse(input)?;
14            Ok(InjectExpr(expr.body, expr.inputs))
15        } else {
16            Ok(InjectExpr(input.parse()?, vec![]))
17        }
18    }
19}
20
21pub(crate) fn handle_inject(item: TokenStream, attr: TokenStream) -> syn::Result<TokenStream> {
22    let input = syn::parse::<DeriveInput>(item)?;
23    let attributes: InjectExpr = syn::parse(attr).map_err(|e| {
24        error::combine(Error::new(e.span(), "Unable to parse inject attribute."), e)
25    })?;
26    let ident = &input.ident;
27    let generic_params = input.generic_params();
28    let generic_keys = input.generic_keys();
29    let lifetime_keys = input.lifetime_keys();
30    let prov_lifetimes = match lifetime_keys.is_empty() {
31        false => quote! { 'prov: #(#lifetime_keys)+*, },
32        true => quote! {},
33    };
34    let prov_types = attributes.1.iter().map(|x| &x.ty).collect::<Vec<_>>();
35    let where_predicates = match &input.generics.where_clause {
36        Some(w) => {
37            let predicates = &w.predicates;
38            quote! { #predicates }
39        }
40        None => quote! {},
41    };
42    let prov_input = attributes
43        .1
44        .iter()
45        .map(|x| quote! { let #x = provider.provide(); })
46        .collect::<Vec<_>>();
47    let factory = attributes.0;
48    let creation_output = quote! {
49       #(#prov_input)*
50       #factory
51    };
52    let output = quote! {
53        #input
54
55        impl<'prov, #(#generic_params,)*NjectProvider> nject::Injectable<'prov, #ident<#(#generic_keys),*>, NjectProvider> for #ident<#(#generic_keys),*>
56            where
57                #prov_lifetimes
58                NjectProvider: #(nject::Provider<'prov, #prov_types>)+*, #where_predicates
59        {
60            #[inline]
61            fn inject(provider: &'prov NjectProvider) -> #ident<#(#generic_keys),*> {
62                #creation_output
63            }
64        }
65    };
66    Ok(output.into())
67}