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}