tusks_lib/codegen/handle_matches/arms/
function.rs1use proc_macro2::{Span, TokenStream};
2use quote::quote;
3
4use crate::codegen::util::enum_util::convert_function_to_enum_variant;
5
6use crate::{TusksModule, models::Tusk};
7
8impl TusksModule {
9 pub fn build_function_match_arm(
29 &self,
30 tusk: &Tusk,
31 cli_path: &TokenStream,
32 path: &[&str]
33 ) -> TokenStream {
34 let variant_ident = convert_function_to_enum_variant(&tusk.func.sig.ident);
35 let pattern_bindings = self.build_pattern_bindings(tusk);
36 let pattern_fields = self.build_pattern_fields(&pattern_bindings);
37 let function_call = self.build_function_call(
38 tusk,
39 &pattern_bindings,
40 path,
41 false,
42 false
43 );
44
45 quote! {
46 Some(#cli_path::Commands::#variant_ident { #(#pattern_fields),* }) => {
47 #function_call
48 }
49 }
50 }
51
52 pub fn build_default_function_match_arm(
53 &self,
54 tusk: &Tusk,
55 path: &[&str],
56 is_external_subcommand_case: bool
57 ) -> TokenStream {
58 let pattern_bindings = self.build_pattern_bindings(tusk);
59 let function_call = self.build_function_call(
60 tusk,
61 &pattern_bindings,
62 path,
63 true,
64 is_external_subcommand_case
65 );
66
67 quote! {
68 None => {
69 #function_call
70 }
71 }
72 }
73
74 pub fn build_external_subcommand_match_arm(&self, tusk: &Tusk, path: &[&str]) -> TokenStream
75 {
76 let pattern_bindings = self.build_pattern_bindings(tusk);
77 let function_call = self.build_function_call(
78 tusk,
79 &pattern_bindings,
80 path,
81 false,
82 true
83 );
84
85 quote! {
86 Some(cli::Commands::ClapExternalSubcommand(external_subcommand_args)) => {
87 #function_call
88 }
89 }
90 }
91
92 fn build_function_call(
94 &self,
95 tusk: &Tusk,
96 pattern_bindings: &[(syn::Ident, syn::Ident)],
97 path: &[&str],
98 is_default_case: bool,
99 is_external_subcommand_case: bool
100 ) -> TokenStream {
101 let func_args = self.build_function_arguments(
102 tusk,
103 pattern_bindings,
104 is_default_case,
105 is_external_subcommand_case
106 );
107 let func_path = self.build_function_path(tusk, path);
108
109 match &tusk.func.sig.output {
110 syn::ReturnType::Default => {
111 quote! { #func_path(#(#func_args),*); None }
113 }
114 syn::ReturnType::Type(_, ty) => {
115 if Tusk::is_u8_type(ty) {
116 quote! { Some(#func_path(#(#func_args),*)) }
118 } else if Tusk::is_option_u8_type(ty) {
119 quote! { #func_path(#(#func_args),*) }
121 } else {
122 quote! { None }
124 }
125 }
126 }
127 }
128
129 fn build_pattern_bindings(&self, tusk: &Tusk) -> Vec<(syn::Ident, syn::Ident)> {
139 let has_params_arg = self.tusk_has_parameters_arg(tusk);
140 let skip = if has_params_arg { 1 } else { 0 };
141
142 let mut pattern_bindings = Vec::new();
143 let mut param_counter = 1;
144
145 for param in tusk.func.sig.inputs.iter().skip(skip) {
146 if let syn::FnArg::Typed(pat_type) = param {
147 if let syn::Pat::Ident(pat_ident) = &*pat_type.pat {
148 let field_name = &pat_ident.ident;
149 let binding_name = syn::Ident::new(
150 &format!("p{}", param_counter),
151 Span::call_site()
152 );
153 pattern_bindings.push((field_name.clone(), binding_name.clone()));
154 param_counter += 1;
155 }
156 }
157 }
158
159 pattern_bindings
160 }
161
162 pub fn build_pattern_fields(
171 &self,
172 pattern_bindings: &[(syn::Ident, syn::Ident)]
173 ) -> Vec<TokenStream> {
174 pattern_bindings.iter()
175 .filter(|(field_name, _)| {
176 let field_name_str = field_name.to_string();
177 field_name_str != "_phantom_lifetime_marker"
178 })
179 .map(|(field_name, binding_name)| {
180 quote! { #field_name: #binding_name }
181 })
182 .collect()
183 }
184
185 fn build_function_arguments(
195 &self,
196 tusk: &Tusk,
197 pattern_bindings: &[(syn::Ident, syn::Ident)],
198 is_default_case: bool,
199 is_external_subcommand_case: bool
200 ) -> Vec<TokenStream> {
201 let has_params_arg = self.tusk_has_parameters_arg(tusk);
202 let mut func_args = Vec::new();
203
204 let mut number_of_non_params_args = tusk.func.sig.inputs.len();
205 if has_params_arg {
206 func_args.push(quote! { ¶meters });
207 number_of_non_params_args -= 1;
208 }
209
210 if is_default_case {
211 if is_external_subcommand_case {
212 func_args.push(quote! { Vec::new() });
213 }
214 return func_args;
215 }
216
217 if is_external_subcommand_case && number_of_non_params_args > 0 {
218 func_args.push(quote! { external_subcommand_args.clone() });
219 return func_args;
220 }
221
222 for (_, binding_name) in pattern_bindings {
223 func_args.push(quote! { #binding_name.clone() });
224 }
225
226 func_args
227 }
228
229 fn build_function_path(&self, tusk: &Tusk, path: &[&str]) -> TokenStream {
237 let func_name = &tusk.func.sig.ident;
238
239 if path.is_empty() {
240 quote! { super::#func_name }
241 } else {
242 let path_idents: Vec<_> = path.iter()
243 .map(|p| syn::Ident::new(p, Span::call_site()))
244 .collect();
245 quote! { super::#(#path_idents)::*::#func_name }
246 }
247 }
248}