bevy_yoetz_macros/suggestion/
variant.rs1use proc_macro2::TokenStream;
2use quote::quote;
3use syn::{parse_quote, Error};
4
5use super::field::{FieldConfig, FieldRole};
6use super::suggestion_enum::SuggestionEnumData;
7
8pub struct SuggestionVariantData<'a> {
9 pub parent: &'a SuggestionEnumData,
10 pub name: syn::Ident,
11 pub strategy_name: syn::Ident,
12 pub fields: syn::Fields,
13 pub fields_config: Vec<FieldConfig>,
14}
15
16impl<'a> SuggestionVariantData<'a> {
17 pub fn new(parent: &'a SuggestionEnumData, variant: &syn::Variant) -> Result<Self, Error> {
18 let mut fields = variant.fields.clone();
19 let fields_config = fields
20 .iter_mut()
21 .map(FieldConfig::new_for)
22 .collect::<Result<Vec<_>, _>>()?;
23 Ok(Self {
24 parent,
25 name: variant.ident.clone(),
26 strategy_name: syn::Ident::new(
27 &format!("{}{}", parent.name, variant.ident,),
28 variant.ident.span(),
29 ),
30 fields,
31 fields_config,
32 })
33 }
34
35 fn semicolon_if_needed(&self) -> Option<syn::token::Semi> {
36 if matches!(self.fields, syn::Fields::Named(..)) {
37 None
38 } else {
39 Some(Default::default())
40 }
41 }
42
43 pub fn emit_strategy_code(&self) -> Result<TokenStream, Error> {
44 let strategy_name = &self.strategy_name;
45 let mut fields = self.fields.clone();
46 for (field, config) in fields.iter_mut().zip(self.fields_config.iter()) {
47 field.vis = self.parent.visibility.clone();
48 if config.role.unwrap() == FieldRole::Key {
49 field.attrs.push(parse_quote!(#[allow(dead_code)]))
50 }
51 }
52 let visibility = &self.parent.visibility;
53 let semicolon = self.semicolon_if_needed();
54 let extra_derives = &self.parent.strategy_structs_config.derive;
55 Ok(quote! {
56 #[derive(bevy::ecs::component::Component, #(#extra_derives),*)]
57 #visibility struct #strategy_name #fields #semicolon
58 })
59 }
60
61 pub fn iter_fields_with_configs(&self) -> impl Iterator<Item = (&syn::Field, &FieldConfig)> {
62 self.fields.iter().zip(&self.fields_config)
63 }
64
65 pub fn iter_key_fields(&self) -> impl Iterator<Item = &syn::Field> {
66 self.iter_fields_with_configs()
67 .filter_map(|(field, config)| {
68 if config.role.unwrap() == FieldRole::Key {
69 Some(field)
70 } else {
71 None
72 }
73 })
74 }
75
76 pub fn emit_key_enum_variant(&self) -> Result<TokenStream, Error> {
77 let name = &self.name;
78 let fields = match &self.fields {
79 syn::Fields::Named(named) => syn::Fields::Named(syn::FieldsNamed {
80 brace_token: named.brace_token,
81 named: self.iter_key_fields().cloned().collect(),
82 }),
83 syn::Fields::Unnamed(unnamed) => {
84 return Err(Error::new_spanned(
85 unnamed,
86 "tuple variants are currently unsupported for YoetzSuggestion, \
87 and are resuseved for future features",
88 ));
89 }
90 syn::Fields::Unit => syn::Fields::Unit,
91 };
92 Ok(quote! {
93 #name #fields
94 })
95 }
96}