@@ -60,10 +60,12 @@ pub(crate) struct ExportMethod {
60
60
pub ( crate ) sig : Signature ,
61
61
pub ( crate ) export_args : ExportArgs ,
62
62
pub ( crate ) optional_args : Option < usize > ,
63
+ pub ( crate ) exist_base_arg : bool ,
63
64
}
64
65
65
66
#[ derive( Clone , Eq , PartialEq , Ord , PartialOrd , Hash , Debug , Default ) ]
66
67
pub ( crate ) struct ExportArgs {
68
+ pub ( crate ) is_old_syntax : bool ,
67
69
pub ( crate ) rpc_mode : Option < RpcMode > ,
68
70
pub ( crate ) name_override : Option < String > ,
69
71
pub ( crate ) is_deref_return : bool ,
@@ -80,7 +82,7 @@ pub(crate) fn derive_methods(item_impl: ItemImpl) -> TokenStream2 {
80
82
let methods = export
81
83
. methods
82
84
. into_iter ( )
83
- . map ( |ExportMethod { sig, export_args , optional_args} | {
85
+ . map ( |ExportMethod { sig, export_args, optional_args, exist_base_arg } | {
84
86
let sig_span = sig. ident . span ( ) ;
85
87
86
88
let name = sig. ident ;
@@ -93,10 +95,18 @@ pub(crate) fn derive_methods(item_impl: ItemImpl) -> TokenStream2 {
93
95
94
96
let arg_count = sig. inputs . len ( ) ;
95
97
96
- if arg_count < 2 {
98
+ if arg_count == 0 {
97
99
return syn:: Error :: new (
98
100
sig_span,
99
- "exported methods must take self and owner as arguments" ,
101
+ "exported methods must take self parameter" ,
102
+ )
103
+ . to_compile_error ( ) ;
104
+ }
105
+
106
+ if export_args. is_old_syntax && !exist_base_arg {
107
+ return syn:: Error :: new (
108
+ sig_span,
109
+ "exported methods must take second parameter" ,
100
110
)
101
111
. to_compile_error ( ) ;
102
112
}
@@ -106,7 +116,7 @@ pub(crate) fn derive_methods(item_impl: ItemImpl) -> TokenStream2 {
106
116
let max_optional = arg_count - 2 ; // self and owner
107
117
if count > max_optional {
108
118
let message = format ! (
109
- "there can be at most {} optional arguments , got {}" ,
119
+ "there can be at most {} optional parameters , got {}" ,
110
120
max_optional, count,
111
121
) ;
112
122
return syn:: Error :: new ( sig_span, message) . to_compile_error ( ) ;
@@ -121,13 +131,17 @@ pub(crate) fn derive_methods(item_impl: ItemImpl) -> TokenStream2 {
121
131
122
132
let args = sig. inputs . iter ( ) . enumerate ( ) . map ( |( n, arg) | {
123
133
let span = arg. span ( ) ;
124
- if n < arg_count - optional_args {
134
+ if exist_base_arg && n == 1 {
135
+ quote_spanned ! ( span => #[ base] #arg , )
136
+ }
137
+ else if n < arg_count - optional_args {
125
138
quote_spanned ! ( span => #arg , )
126
139
} else {
127
140
quote_spanned ! ( span => #[ opt] #arg , )
128
141
}
129
142
} ) ;
130
143
144
+ // See gdnative-core::export::deprecated_reference_return!()
131
145
let deprecated = if let syn:: ReturnType :: Type ( _, ty) = & sig. output {
132
146
if !is_deref_return && matches ! ( * * ty, syn:: Type :: Reference ( _) ) {
133
147
quote_spanned ! ( ret_span=> :: gdnative:: export:: deprecated_reference_return!( ) ; )
@@ -208,9 +222,23 @@ fn impl_gdnative_expose(ast: ItemImpl) -> (ItemImpl, ClassMethodExport) {
208
222
. last ( )
209
223
. map ( |i| i. ident . to_string ( ) ) ;
210
224
211
- if let Some ( "export" ) = last_seg. as_deref ( ) {
212
- let mut _export_args = export_args. get_or_insert_with ( ExportArgs :: default) ;
225
+ let ( is_export, is_old_syntax) = if let Some ( "export" ) = last_seg. as_deref ( )
226
+ {
227
+ ( true , true )
228
+ } else if let Some ( "method" ) = last_seg. as_deref ( ) {
229
+ ( true , false )
230
+ } else {
231
+ ( false , false )
232
+ } ;
233
+
234
+ if is_export {
213
235
use syn:: { punctuated:: Punctuated , Lit , Meta , NestedMeta } ;
236
+ let mut export_args =
237
+ export_args. get_or_insert_with ( ExportArgs :: default) ;
238
+ export_args. is_old_syntax = is_old_syntax;
239
+
240
+ // Codes like #[macro(path, name = "value")] are accepted.
241
+ // Codes like #[path], #[name = "value"] or #[macro("lit")] are not accepted.
214
242
let nested_meta_iter = match attr. parse_meta ( ) {
215
243
Err ( err) => {
216
244
errors. push ( err) ;
@@ -260,7 +288,7 @@ fn impl_gdnative_expose(ast: ItemImpl) -> (ItemImpl, ClassMethodExport) {
260
288
Some ( Lit :: Str ( str) ) => {
261
289
let value = str. value ( ) ;
262
290
if let Some ( mode) = RpcMode :: parse ( value. as_str ( ) ) {
263
- if _export_args . rpc_mode . replace ( mode) . is_some ( ) {
291
+ if export_args . rpc_mode . replace ( mode) . is_some ( ) {
264
292
errors. push ( syn:: Error :: new (
265
293
nested_meta. span ( ) ,
266
294
"rpc mode was set more than once" ,
@@ -290,7 +318,11 @@ fn impl_gdnative_expose(ast: ItemImpl) -> (ItemImpl, ClassMethodExport) {
290
318
) ) ;
291
319
}
292
320
Some ( Lit :: Str ( str) ) => {
293
- if _export_args. name_override . replace ( str. value ( ) ) . is_some ( ) {
321
+ if export_args
322
+ . name_override
323
+ . replace ( str. value ( ) )
324
+ . is_some ( )
325
+ {
294
326
errors. push ( syn:: Error :: new (
295
327
nested_meta. span ( ) ,
296
328
"name was set more than once" ,
@@ -311,13 +343,13 @@ fn impl_gdnative_expose(ast: ItemImpl) -> (ItemImpl, ClassMethodExport) {
311
343
nested_meta. span ( ) ,
312
344
"value for deref_return parameter is not valid" ,
313
345
) ) ;
314
- } else if _export_args . is_deref_return {
346
+ } else if export_args . is_deref_return {
315
347
errors. push ( syn:: Error :: new (
316
348
nested_meta. span ( ) ,
317
349
"deref_return was apply more than once" ,
318
350
) ) ;
319
351
} else {
320
- _export_args . is_deref_return = true ;
352
+ export_args . is_deref_return = true ;
321
353
}
322
354
} else {
323
355
let msg = format ! (
@@ -336,6 +368,7 @@ fn impl_gdnative_expose(ast: ItemImpl) -> (ItemImpl, ClassMethodExport) {
336
368
337
369
if let Some ( export_args) = export_args. take ( ) {
338
370
let mut optional_args = None ;
371
+ let mut exist_base_arg = false ;
339
372
340
373
for ( n, arg) in method. sig . inputs . iter_mut ( ) . enumerate ( ) {
341
374
let attrs = match arg {
@@ -344,39 +377,57 @@ fn impl_gdnative_expose(ast: ItemImpl) -> (ItemImpl, ClassMethodExport) {
344
377
} ;
345
378
346
379
let mut is_optional = false ;
380
+ let mut is_base = false ;
347
381
348
382
attrs. retain ( |attr| {
349
383
if attr. path . is_ident ( "opt" ) {
350
384
is_optional = true ;
351
385
false
386
+ } else if attr. path . is_ident ( "base" ) {
387
+ is_base = true ;
388
+ false
352
389
} else {
353
390
true
354
391
}
355
392
} ) ;
356
393
394
+ // In the old syntax, the second parameter is always the base parameter.
395
+ if export_args. is_old_syntax && n == 1 {
396
+ is_base = true ;
397
+ }
398
+
357
399
if is_optional {
358
400
if n < 2 {
359
401
errors. push ( syn:: Error :: new (
360
402
arg. span ( ) ,
361
403
"self or owner cannot be optional" ,
362
404
) ) ;
363
- continue ;
405
+ } else {
406
+ * optional_args. get_or_insert ( 0 ) += 1 ;
364
407
}
365
-
366
- * optional_args. get_or_insert ( 0 ) += 1 ;
367
408
} else if optional_args. is_some ( ) {
368
409
errors. push ( syn:: Error :: new (
369
410
arg. span ( ) ,
370
411
"cannot add required parameters after optional ones" ,
371
412
) ) ;
372
- continue ;
413
+ }
414
+
415
+ if is_base {
416
+ exist_base_arg = true ;
417
+ if n != 1 {
418
+ errors. push ( syn:: Error :: new (
419
+ arg. span ( ) ,
420
+ "base must be the second parameter." ,
421
+ ) ) ;
422
+ }
373
423
}
374
424
}
375
425
376
426
methods_to_export. push ( ExportMethod {
377
427
sig : method. sig . clone ( ) ,
378
428
export_args,
379
429
optional_args,
430
+ exist_base_arg,
380
431
} ) ;
381
432
}
382
433
@@ -423,7 +474,7 @@ fn impl_gdnative_expose(ast: ItemImpl) -> (ItemImpl, ClassMethodExport) {
423
474
continue ;
424
475
}
425
476
426
- // remove "mut" from arguments .
477
+ // remove "mut" from parameters .
427
478
// give every wildcard a (hopefully) unique name.
428
479
method
429
480
. sig
0 commit comments