apecs_derive_canfetch/
lib.rs1use quote::quote;
5use syn::{
6 punctuated::Punctuated, token::Comma, Data, DataStruct, DeriveInput, Field, Fields,
7 FieldsNamed, FieldsUnnamed, Ident, Path, Type, WhereClause, WherePredicate,
8};
9
10fn collect_field_types(fields: &Punctuated<Field, Comma>) -> Vec<Type> {
11 fields.iter().map(|x| x.ty.clone()).collect()
12}
13
14fn gen_identifiers(fields: &Punctuated<Field, Comma>) -> Vec<Ident> {
15 fields.iter().map(|x| x.ident.clone().unwrap()).collect()
16}
17
18fn gen_from_body(path: &Path, ast: &Data, name: &Ident) -> (proc_macro2::TokenStream, Vec<Type>) {
19 enum DataType {
20 Struct,
21 Tuple,
22 }
23
24 let (body, fields) = match *ast {
25 Data::Struct(DataStruct {
26 fields: Fields::Named(FieldsNamed { named: ref x, .. }),
27 ..
28 }) => (DataType::Struct, x),
29 Data::Struct(DataStruct {
30 fields: Fields::Unnamed(FieldsUnnamed { unnamed: ref x, .. }),
31 ..
32 }) => (DataType::Tuple, x),
33 _ => panic!("Enums are not supported"),
34 };
35
36 let tys = collect_field_types(fields);
37
38 let fetch_return = match body {
39 DataType::Struct => {
40 let identifiers = gen_identifiers(fields);
41
42 quote! {
43 #name {
44 #( #identifiers: #path::CanFetch::construct(loan_mngr)? ),*
45 }
46 }
47 }
48 DataType::Tuple => {
49 let count = tys.len();
50 let fetch = vec![quote! { #path::CanFetch::construct(loan_mngr)? }; count];
51
52 quote! {
53 #name ( #( #fetch ),* )
54 }
55 }
56 };
57
58 (fetch_return, tys)
59}
60
61pub fn derive_canfetch(path: Path, input: DeriveInput) -> proc_macro2::TokenStream {
63 let name = input.ident;
64 let (construct_return, tys) = gen_from_body(&path, &input.data, &name);
65 let mut generics = input.generics;
66 {
67 fn constrain_system_data_types(path: &Path, clause: &mut WhereClause, tys: &[Type]) {
69 for ty in tys.iter() {
70 let where_predicate: WherePredicate = syn::parse_quote!(#ty : #path::CanFetch);
71 clause.predicates.push(where_predicate);
72 }
73 }
74
75 let where_clause = generics.make_where_clause();
76 constrain_system_data_types(&path, where_clause, &tys)
77 }
78
79 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
80
81 let output = quote! {
82 impl #impl_generics #path::CanFetch for #name #ty_generics #where_clause {
83 fn borrows() -> Vec<#path::internal::Borrow> {
84 let mut r = Vec::new();
85 #({
86 r.extend(<#tys as #path::CanFetch>::borrows());
87 })*
88 r
89 }
90
91 fn construct(loan_mngr: &mut #path::internal::LoanManager) -> anyhow::Result<Self> {
92 Ok(#construct_return)
93 }
94
95 fn plugin() -> #path::Plugin {
96 #path::Plugin::default()
97 #(.with_plugin(<#tys as #path::CanFetch>::plugin()))*
98 }
99 }
100 };
101
102 output.into()
103}
104
105pub fn derive_trydefault(path: Path, mut input: DeriveInput) -> proc_macro2::TokenStream {
107 let name = input.ident;
108 {input.generics.make_where_clause();}
109 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
110 let where_clause = if let Some(mut clause) = where_clause.map(|c| c.clone()) {
111 let where_predicate: WherePredicate = syn::parse_quote!(#name #ty_generics : Default);
112 clause.predicates.push(where_predicate);
113 clause
114 } else {
115 syn::parse_quote!(where #name #ty_generics: Default)
116 };
117 let output = quote!{
118 impl #impl_generics #path::TryDefault for #name #ty_generics #where_clause {
119 fn try_default() -> Option<Self> {
120 Some(Self::default())
121 }
122 }
123 };
124 output.into()
125}