tusks_lib/codegen/handle_matches/arms/
submodule.rs1use proc_macro2::{Span, TokenStream};
2use quote::quote;
3
4use crate::TusksModule;
5use crate::codegen::module_path::ModulePath;
6use crate::codegen::util::enum_util::to_variant_ident;
7use crate::codegen::util::field_util::is_generated_field;
8
9impl TusksModule {
10 pub fn build_submodule_match_arm(
22 &self,
23 cli_path: &TokenStream,
24 path: &ModulePath,
25 ) -> TokenStream {
26 let variant_ident = to_variant_ident(&self.name);
27 let param_bindings = self.build_parameter_pattern_bindings();
28 let mut pattern_fields = self.build_pattern_fields(¶m_bindings);
29 let has_commands = self.has_commands();
30
31 if has_commands {
32 pattern_fields.push(quote! { sub });
33 }
34
35 let params_init = self.build_parameter_initialization(¶m_bindings, path, has_commands);
36 let nested_match = self.build_nested_match_arms(path, has_commands);
37
38 quote! {
39 Some(#cli_path::Commands::#variant_ident { #(#pattern_fields),* }) => {
40 #params_init
41 #nested_match
42 }
43 }
44 }
45
46 fn build_parameter_pattern_bindings(&self) -> Vec<(syn::Ident, syn::Ident)> {
47 let mut bindings = Vec::new();
48 let mut counter = 1;
49
50 if let Some(ref params) = self.parameters {
51 for field in ¶ms.pstruct.fields {
52 if let Some(field_name) = &field.ident {
53 if !is_generated_field(&field_name.to_string()) {
54 let binding = syn::Ident::new(
55 &format!("p{}", counter),
56 Span::call_site(),
57 );
58 bindings.push((field_name.clone(), binding));
59 counter += 1;
60 }
61 }
62 }
63 }
64
65 bindings
66 }
67
68 fn has_commands(&self) -> bool {
69 !self.tusks.is_empty()
70 || !self.submodules.is_empty()
71 || !self.external_modules.is_empty()
72 }
73
74 fn build_parameter_initialization(
75 &self,
76 bindings: &[(syn::Ident, syn::Ident)],
77 path: &ModulePath,
78 has_commands: bool,
79 ) -> TokenStream {
80 if !has_commands || self.parameters.is_none() {
81 return quote! {};
82 }
83
84 let submod_name = &self.name;
85 let params = self.parameters.as_ref().unwrap();
86 let mut field_inits = Vec::new();
87
88 for field in ¶ms.pstruct.fields {
89 if let Some(field_name) = &field.ident {
90 if field_name == "super_" {
91 field_inits.push(quote! { super_: super_parameters, });
92 } else if field_name == "_phantom_lifetime_marker" {
93 field_inits.push(quote! {
94 _phantom_lifetime_marker: ::std::marker::PhantomData,
95 });
96 } else if let Some((_, binding)) =
97 bindings.iter().find(|(fname, _)| fname == field_name)
98 {
99 field_inits.push(quote! { #field_name: #binding, });
100 }
101 }
102 }
103
104 let params_path = path.super_path_to(submod_name);
105
106 quote! {
107 let super_parameters = ¶meters;
108 let parameters = #params_path::Parameters {
109 #(#field_inits)*
110 };
111 }
112 }
113
114 fn build_nested_match_arms(
115 &self,
116 path: &ModulePath,
117 has_commands: bool,
118 ) -> TokenStream {
119 if !has_commands {
120 return Self::build_no_command_error(path);
121 }
122
123 let new_path = path.join(&self.name.to_string());
124 let nested_arms = self.build_match_arms_recursive(&new_path);
125
126 quote! {
127 match sub {
128 #(#nested_arms)*
129 }
130 }
131 }
132}