|
7 | 7 |
|
8 | 8 | use crate::generator::default_parameters;
|
9 | 9 | use crate::models::domain::{FnParam, FnQualifier, Function, RustTy};
|
| 10 | +use crate::special_cases; |
10 | 11 | use crate::util::safe_ident;
|
11 |
| -use proc_macro2::TokenStream; |
| 12 | +use proc_macro2::{Ident, TokenStream}; |
12 | 13 | use quote::{format_ident, quote};
|
13 | 14 |
|
14 | 15 | pub struct FnReceiver {
|
@@ -83,6 +84,22 @@ impl FnDefinitions {
|
83 | 84 | }
|
84 | 85 | }
|
85 | 86 |
|
| 87 | +// Gathers multiple token vectors related to function parameters. |
| 88 | +#[derive(Default)] |
| 89 | +pub struct FnParamTokens { |
| 90 | + pub params: Vec<TokenStream>, |
| 91 | + pub param_types: Vec<TokenStream>, |
| 92 | + pub arg_names: Vec<TokenStream>, |
| 93 | +} |
| 94 | + |
| 95 | +impl FnParamTokens { |
| 96 | + pub fn push_regular(&mut self, param_name: &Ident, param_ty: &RustTy) { |
| 97 | + self.params.push(quote! { #param_name: #param_ty }); |
| 98 | + self.arg_names.push(quote! { #param_name }); |
| 99 | + self.param_types.push(quote! { #param_ty }); |
| 100 | + } |
| 101 | +} |
| 102 | + |
86 | 103 | pub fn make_function_definition(
|
87 | 104 | sig: &dyn Function,
|
88 | 105 | code: &FnCode,
|
@@ -119,12 +136,19 @@ pub fn make_function_definition(
|
119 | 136 | (TokenStream::new(), TokenStream::new())
|
120 | 137 | };
|
121 | 138 |
|
122 |
| - let [params, param_types, arg_names] = make_params_exprs( |
123 |
| - sig.params().iter(), |
124 |
| - sig.is_virtual(), |
125 |
| - !has_default_params, // For *_full function, we don't need impl AsObjectArg<T> parameters |
126 |
| - !has_default_params, // or arg.as_object_arg() calls. |
127 |
| - ); |
| 139 | + let FnParamTokens { |
| 140 | + params, |
| 141 | + param_types, |
| 142 | + arg_names, |
| 143 | + } = if sig.is_virtual() { |
| 144 | + make_params_exprs_virtual(sig.params().iter(), sig) |
| 145 | + } else { |
| 146 | + make_params_exprs( |
| 147 | + sig.params().iter(), |
| 148 | + !has_default_params, // For *_full function, we don't need impl AsObjectArg<T> parameters |
| 149 | + !has_default_params, // or arg.as_object_arg() calls. |
| 150 | + ) |
| 151 | + }; |
128 | 152 |
|
129 | 153 | let rust_function_name_str = sig.name();
|
130 | 154 |
|
@@ -200,9 +224,11 @@ pub fn make_function_definition(
|
200 | 224 | // This can be made more complex if ever necessary.
|
201 | 225 |
|
202 | 226 | // A function() may call try_function(), its arguments should not have .as_object_arg().
|
203 |
| - let [_, _, arg_names_without_asarg] = make_params_exprs( |
| 227 | + let FnParamTokens { |
| 228 | + arg_names: arg_names_without_asarg, |
| 229 | + .. |
| 230 | + } = make_params_exprs( |
204 | 231 | sig.params().iter(),
|
205 |
| - false, |
206 | 232 | !has_default_params, // For *_full function, we don't need impl AsObjectArg<T> parameters
|
207 | 233 | false, // or arg.as_object_arg() calls.
|
208 | 234 | );
|
@@ -307,54 +333,81 @@ pub fn make_vis(is_private: bool) -> TokenStream {
|
307 | 333 | // ----------------------------------------------------------------------------------------------------------------------------------------------
|
308 | 334 | // Implementation
|
309 | 335 |
|
310 |
| -// Method could possibly be split -- only one invocation uses all 3 return values, the rest uses only index [0] or [2]. |
| 336 | +/// For non-virtual functions, returns the parameter declarations, type tokens, and names. |
311 | 337 | pub(crate) fn make_params_exprs<'a>(
|
312 | 338 | method_args: impl Iterator<Item = &'a FnParam>,
|
313 |
| - is_virtual: bool, |
314 | 339 | param_is_impl_asarg: bool,
|
315 | 340 | arg_is_asarg: bool,
|
316 |
| -) -> [Vec<TokenStream>; 3] { |
317 |
| - let mut params = vec![]; |
318 |
| - let mut param_types = vec![]; // or non-generic params |
319 |
| - let mut arg_names = vec![]; |
| 341 | +) -> FnParamTokens { |
| 342 | + let mut ret = FnParamTokens::default(); |
320 | 343 |
|
321 | 344 | for param in method_args {
|
322 | 345 | let param_name = ¶m.name;
|
323 | 346 | let param_ty = ¶m.type_;
|
324 | 347 |
|
325 |
| - // Objects (Gd<T>) use implicit conversions via AsObjectArg. Only use in non-virtual functions. |
326 | 348 | match ¶m.type_ {
|
| 349 | + // Non-virtual functions: Objects (Gd<T>) use implicit conversions via AsObjectArg. |
327 | 350 | RustTy::EngineClass {
|
328 | 351 | object_arg,
|
329 | 352 | impl_as_object_arg,
|
330 | 353 | ..
|
331 |
| - } if !is_virtual => { |
| 354 | + } => { |
332 | 355 | // Parameter declarations in signature: impl AsObjectArg<T>
|
333 | 356 | if param_is_impl_asarg {
|
334 |
| - params.push(quote! { #param_name: #impl_as_object_arg }); |
| 357 | + ret.params.push(quote! { #param_name: #impl_as_object_arg }); |
335 | 358 | } else {
|
336 |
| - params.push(quote! { #param_name: #object_arg }); |
| 359 | + ret.params.push(quote! { #param_name: #object_arg }); |
337 | 360 | }
|
338 | 361 |
|
339 | 362 | // Argument names in function body: arg.as_object_arg() vs. arg
|
340 | 363 | if arg_is_asarg {
|
341 |
| - arg_names.push(quote! { #param_name.as_object_arg() }); |
| 364 | + ret.arg_names.push(quote! { #param_name.as_object_arg() }); |
342 | 365 | } else {
|
343 |
| - arg_names.push(quote! { #param_name }); |
| 366 | + ret.arg_names.push(quote! { #param_name }); |
344 | 367 | }
|
345 | 368 |
|
346 |
| - param_types.push(quote! { #object_arg }); |
| 369 | + ret.param_types.push(quote! { #object_arg }); |
347 | 370 | }
|
348 | 371 |
|
349 |
| - _ => { |
350 |
| - params.push(quote! { #param_name: #param_ty }); |
351 |
| - arg_names.push(quote! { #param_name }); |
352 |
| - param_types.push(quote! { #param_ty }); |
| 372 | + // All other methods and parameter types: standard handling. |
| 373 | + _ => ret.push_regular(param_name, param_ty), |
| 374 | + } |
| 375 | + } |
| 376 | + |
| 377 | + ret |
| 378 | +} |
| 379 | + |
| 380 | +/// For virtual functions, returns the parameter declarations, type tokens, and names. |
| 381 | +pub(crate) fn make_params_exprs_virtual<'a>( |
| 382 | + method_args: impl Iterator<Item = &'a FnParam>, |
| 383 | + function_sig: &dyn Function, |
| 384 | +) -> FnParamTokens { |
| 385 | + let mut ret = FnParamTokens::default(); |
| 386 | + |
| 387 | + for param in method_args { |
| 388 | + let param_name = ¶m.name; |
| 389 | + let param_ty = ¶m.type_; |
| 390 | + |
| 391 | + match ¶m.type_ { |
| 392 | + // Virtual methods accept Option<Gd<T>>, since we don't know whether objects are nullable or required. |
| 393 | + RustTy::EngineClass { .. } |
| 394 | + if !special_cases::is_class_method_param_required( |
| 395 | + function_sig.surrounding_class().unwrap(), |
| 396 | + function_sig.name(), |
| 397 | + param_name, |
| 398 | + ) => |
| 399 | + { |
| 400 | + ret.params.push(quote! { #param_name: Option<#param_ty> }); |
| 401 | + ret.arg_names.push(quote! { #param_name }); |
| 402 | + ret.param_types.push(quote! { #param_ty }); |
353 | 403 | }
|
| 404 | + |
| 405 | + // All other methods and parameter types: standard handling. |
| 406 | + _ => ret.push_regular(param_name, param_ty), |
354 | 407 | }
|
355 | 408 | }
|
356 | 409 |
|
357 |
| - [params, param_types, arg_names] |
| 410 | + ret |
358 | 411 | }
|
359 | 412 |
|
360 | 413 | fn function_uses_pointers(sig: &dyn Function) -> bool {
|
|
0 commit comments