1
1
//! Method registration
2
2
3
3
use std:: borrow:: Cow ;
4
- use std:: fmt;
5
4
use std:: marker:: PhantomData ;
5
+ use std:: { fmt, ops} ;
6
6
7
7
use crate :: core_types:: { FromVariant , FromVariantError , Variant } ;
8
8
use crate :: export:: class:: NativeClass ;
@@ -209,17 +209,45 @@ impl<C: NativeClass, F: StaticArgsMethod<C>> Method<C> for StaticArgs<F> {
209
209
}
210
210
211
211
/// Safe interface to a list of borrowed method arguments with a convenient API
212
- /// for common operations with them. Can also be used as an iterator.
212
+ /// for common operations with them.
213
+ ///
214
+ /// **Note:** the `impl Iterator` is deprecated, `Varargs` itself should not be treated as a consumable iterator.
215
+ /// Instead, use [`Self::as_slice()`].
216
+ ///
217
+ /// This type can be destructured into tuples:
218
+ /// ```no_run
219
+ /// use gdnative::prelude::*;
220
+ /// use gdnative::export::Varargs;
221
+ ///
222
+ /// #[derive(NativeClass)]
223
+ /// #[no_constructor]
224
+ /// struct MyClass {}
225
+ ///
226
+ /// struct CalcMethod;
227
+ /// impl Method<MyClass> for CalcMethod {
228
+ /// fn call(
229
+ /// &self,
230
+ /// _this: TInstance<'_, MyClass>,
231
+ /// args: Varargs<'_>,
232
+ /// ) -> Variant {
233
+ /// // Destructure via try_into():
234
+ /// let (a, b): (i64, i64) = args.try_into().expect("signature mismatch");
235
+ /// let ret = a * b;
236
+ /// ret.to_variant()
237
+ /// }
238
+ /// }
239
+ /// ```
213
240
pub struct Varargs < ' a > {
214
241
idx : usize ,
215
- iter : std:: slice:: Iter < ' a , & ' a Variant > ,
242
+ args : & ' a [ & ' a Variant ] ,
243
+ offset_index : usize ,
216
244
}
217
245
218
246
impl < ' a > Varargs < ' a > {
219
247
/// Returns the amount of arguments left.
220
248
#[ inline]
221
249
pub fn len ( & self ) -> usize {
222
- self . iter . len ( )
250
+ self . args . len ( ) - self . idx
223
251
}
224
252
225
253
#[ inline]
@@ -250,7 +278,7 @@ impl<'a> Varargs<'a> {
250
278
/// Returns the remaining arguments as a slice of `Variant`s.
251
279
#[ inline]
252
280
pub fn as_slice ( & self ) -> & ' a [ & ' a Variant ] {
253
- self . iter . as_slice ( )
281
+ self . args
254
282
}
255
283
256
284
/// Discard the rest of the arguments, and return an error if there is any.
@@ -284,7 +312,87 @@ impl<'a> Varargs<'a> {
284
312
let args = std:: mem:: transmute :: < & [ * mut sys:: godot_variant ] , & [ & Variant ] > ( args) ;
285
313
Self {
286
314
idx : 0 ,
287
- iter : args. iter ( ) ,
315
+ args,
316
+ offset_index : 0 ,
317
+ }
318
+ }
319
+
320
+ /// Check the length of arguments.
321
+ ///
322
+ /// See [`Self::get()`] or [`Self::get_opt()`] for examples.
323
+ ///
324
+ /// # Errors
325
+ /// Returns an [`VarargsError::InvalidLength`] if the length of arguments is outside the specified range.
326
+ #[ inline]
327
+ pub fn check_length ( & self , expected : impl Into < IndexBounds > ) -> Result < ( ) , VarargsError > {
328
+ let passed = self . args . len ( ) ;
329
+ let expected = expected. into ( ) ;
330
+ if expected. contains ( passed) {
331
+ Ok ( ( ) )
332
+ } else {
333
+ // Note: cannot use Box<dyn RangeBounds<usize>> because trait is not object-safe due to _unrelated_ method contains()
334
+ Err ( VarargsError :: InvalidLength {
335
+ length : passed,
336
+ expected,
337
+ } )
338
+ }
339
+ }
340
+
341
+ /// Returns the type-converted value at the specified argument position.
342
+ ///
343
+ /// # Errors
344
+ /// Returns a [`VarargsError::InvalidArgumentType`] if the conversion fails or the argument is not set.
345
+ ///
346
+ /// # Examples
347
+ /// ```
348
+ /// # fn call(args: gdnative::export::Varargs) -> Result<(), Box<dyn std::error::Error>> {
349
+ /// args.check_length(2)?;
350
+ /// let a: usize = args.get(0)?;
351
+ /// let rest: i64 = args.get(1)?;
352
+ /// # Ok(())
353
+ /// # }
354
+ /// ```
355
+ #[ inline]
356
+ pub fn get < T : FromVariant > ( & self , index : usize ) -> Result < T , VarargsError > {
357
+ // Note: disregards iterator offset, since that representation is deprecated
358
+
359
+ match self . args . get ( index) {
360
+ Some ( v) => match T :: from_variant ( v) {
361
+ Ok ( ok) => Ok ( ok) ,
362
+ Err ( error) => Err ( VarargsError :: InvalidArgumentType { index, error } ) ,
363
+ } ,
364
+ None => {
365
+ let error = FromVariantError :: Custom ( "Argument is not set" . to_owned ( ) ) ;
366
+ Err ( VarargsError :: InvalidArgumentType { index, error } )
367
+ }
368
+ }
369
+ }
370
+
371
+ /// Returns the type-converted value at the specified argument position.
372
+ /// Returns `None` if the argument is not set.
373
+ ///
374
+ /// # Errors
375
+ /// Returns a [`VarargsError::InvalidArgumentType`] if the conversion fails.
376
+ ///
377
+ /// # Examples
378
+ /// ```
379
+ /// # fn call(args: gdnative::export::Varargs) -> Result<(), Box<dyn std::error::Error>> {
380
+ /// args.check_length(1..=2)?;
381
+ /// let a: usize = args.get(0)?;
382
+ /// let rest: i64 = args.get_opt(1)?.unwrap_or(72);
383
+ /// # Ok(())
384
+ /// # }
385
+ /// ```
386
+ #[ inline]
387
+ pub fn get_opt < T : FromVariant > ( & self , index : usize ) -> Result < Option < T > , VarargsError > {
388
+ // Note: disregards iterator offset, since that representation is deprecated
389
+
390
+ match self . args . get ( index) {
391
+ Some ( v) => match T :: from_variant ( v) {
392
+ Ok ( ok) => Ok ( Some ( ok) ) ,
393
+ Err ( error) => Err ( VarargsError :: InvalidArgumentType { index, error } ) ,
394
+ } ,
395
+ None => Ok ( None ) ,
288
396
}
289
397
}
290
398
}
@@ -293,7 +401,197 @@ impl<'a> Iterator for Varargs<'a> {
293
401
type Item = & ' a Variant ;
294
402
#[ inline]
295
403
fn next ( & mut self ) -> Option < Self :: Item > {
296
- self . iter . next ( ) . copied ( )
404
+ let ret = self . args . get ( self . idx ) ;
405
+ ret. map ( |& v| {
406
+ self . idx += 1 ;
407
+ v
408
+ } )
409
+ }
410
+ }
411
+
412
+ // Return a second token.
413
+ macro_rules! replace_expr {
414
+ ( $_t: tt $sub: expr) => {
415
+ $sub
416
+ } ;
417
+ }
418
+
419
+ // Count parameters.
420
+ macro_rules! count_tts {
421
+ ( $( $tts: tt) * ) => {
422
+ 0usize $( + replace_expr!( $tts 1usize ) ) *
423
+ } ;
424
+ }
425
+
426
+ // Convert from Varargs to tuples, implement traits.
427
+ macro_rules! varargs_into_tuple {
428
+ ( $( $params: ident) ,* ) => {
429
+ impl <' a, $( $params: FromVariant ) ,* > std:: convert:: TryFrom <Varargs <' a>> for ( $( $params, ) * ) {
430
+ type Error = VarargsError ;
431
+
432
+ #[ inline]
433
+ fn try_from( args: Varargs <' a>) -> Result <Self , Self :: Error > {
434
+ const EXPECTED : usize = count_tts!( $( $params) * ) ;
435
+ args. check_length( EXPECTED ) ?;
436
+ let mut i: usize = 0 ;
437
+ #[ allow( unused_variables, unused_mut) ]
438
+ let mut inc = || {
439
+ let ret = i;
440
+ i += 1 ;
441
+ ret
442
+ } ;
443
+ Ok ( (
444
+ $( args. get:: <$params>( inc( ) ) ?, ) *
445
+ ) )
446
+ }
447
+ }
448
+ } ;
449
+ }
450
+
451
+ // Define up to the length supported by standard library.
452
+ varargs_into_tuple ! ( ) ;
453
+ varargs_into_tuple ! ( A ) ;
454
+ varargs_into_tuple ! ( A , B ) ;
455
+ varargs_into_tuple ! ( A , B , C ) ;
456
+ varargs_into_tuple ! ( A , B , C , D ) ;
457
+ varargs_into_tuple ! ( A , B , C , D , E ) ;
458
+ varargs_into_tuple ! ( A , B , C , D , E , F ) ;
459
+ varargs_into_tuple ! ( A , B , C , D , E , F , G ) ;
460
+ varargs_into_tuple ! ( A , B , C , D , E , F , G , H ) ;
461
+ varargs_into_tuple ! ( A , B , C , D , E , F , G , H , I ) ;
462
+ varargs_into_tuple ! ( A , B , C , D , E , F , G , H , I , J ) ;
463
+ varargs_into_tuple ! ( A , B , C , D , E , F , G , H , I , J , K ) ;
464
+ varargs_into_tuple ! ( A , B , C , D , E , F , G , H , I , J , K , L ) ;
465
+
466
+ /// All possible errors that can occur when converting from Varargs.
467
+ ///
468
+ /// For methods that return this error, see [`Varargs::check_length()`], [`Varargs::get()`] or [`Varargs::get_opt()`].
469
+ /// Another context where this type is used is when destructuring `Varargs` into tuples.
470
+ #[ derive( Debug ) ]
471
+ pub enum VarargsError {
472
+ /// At least one argument type mismatches.
473
+ InvalidArgumentType {
474
+ index : usize ,
475
+ error : FromVariantError ,
476
+ } ,
477
+ /// Number of arguments doesn't match expectations.
478
+ InvalidLength {
479
+ /// The number of arguments actually passed.
480
+ length : usize ,
481
+ expected : IndexBounds ,
482
+ } ,
483
+ }
484
+
485
+ impl std:: error:: Error for VarargsError { }
486
+
487
+ impl fmt:: Display for VarargsError {
488
+ #[ inline]
489
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
490
+ match self {
491
+ VarargsError :: InvalidArgumentType { index, error } => {
492
+ write ! ( f, "type error for argument #{}: {}" , index, error) ?
493
+ }
494
+ VarargsError :: InvalidLength { expected, length } => write ! (
495
+ f,
496
+ "length mismatch: expected range {}, actual {}" ,
497
+ expected, length
498
+ ) ?,
499
+ }
500
+
501
+ Ok ( ( ) )
502
+ }
503
+ }
504
+
505
+ /// Defines which number of arguments is valid.
506
+ ///
507
+ /// Convertible from an exact value `a` as well as inclusive range expressions `a..`, `..=b`, `a..=b`.
508
+ pub struct IndexBounds {
509
+ /// The lower (inclusive) bound of the expected number of arguments, or `None` if unbounded.
510
+ pub start : Option < usize > ,
511
+
512
+ /// The upper (inclusive) bound of the expected number of arguments, or `None` if unbounded.
513
+ pub end : Option < usize > ,
514
+ }
515
+
516
+ impl IndexBounds {
517
+ #[ inline]
518
+ pub fn contains ( & self , value : usize ) -> bool {
519
+ match ( self . start , self . end ) {
520
+ ( Some ( s) , Some ( e) ) => value >= s && value <= e,
521
+ ( Some ( s) , None ) => value >= s,
522
+ ( None , Some ( e) ) => value <= e,
523
+ ( None , None ) => false , // unreachable in this context, but can be constructed by user
524
+ }
525
+ }
526
+ }
527
+
528
+ /// `a`
529
+ impl From < usize > for IndexBounds {
530
+ #[ inline]
531
+ fn from ( exact_value : usize ) -> Self {
532
+ Self {
533
+ start : Some ( exact_value) ,
534
+ end : Some ( exact_value) ,
535
+ }
536
+ }
537
+ }
538
+
539
+ /// `a..=b`
540
+ impl From < ops:: RangeInclusive < usize > > for IndexBounds {
541
+ #[ inline]
542
+ fn from ( range : ops:: RangeInclusive < usize > ) -> Self {
543
+ Self {
544
+ start : Some ( * range. start ( ) ) ,
545
+ end : Some ( * range. end ( ) ) ,
546
+ }
547
+ }
548
+ }
549
+
550
+ /// `a..`
551
+ impl From < ops:: RangeFrom < usize > > for IndexBounds {
552
+ #[ inline]
553
+ fn from ( range : ops:: RangeFrom < usize > ) -> Self {
554
+ Self {
555
+ start : Some ( range. start ) ,
556
+ end : None ,
557
+ }
558
+ }
559
+ }
560
+
561
+ /// `..=b`
562
+ impl From < ops:: RangeToInclusive < usize > > for IndexBounds {
563
+ #[ inline]
564
+ fn from ( range : ops:: RangeToInclusive < usize > ) -> Self {
565
+ Self {
566
+ start : None ,
567
+ end : Some ( range. end ) ,
568
+ }
569
+ }
570
+ }
571
+
572
+ impl fmt:: Debug for IndexBounds {
573
+ #[ inline]
574
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
575
+ write ! ( f, "IndexBounds({})" , self )
576
+ }
577
+ }
578
+
579
+ impl fmt:: Display for IndexBounds {
580
+ #[ inline]
581
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
582
+ match self . start {
583
+ Some ( start) => write ! ( f, "{}" , start) ?,
584
+ None => { }
585
+ }
586
+
587
+ write ! ( f, "..=" ) ?;
588
+
589
+ match self . end {
590
+ Some ( end) => write ! ( f, "{}" , end) ?,
591
+ None => { }
592
+ }
593
+
594
+ Ok ( ( ) )
297
595
}
298
596
}
299
597
@@ -361,10 +659,11 @@ impl<'r, 'a, T: FromVariant> ArgBuilder<'r, 'a, T> {
361
659
#[ inline]
362
660
pub fn get ( mut self ) -> Result < T , ArgumentError < ' a > > {
363
661
self . get_optional_internal ( ) . and_then ( |arg| {
662
+ let actual_index = self . args . idx + self . args . offset_index ;
364
663
arg. ok_or ( ArgumentError {
365
664
site : self . site ,
366
665
kind : ArgumentErrorKind :: Missing {
367
- idx : self . args . idx ,
666
+ idx : actual_index ,
368
667
name : self . name ,
369
668
} ,
370
669
} )
@@ -389,14 +688,13 @@ impl<'r, 'a, T: FromVariant> ArgBuilder<'r, 'a, T> {
389
688
ty,
390
689
..
391
690
} = self ;
392
- let idx = args. idx ;
691
+ let actual_index = args. idx + args . offset_index ;
393
692
394
- if let Some ( arg) = args. iter . next ( ) {
395
- args. idx += 1 ;
693
+ if let Some ( arg) = args. next ( ) {
396
694
T :: from_variant ( arg) . map ( Some ) . map_err ( |err| ArgumentError {
397
695
site : * site,
398
696
kind : ArgumentErrorKind :: CannotConvert {
399
- idx,
697
+ idx : actual_index ,
400
698
name : name. take ( ) ,
401
699
value : arg,
402
700
ty : ty
0 commit comments