tusks_lib/codegen/handle_matches/arms/
function.rs1use proc_macro2::{Span, TokenStream};
2use quote::quote;
3
4use crate::codegen::module_path::ModulePath;
5use crate::codegen::util::enum_util::to_variant_ident;
6use crate::codegen::util::field_util::is_generated_field;
7use crate::{TusksModule, models::Tusk};
8
9fn build_result_ok_handler(ok_ty: &syn::Type, val: TokenStream) -> TokenStream {
11 if Tusk::is_u8_type(ok_ty) {
12 quote! { Some(#val) }
13 } else if Tusk::is_option_u8_type(ok_ty) {
14 quote! { #val }
15 } else {
16 quote! { let _ = #val; None }
18 }
19}
20
21impl TusksModule {
22 pub fn build_function_match_arm(
31 &self,
32 tusk: &Tusk,
33 cli_path: &TokenStream,
34 path: &ModulePath,
35 ) -> TokenStream {
36 let variant_ident = to_variant_ident(&tusk.func.sig.ident);
37 let pattern_bindings = self.build_pattern_bindings(tusk);
38 let pattern_fields = self.build_pattern_fields(&pattern_bindings);
39 let function_call = self.build_function_call(tusk, &pattern_bindings, path, false, false);
40
41 quote! {
42 Some(#cli_path::Commands::#variant_ident { #(#pattern_fields),* }) => {
43 #function_call
44 }
45 }
46 }
47
48 pub fn build_default_function_match_arm(
49 &self,
50 tusk: &Tusk,
51 path: &ModulePath,
52 is_external_subcommand_case: bool,
53 ) -> TokenStream {
54 let pattern_bindings = self.build_pattern_bindings(tusk);
55 let function_call = self.build_function_call(
56 tusk, &pattern_bindings, path, true, is_external_subcommand_case,
57 );
58
59 quote! {
60 None => {
61 #function_call
62 }
63 }
64 }
65
66 pub fn build_external_subcommand_match_arm(
67 &self,
68 tusk: &Tusk,
69 path: &ModulePath,
70 ) -> TokenStream {
71 let pattern_bindings = self.build_pattern_bindings(tusk);
72 let function_call = self.build_function_call(
73 tusk, &pattern_bindings, path, false, true,
74 );
75
76 let cli_path = path.cli_path();
77
78 quote! {
79 Some(#cli_path::Commands::ClapExternalSubcommand(external_subcommand_args)) => {
80 #function_call
81 }
82 }
83 }
84
85 fn build_function_call(
86 &self,
87 tusk: &Tusk,
88 pattern_bindings: &[(syn::Ident, syn::Ident)],
89 path: &ModulePath,
90 is_default_case: bool,
91 is_external_subcommand_case: bool,
92 ) -> TokenStream {
93 let func_args = self.build_function_arguments(
94 tusk, pattern_bindings, is_default_case, is_external_subcommand_case,
95 );
96 let func_name = &tusk.func.sig.ident;
97 let func_path = path.super_path_to(func_name);
98 let maybe_await = if tusk.is_async { quote! { .await } } else { quote! {} };
99
100 let call = quote! { #func_path(#(#func_args),*)#maybe_await };
101
102 match &tusk.func.sig.output {
103 syn::ReturnType::Default => {
104 quote! { #call; None }
105 }
106 syn::ReturnType::Type(_, ty) => {
107 if let Some(ok_ty) = Tusk::result_ok_type(ty) {
108 let ok_handler = build_result_ok_handler(ok_ty, quote! { __ok_val });
110 quote! {
111 match #call {
112 Ok(__ok_val) => { #ok_handler }
113 Err(__err) => {
114 eprintln!("Error: {}", __err);
115 Some(1)
116 }
117 }
118 }
119 } else if Tusk::is_u8_type(ty) {
120 quote! { Some(#call) }
121 } else if Tusk::is_option_u8_type(ty) {
122 quote! { #call }
123 } else {
124 quote! { None }
125 }
126 }
127 }
128 }
129
130 fn build_pattern_bindings(&self, tusk: &Tusk) -> Vec<(syn::Ident, syn::Ident)> {
133 let skip = if self.tusk_has_parameters_arg(tusk) { 1 } else { 0 };
134 let mut bindings = Vec::new();
135 let mut counter = 1;
136
137 for param in tusk.func.sig.inputs.iter().skip(skip) {
138 if let syn::FnArg::Typed(pat_type) = param
139 && let syn::Pat::Ident(pat_ident) = &*pat_type.pat {
140 let binding = syn::Ident::new(&format!("p{}", counter), Span::call_site());
141 bindings.push((pat_ident.ident.clone(), binding));
142 counter += 1;
143 }
144 }
145
146 bindings
147 }
148
149 pub fn build_pattern_fields(
152 &self,
153 pattern_bindings: &[(syn::Ident, syn::Ident)],
154 ) -> Vec<TokenStream> {
155 pattern_bindings
156 .iter()
157 .filter(|(name, _)| !is_generated_field(&name.to_string()))
158 .map(|(name, binding)| quote! { #name: #binding })
159 .collect()
160 }
161
162 fn build_function_arguments(
163 &self,
164 tusk: &Tusk,
165 pattern_bindings: &[(syn::Ident, syn::Ident)],
166 is_default_case: bool,
167 is_external_subcommand_case: bool,
168 ) -> Vec<TokenStream> {
169 let has_params_arg = self.tusk_has_parameters_arg(tusk);
170 let mut func_args = Vec::new();
171
172 let mut number_of_non_params_args = tusk.func.sig.inputs.len();
173 if has_params_arg {
174 func_args.push(quote! { ¶meters });
175 number_of_non_params_args -= 1;
176 }
177
178 if is_default_case {
179 if is_external_subcommand_case {
180 func_args.push(quote! { Vec::new() });
181 }
182 return func_args;
183 }
184
185 if is_external_subcommand_case && number_of_non_params_args > 0 {
186 func_args.push(quote! { external_subcommand_args.clone() });
187 return func_args;
188 }
189
190 for (_, binding_name) in pattern_bindings {
191 func_args.push(quote! { #binding_name.clone() });
192 }
193
194 func_args
195 }
196}