@@ -51,6 +51,7 @@ use quote::TokenStreamExt;
51
51
use crate :: { Entry , HashMap , HashSet } ;
52
52
use std:: borrow:: Cow ;
53
53
use std:: cell:: Cell ;
54
+ use std:: collections:: BTreeMap ;
54
55
use std:: collections:: VecDeque ;
55
56
use std:: fmt:: Write ;
56
57
use std:: iter;
@@ -192,6 +193,12 @@ impl From<DerivableTraits> for Vec<&'static str> {
192
193
}
193
194
}
194
195
196
+ struct VariadicMethodInfo {
197
+ args : Vec < proc_macro2:: TokenStream > ,
198
+ ret : proc_macro2:: TokenStream ,
199
+ exprs : Vec < proc_macro2:: TokenStream > ,
200
+ }
201
+
195
202
struct CodegenResult < ' a > {
196
203
items : Vec < proc_macro2:: TokenStream > ,
197
204
dynamic_items : DynamicItems ,
@@ -239,6 +246,8 @@ struct CodegenResult<'a> {
239
246
/// function name to the number of overloads we have already codegen'd for
240
247
/// that name. This lets us give each overload a unique suffix.
241
248
overload_counters : HashMap < String , u32 > ,
249
+
250
+ variadic_methods : BTreeMap < Ident , VariadicMethodInfo > ,
242
251
}
243
252
244
253
impl < ' a > CodegenResult < ' a > {
@@ -256,6 +265,7 @@ impl<'a> CodegenResult<'a> {
256
265
functions_seen : Default :: default ( ) ,
257
266
vars_seen : Default :: default ( ) ,
258
267
overload_counters : Default :: default ( ) ,
268
+ variadic_methods : Default :: default ( ) ,
259
269
}
260
270
}
261
271
@@ -2485,12 +2495,6 @@ impl MethodCodegen for Method {
2485
2495
return ;
2486
2496
}
2487
2497
2488
- // Do not generate variadic methods, since rust does not allow
2489
- // implementing them, and we don't do a good job at it anyway.
2490
- if signature. is_variadic ( ) {
2491
- return ;
2492
- }
2493
-
2494
2498
let count = {
2495
2499
let count = method_names. entry ( name. clone ( ) ) . or_insert ( 0 ) ;
2496
2500
* count += 1 ;
@@ -2508,13 +2512,10 @@ impl MethodCodegen for Method {
2508
2512
let function_name = ctx. rust_ident ( function_name) ;
2509
2513
let mut args = utils:: fnsig_arguments ( ctx, signature) ;
2510
2514
let mut ret = utils:: fnsig_return_ty ( ctx, signature) ;
2515
+ let is_variadic = signature. is_variadic ( ) ;
2511
2516
2512
- if !self . is_static ( ) && !self . is_constructor ( ) {
2513
- args[ 0 ] = if self . is_const ( ) {
2514
- quote ! { & self }
2515
- } else {
2516
- quote ! { & mut self }
2517
- } ;
2517
+ if is_variadic && ctx. options ( ) . tuple_varargs_len . is_none ( ) {
2518
+ return ;
2518
2519
}
2519
2520
2520
2521
// If it's a constructor, we always return `Self`, and we inject the
@@ -2530,6 +2531,28 @@ impl MethodCodegen for Method {
2530
2531
let mut exprs =
2531
2532
helpers:: ast_ty:: arguments_from_signature ( signature, ctx) ;
2532
2533
2534
+ if is_variadic {
2535
+ let ( last_arg, args) = args. split_last_mut ( ) . unwrap ( ) ;
2536
+ // FIXME (pvdrz): what if this identifier is already being used?
2537
+ * last_arg = quote ! ( var_args: impl VarArgs ) ;
2538
+ result. variadic_methods . insert (
2539
+ function_name. clone ( ) ,
2540
+ VariadicMethodInfo {
2541
+ args : args. to_owned ( ) ,
2542
+ ret : ret. clone ( ) ,
2543
+ exprs : exprs. clone ( ) ,
2544
+ } ,
2545
+ ) ;
2546
+ }
2547
+
2548
+ if !self . is_static ( ) && !self . is_constructor ( ) {
2549
+ args[ 0 ] = if self . is_const ( ) {
2550
+ quote ! { & self }
2551
+ } else {
2552
+ quote ! { & mut self }
2553
+ } ;
2554
+ }
2555
+
2533
2556
let mut stmts = vec ! [ ] ;
2534
2557
2535
2558
// If it's a constructor, we need to insert an extra parameter with a
@@ -2563,8 +2586,15 @@ impl MethodCodegen for Method {
2563
2586
} ;
2564
2587
} ;
2565
2588
2566
- let call = quote ! {
2567
- #function_name ( #( #exprs ) , * )
2589
+ let call = if is_variadic {
2590
+ let function_name = quote:: format_ident!( "call_{}" , function_name) ;
2591
+ quote ! {
2592
+ var_args. #function_name( #( #exprs ) , * )
2593
+ }
2594
+ } else {
2595
+ quote ! {
2596
+ #function_name ( #( #exprs ) , * )
2597
+ }
2568
2598
} ;
2569
2599
2570
2600
stmts. push ( call) ;
@@ -4508,6 +4538,10 @@ pub(crate) fn codegen(
4508
4538
result. push ( dynamic_items_tokens) ;
4509
4539
}
4510
4540
4541
+ if let Some ( max_len) = context. options ( ) . tuple_varargs_len {
4542
+ utils:: generate_varargs_trait ( max_len, & mut result) ;
4543
+ }
4544
+
4511
4545
postprocessing:: postprocessing ( result. items , context. options ( ) )
4512
4546
} )
4513
4547
}
@@ -5047,4 +5081,77 @@ pub mod utils {
5047
5081
5048
5082
true
5049
5083
}
5084
+
5085
+ pub ( super ) fn generate_varargs_trait (
5086
+ max_len : usize ,
5087
+ result : & mut super :: CodegenResult ,
5088
+ ) {
5089
+ // This will hold the identifiers to be used for the fields of the tuples `t0, ..., tn` as
5090
+ // well as the identifiers of the type parameters for each field type of the tuples `T0, ..., TN`.
5091
+ // FIXME (pvdrz): what if these identifiers are already in use?
5092
+ let ( fields, params) : ( Vec < _ > , Vec < _ > ) = ( 0 ..max_len)
5093
+ . map ( |len| {
5094
+ (
5095
+ quote:: format_ident!( "t{}" , len) ,
5096
+ quote:: format_ident!( "T{}" , len) ,
5097
+ )
5098
+ } )
5099
+ . unzip ( ) ;
5100
+
5101
+ // This will hold the methods to be declared in the `VarArgs` trait as well as the
5102
+ // bodies of the implementations of such methods for each tuple length.
5103
+ let ( trait_method_decls, trait_method_impl_fns) : ( Vec < _ > , Vec < _ > ) =
5104
+ std:: mem:: take ( & mut result. variadic_methods )
5105
+ . into_iter ( )
5106
+ . map ( |( name, info) | {
5107
+ let super :: VariadicMethodInfo { args, ret, exprs } = info;
5108
+
5109
+ // The name of the `VarArgs` trait method associated with this method.
5110
+ // FIXME (pvdrz): what these identifiers are already in use?
5111
+ let trait_method_name =
5112
+ quote:: format_ident!( "call_{}" , name) ;
5113
+
5114
+ // The declaration of the `VarArgs` trait method associated with this method.
5115
+ let trait_method_decl = quote ! {
5116
+ unsafe fn #trait_method_name( self , #( #args) , * ) #ret
5117
+ } ;
5118
+
5119
+ // The implementations of the `VarArgs` trait method associated with this
5120
+ // method for each tuple length.
5121
+ let trait_method_impls = ( 0 ..=fields. len ( ) )
5122
+ . map ( |index| {
5123
+ let fields = & fields[ ..index] ;
5124
+ quote ! {
5125
+ #trait_method_decl {
5126
+ let ( #( #fields, ) * ) = self ;
5127
+ #name( #( #exprs) , * , #( #fields) , * )
5128
+ }
5129
+ }
5130
+ } )
5131
+ . collect :: < Vec < _ > > ( ) ;
5132
+
5133
+ ( trait_method_decl, trait_method_impls)
5134
+ } )
5135
+ . unzip ( ) ;
5136
+
5137
+ // Push the trait with the method declarations.
5138
+ result. items . push ( quote ! {
5139
+ pub trait VarArgs {
5140
+ #( #trait_method_decls; ) *
5141
+ }
5142
+ } ) ;
5143
+
5144
+ for index in 0 ..=params. len ( ) {
5145
+ let params = & params[ ..index] ;
5146
+ let methods =
5147
+ trait_method_impl_fns. iter ( ) . map ( |impls| & impls[ index] ) ;
5148
+
5149
+ // Push the implementation the trait for each tuple.
5150
+ result. items . push ( quote ! {
5151
+ impl <#( #params) , * > VarArgs for ( #( #params, ) * ) {
5152
+ #( #methods) *
5153
+ }
5154
+ } ) ;
5155
+ }
5156
+ }
5050
5157
}
0 commit comments