use super::*; /// Generates strongly typed utilites to access inputs pub(crate) fn generate_node_input_references( parsed: &ParsedNodeFn, fn_generics: &[crate::GenericParam], field_idents: &[&PatIdent], core_types: &TokenStream2, identifier: &Ident, cfg: &TokenStream2, ) -> TokenStream2 { let inputs_module_name = format_ident!("{}", parsed.struct_name.to_string().to_case(Case::Snake)); let mut generated_input_accessor = Vec::new(); if !parsed.attributes.skip_impl { let (mut modified, mut generic_collector) = FilterUsedGenerics::new(fn_generics); for (input_index, (parsed_input, input_ident)) in parsed.fields.iter().zip(field_idents).enumerate() { let mut ty = match &parsed_input.ty { ParsedFieldType::Regular(RegularParsedField { ty, .. }) => ty, ParsedFieldType::Node(NodeParsedField { output_type, .. }) => output_type, } .clone(); // We only want the necessary generics. let used = generic_collector.filter_unnecessary_generics(&mut modified, &mut ty); // TODO: figure out a better name that doesn't conflict with so many types let struct_name = format_ident!("{}Input", input_ident.ident.to_string().to_case(Case::Pascal)); let (fn_generic_params, phantom_data_declerations) = generate_phantom_data(used.iter()); // Only create structs with phantom data where necessary. generated_input_accessor.push(if phantom_data_declerations.is_empty() { quote! { pub struct #struct_name; } } else { quote! { pub struct #struct_name <#(#used),*>{ #(#phantom_data_declerations,)* } } }); generated_input_accessor.push(quote! { impl <#(#used),*> #core_types::NodeInputDecleration for #struct_name <#(#fn_generic_params),*> { const INDEX: usize = #input_index; fn identifier() -> #core_types::ProtoNodeIdentifier { #inputs_module_name::IDENTIFIER.clone() } type Result = #ty; } }) } } quote! { #cfg pub mod #inputs_module_name { use super::*; /// The `ProtoNodeIdentifier` of this node without any generics attached to it pub const IDENTIFIER: #core_types::ProtoNodeIdentifier = #identifier(); #(#generated_input_accessor)* } } } /// It is necessary to generate PhantomData for each fn generic to avoid compiler errors. pub(crate) fn generate_phantom_data<'a>(fn_generics: impl Iterator) -> (Vec, Vec) { let mut phantom_data_declerations = Vec::new(); let mut fn_generic_params = Vec::new(); for fn_generic_param in fn_generics { let field_name = format_ident!("phantom_{}", phantom_data_declerations.len()); match fn_generic_param { crate::GenericParam::Lifetime(lifetime_param) => { let lifetime = &lifetime_param.lifetime; fn_generic_params.push(quote! {#lifetime}); phantom_data_declerations.push(quote! {#field_name: core::marker::PhantomData<&#lifetime ()>}) } crate::GenericParam::Type(type_param) => { let generic_name = &type_param.ident; fn_generic_params.push(quote! {#generic_name}); phantom_data_declerations.push(quote! {#field_name: core::marker::PhantomData<#generic_name>}); } _ => {} } } (fn_generic_params, phantom_data_declerations) } /// Get only the necessary generics. struct FilterUsedGenerics { all: Vec, used: Vec, } impl VisitMut for FilterUsedGenerics { fn visit_lifetime_mut(&mut self, used_lifetime: &mut Lifetime) { for (generic, used) in self.all.iter().zip(self.used.iter_mut()) { let crate::GenericParam::Lifetime(lifetime_param) = generic else { continue }; if used_lifetime == &lifetime_param.lifetime { *used = true; } } } fn visit_path_mut(&mut self, path: &mut syn::Path) { for (index, (generic, used)) in self.all.iter().zip(self.used.iter_mut()).enumerate() { let crate::GenericParam::Type(type_param) = generic else { continue }; if path.leading_colon.is_none() && !path.segments.is_empty() && path.segments[0].arguments.is_none() && path.segments[0].ident == type_param.ident { *used = true; // Sometimes the generics conflict with the type name so we rename the generics. path.segments[0].ident = format_ident!("G{index}"); } } for mut el in Punctuated::pairs_mut(&mut path.segments) { self.visit_path_segment_mut(el.value_mut()); } } } impl FilterUsedGenerics { fn new(fn_generics: &[crate::GenericParam]) -> (Vec, Self) { let mut all_possible_generics = fn_generics.to_vec(); // The 'n lifetime may also be needed; we must add it in all_possible_generics.insert(0, syn::GenericParam::Lifetime(syn::LifetimeParam::new(Lifetime::new("'n", proc_macro2::Span::call_site())))); let modified = all_possible_generics .iter() .cloned() .enumerate() .map(|(index, mut generic)| { let crate::GenericParam::Type(type_param) = &mut generic else { return generic }; // Sometimes the generics conflict with the type name so we rename the generics. type_param.ident = format_ident!("G{index}"); generic }) .collect::>(); let generic_collector = Self { used: vec![false; all_possible_generics.len()], all: all_possible_generics, }; (modified, generic_collector) } fn used<'a>(&'a self, modified: &'a [crate::GenericParam]) -> impl Iterator { modified.iter().zip(&self.used).filter(|(_, used)| **used).map(move |(value, _)| value) } fn filter_unnecessary_generics(&mut self, modified: &mut Vec, ty: &mut Type) -> Vec { self.used.fill(false); // Find out which generics are necessary to support the node input self.visit_type_mut(ty); // Sometimes generics may reference other generics. This is a non-optimal way of dealing with that. for _ in 0..=self.all.len() { for (index, item) in modified.iter_mut().enumerate() { if self.used[index] { self.visit_generic_param_mut(item); } } } self.used(&*modified).cloned().collect() } }