@@ -84,6 +84,8 @@ use core::sync::atomic;
84
84
#[ doc( inline) ]
85
85
pub use objc2_encode:: { Encoding , EncodingBox , ParseError } ;
86
86
87
+ use crate :: runtime:: { AnyObject , Imp , Sel } ;
88
+
87
89
/// Types that have an Objective-C type-encoding.
88
90
///
89
91
/// Usually you will want to implement [`RefEncode`] as well.
@@ -364,45 +366,180 @@ mod args_private {
364
366
/// argument has an Objective-C type-encoding, or can be converted from one.
365
367
///
366
368
/// This is implemented for tuples of up to 16 arguments, where each argument
367
- /// implements [`EncodeArgument`]. It is primarily used to make generic
368
- /// code a bit easier.
369
+ /// implements [`EncodeArgument`]. It is a sealed trait, and should not need
370
+ /// to be implemented manually - it is primarily used to make generic code a
371
+ /// bit easier to read and understand.
369
372
///
370
373
/// Note that tuples themselves don't implement [`Encode`] directly, because
371
374
/// they're not FFI-safe!
372
375
pub trait EncodeArguments : args_private:: Sealed {
373
376
/// The encodings for the arguments.
374
377
const ENCODINGS : & ' static [ Encoding ] ;
378
+
379
+ /// Invoke a message sending function with the given object, selector,
380
+ /// and arguments.
381
+ ///
382
+ /// Implementation-wise, this is a bit ugly, but simply just easiest to
383
+ /// have the method on this trait, since inside `MessageReceiver` we only
384
+ /// want to publicly require `EncodeArguments`, and not another private
385
+ /// trait.
386
+ #[ doc( hidden) ]
387
+ unsafe fn __invoke < R : EncodeReturn > (
388
+ msg_send_fn : Imp ,
389
+ receiver : * mut AnyObject ,
390
+ sel : Sel ,
391
+ args : Self ,
392
+ ) -> R ;
375
393
}
376
394
377
395
macro_rules! encode_args_impl {
378
- ( $( $Arg : ident) ,* ) => {
379
- impl <$( $Arg : EncodeArgument ) ,* > args_private:: Sealed for ( $( $Arg , ) * ) { }
396
+ ( $( $a : ident : $T : ident) ,* ) => {
397
+ impl <$( $T : EncodeArgument ) ,* > args_private:: Sealed for ( $( $T , ) * ) { }
380
398
381
- impl <$( $Arg : EncodeArgument ) ,* > EncodeArguments for ( $( $Arg , ) * ) {
399
+ impl <$( $T : EncodeArgument ) ,* > EncodeArguments for ( $( $T , ) * ) {
382
400
const ENCODINGS : & ' static [ Encoding ] = & [
383
- $( $Arg :: ENCODING_ARGUMENT ) ,*
401
+ $( $T :: ENCODING_ARGUMENT ) ,*
384
402
] ;
403
+
404
+ #[ inline]
405
+ unsafe fn __invoke<R : EncodeReturn >( msg_send_fn: Imp , receiver: * mut AnyObject , sel: Sel , ( $( $a, ) * ) : Self ) -> R {
406
+ // Message sending works by passing the receiver as the first
407
+ // argument, the selector as the second argument, and the rest
408
+ // of the arguments after that.
409
+ //
410
+ // The imp must be cast to the appropriate function pointer
411
+ // type before being called; contrary to how the headers and
412
+ // documentation describe them, the msgSend functions are not
413
+ // parametric on all platforms, instead they "trampoline" to
414
+ // the actual method implementations.
415
+ //
416
+ // SAFETY: We're transmuting an `unsafe` function pointer to
417
+ // another `unsafe` function pointer.
418
+ #[ cfg( not( feature = "unstable-c-unwind" ) ) ]
419
+ let msg_send_fn: unsafe extern "C" fn ( * mut AnyObject , Sel $( , $T) * ) -> R = unsafe {
420
+ mem:: transmute( msg_send_fn)
421
+ } ;
422
+ #[ cfg( feature = "unstable-c-unwind" ) ]
423
+ let msg_send_fn: unsafe extern "C-unwind" fn ( * mut AnyObject , Sel $( , $T) * ) -> R = unsafe {
424
+ mem:: transmute( msg_send_fn)
425
+ } ;
426
+
427
+ // SAFETY: Caller upholds that the imp is safe to call with
428
+ // the given receiver, selector and arguments.
429
+ //
430
+ // TODO: On x86_64 it would be more efficient to use a GOT
431
+ // entry here (e.g. adding `nonlazybind` in LLVM).
432
+ // Same can be said of e.g. `objc_retain` and `objc_release`.
433
+ unsafe { msg_send_fn( receiver, sel $( , $a) * ) }
434
+ }
385
435
}
386
436
} ;
387
437
}
388
438
389
439
encode_args_impl ! ( ) ;
390
- encode_args_impl ! ( A ) ;
391
- encode_args_impl ! ( A , B ) ;
392
- encode_args_impl ! ( A , B , C ) ;
393
- encode_args_impl ! ( A , B , C , D ) ;
394
- encode_args_impl ! ( A , B , C , D , E ) ;
395
- encode_args_impl ! ( A , B , C , D , E , F ) ;
396
- encode_args_impl ! ( A , B , C , D , E , F , G ) ;
397
- encode_args_impl ! ( A , B , C , D , E , F , G , H ) ;
398
- encode_args_impl ! ( A , B , C , D , E , F , G , H , I ) ;
399
- encode_args_impl ! ( A , B , C , D , E , F , G , H , I , J ) ;
400
- encode_args_impl ! ( A , B , C , D , E , F , G , H , I , J , K ) ;
401
- encode_args_impl ! ( A , B , C , D , E , F , G , H , I , J , K , L ) ;
402
- encode_args_impl ! ( A , B , C , D , E , F , G , H , I , J , K , L , M ) ;
403
- encode_args_impl ! ( A , B , C , D , E , F , G , H , I , J , K , L , M , N ) ;
404
- encode_args_impl ! ( A , B , C , D , E , F , G , H , I , J , K , L , M , N , O ) ;
405
- encode_args_impl ! ( A , B , C , D , E , F , G , H , I , J , K , L , M , N , O , P ) ;
440
+ encode_args_impl ! ( a: A ) ;
441
+ encode_args_impl ! ( a: A , b: B ) ;
442
+ encode_args_impl ! ( a: A , b: B , c: C ) ;
443
+ encode_args_impl ! ( a: A , b: B , c: C , d: D ) ;
444
+ encode_args_impl ! ( a: A , b: B , c: C , d: D , e: E ) ;
445
+ encode_args_impl ! ( a: A , b: B , c: C , d: D , e: E , f: F ) ;
446
+ encode_args_impl ! ( a: A , b: B , c: C , d: D , e: E , f: F , g: G ) ;
447
+ encode_args_impl ! ( a: A , b: B , c: C , d: D , e: E , f: F , g: G , h: H ) ;
448
+ encode_args_impl ! ( a: A , b: B , c: C , d: D , e: E , f: F , g: G , h: H , i: I ) ;
449
+ encode_args_impl ! ( a: A , b: B , c: C , d: D , e: E , f: F , g: G , h: H , i: I , j: J ) ;
450
+ encode_args_impl ! (
451
+ a: A ,
452
+ b: B ,
453
+ c: C ,
454
+ d: D ,
455
+ e: E ,
456
+ f: F ,
457
+ g: G ,
458
+ h: H ,
459
+ i: I ,
460
+ j: J ,
461
+ k: K
462
+ ) ;
463
+ encode_args_impl ! (
464
+ a: A ,
465
+ b: B ,
466
+ c: C ,
467
+ d: D ,
468
+ e: E ,
469
+ f: F ,
470
+ g: G ,
471
+ h: H ,
472
+ i: I ,
473
+ j: J ,
474
+ k: K ,
475
+ l: L
476
+ ) ;
477
+ encode_args_impl ! (
478
+ a: A ,
479
+ b: B ,
480
+ c: C ,
481
+ d: D ,
482
+ e: E ,
483
+ f: F ,
484
+ g: G ,
485
+ h: H ,
486
+ i: I ,
487
+ j: J ,
488
+ k: K ,
489
+ l: L ,
490
+ m: M
491
+ ) ;
492
+ encode_args_impl ! (
493
+ a: A ,
494
+ b: B ,
495
+ c: C ,
496
+ d: D ,
497
+ e: E ,
498
+ f: F ,
499
+ g: G ,
500
+ h: H ,
501
+ i: I ,
502
+ j: J ,
503
+ k: K ,
504
+ l: L ,
505
+ m: M ,
506
+ n: N
507
+ ) ;
508
+ encode_args_impl ! (
509
+ a: A ,
510
+ b: B ,
511
+ c: C ,
512
+ d: D ,
513
+ e: E ,
514
+ f: F ,
515
+ g: G ,
516
+ h: H ,
517
+ i: I ,
518
+ j: J ,
519
+ k: K ,
520
+ l: L ,
521
+ m: M ,
522
+ n: N ,
523
+ o: O
524
+ ) ;
525
+ encode_args_impl ! (
526
+ a: A ,
527
+ b: B ,
528
+ c: C ,
529
+ d: D ,
530
+ e: E ,
531
+ f: F ,
532
+ g: G ,
533
+ h: H ,
534
+ i: I ,
535
+ j: J ,
536
+ k: K ,
537
+ l: L ,
538
+ m: M ,
539
+ n: N ,
540
+ o: O ,
541
+ p: P
542
+ ) ;
406
543
407
544
// TODO: Implement for `PhantomData` and `PhantomPinned`?
408
545
0 commit comments