keket_graph_derive/
lib.rs1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{Attribute, ItemStruct, parse_macro_input, parse_quote};
4
5fn has_asset_deps_attr(attrs: &[Attribute]) -> bool {
6 attrs.iter().any(|attr| attr.path.is_ident("asset_deps"))
7}
8
9#[proc_macro_derive(AssetTree, attributes(asset_deps))]
14pub fn asset_tree_struct(input: TokenStream) -> TokenStream {
15 let ItemStruct {
16 ident,
17 fields,
18 mut generics,
19 ..
20 } = parse_macro_input!(input as ItemStruct);
21 let generics_params = generics.params.clone();
22 let where_clause = generics.make_where_clause();
23 for param in &generics_params {
24 if let syn::GenericParam::Type(ty) = param {
25 where_clause.predicates.push(parse_quote!(#ty: AssetTree));
26 }
27 }
28 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
29 let fields = fields
30 .iter()
31 .filter(|field| has_asset_deps_attr(&field.attrs))
32 .filter_map(|field| field.ident.as_ref())
33 .collect::<Vec<_>>();
34 quote! {
35 impl #impl_generics AssetTree for #ident #ty_generics #where_clause {
36 fn asset_dependencies(&self) -> impl IntoIterator<Item = AssetPathStatic> {
37 let mut result = vec![];
38 #(
39 result.extend(self.#fields.asset_dependencies());
40 )*
41 result
42 }
43 }
44 }
45 .into()
46}