@@ -89,11 +89,12 @@ extern crate std;
8989#[ doc = include_str ! ( "../README.md" ) ]
9090extern "C" { }
9191
92+ use core:: ffi:: c_void;
9293use core:: marker:: PhantomData ;
9394use core:: mem:: { self , ManuallyDrop } ;
94- use core:: ops:: { Deref , DerefMut } ;
95+ use core:: ops:: Deref ;
9596use core:: ptr;
96- use std:: os:: raw:: { c_int , c_ulong} ;
97+ use std:: os:: raw:: c_ulong;
9798
9899pub use block_sys as ffi;
99100use objc2_encode:: { Encode , EncodeArguments , Encoding , RefEncode } ;
@@ -119,12 +120,14 @@ macro_rules! block_args_impl {
119120 ( $( $a: ident : $t: ident) ,* ) => (
120121 impl <$( $t) ,* > BlockArguments for ( $( $t, ) * ) {
121122 unsafe fn call_block<R >( self , block: * mut Block <Self , R >) -> R {
122- let invoke: unsafe extern "C" fn ( * mut Block <Self , R > $( , $t) * ) -> R = {
123- let base = block as * mut BlockBase <Self , R >;
124- unsafe { mem:: transmute( ( * base) . invoke) }
125- } ;
123+ let layout = unsafe { block. cast:: <ffi:: Block_layout >( ) . as_ref( ) . unwrap_unchecked( ) } ;
124+ // TODO: Can `invoke` actually be null?
125+ let invoke: unsafe extern "C" fn ( ) = layout. invoke. unwrap( ) ;
126+ let invoke: unsafe extern "C" fn ( * mut Block <Self , R >, $( $t) ,* ) -> R =
127+ unsafe { mem:: transmute( invoke) }
128+ ;
126129 let ( $( $a, ) * ) = self ;
127- unsafe { invoke( block $( , $a) * ) }
130+ unsafe { invoke( block, $( $a) , * ) }
128131 }
129132 }
130133 ) ;
@@ -169,19 +172,12 @@ block_args_impl!(
169172 l: L
170173) ;
171174
172- #[ repr( C ) ]
173- struct BlockBase < A , R > {
174- isa : * const ffi:: Class ,
175- flags : c_int ,
176- _reserved : c_int ,
177- invoke : unsafe extern "C" fn ( * mut Block < A , R > , ...) -> R ,
178- }
179-
180175/// An Objective-C block that takes arguments of `A` when called and
181176/// returns a value of `R`.
182177#[ repr( C ) ]
183178pub struct Block < A , R > {
184- _base : PhantomData < BlockBase < A , R > > ,
179+ _inner : [ u8 ; 0 ] ,
180+ p : PhantomData < ( ffi:: Block_layout , fn ( A ) -> R ) > ,
185181}
186182
187183unsafe impl < A : BlockArguments + EncodeArguments , R : Encode > RefEncode for Block < A , R > {
@@ -199,7 +195,7 @@ impl<A: BlockArguments + EncodeArguments, R: Encode> Block<A, R> {
199195 /// For example, if this block is shared with multiple references, the
200196 /// caller must ensure that calling it will not cause a data race.
201197 pub unsafe fn call ( & self , args : A ) -> R {
202- unsafe { args. call_block ( self as * const _ as * mut _ ) }
198+ unsafe { args. call_block ( self as * const Self as * mut Self ) }
203199 }
204200}
205201
@@ -249,7 +245,7 @@ impl<A, R> Deref for RcBlock<A, R> {
249245
250246 fn deref ( & self ) -> & Block < A , R > {
251247 // SAFETY: The pointer is ensured valid by creator functions.
252- unsafe { & * self . ptr }
248+ unsafe { self . ptr . as_ref ( ) . unwrap_unchecked ( ) }
253249 }
254250}
255251
@@ -280,21 +276,19 @@ macro_rules! concrete_block_impl {
280276 type Ret = R ;
281277
282278 fn into_concrete_block( self ) -> ConcreteBlock <( $( $t, ) * ) , R , X > {
283- unsafe extern fn $f<$( $t, ) * R , X >(
284- block_ptr : * mut ConcreteBlock <( $( $t, ) * ) , R , X >
285- $( , $a: $t) *
279+ extern "C" fn $f<$( $t, ) * R , X >(
280+ block : & ConcreteBlock <( $( $t, ) * ) , R , X >,
281+ $( $a: $t, ) *
286282 ) -> R
287283 where
288- X : Fn ( $( $t, ) * ) -> R
284+ X : Fn ( $( $t, ) * ) -> R ,
289285 {
290- let block = unsafe { & * block_ptr } ;
291286 ( block. closure) ( $( $a) ,* )
292287 }
293288
294- let f: unsafe extern "C" fn ( * mut ConcreteBlock <( $( $t, ) * ) , R , X > $( , $a: $t) * ) -> R = $f;
295- unsafe {
296- ConcreteBlock :: with_invoke( mem:: transmute( f) , self )
297- }
289+ let f: extern "C" fn ( & ConcreteBlock <( $( $t, ) * ) , R , X >, $( $a: $t, ) * ) -> R = $f;
290+ let f: unsafe extern "C" fn ( ) = unsafe { mem:: transmute( f) } ;
291+ unsafe { ConcreteBlock :: with_invoke( f, self ) }
298292 }
299293 }
300294 ) ;
@@ -395,8 +389,8 @@ concrete_block_impl!(
395389/// constructed on the stack.
396390#[ repr( C ) ]
397391pub struct ConcreteBlock < A , R , F > {
398- base : BlockBase < A , R > ,
399- descriptor : * const BlockDescriptor < ConcreteBlock < A , R , F > > ,
392+ p : PhantomData < Block < A , R > > ,
393+ layout : ffi :: Block_layout ,
400394 closure : F ,
401395}
402396
@@ -421,25 +415,32 @@ where
421415}
422416
423417impl < A , R , F > ConcreteBlock < A , R , F > {
424- const DESCRIPTOR : BlockDescriptor < Self > = BlockDescriptor {
425- _reserved : 0 ,
426- block_size : mem:: size_of :: < Self > ( ) as c_ulong ,
427- copy_helper : block_context_copy :: < Self > ,
428- dispose_helper : block_context_dispose :: < Self > ,
418+ // TODO: Use new ABI with BLOCK_HAS_SIGNATURE
419+ const FLAGS : ffi:: block_flags = ffi:: BLOCK_HAS_COPY_DISPOSE ;
420+
421+ const DESCRIPTOR : ffi:: Block_descriptor = ffi:: Block_descriptor {
422+ header : ffi:: Block_descriptor_header {
423+ reserved : 0 ,
424+ size : mem:: size_of :: < Self > ( ) as c_ulong ,
425+ } ,
426+ copy : Some ( block_context_copy :: < Self > ) ,
427+ dispose : Some ( block_context_dispose :: < Self > ) ,
429428 } ;
430429
431430 /// Constructs a `ConcreteBlock` with the given invoke function and closure.
432431 /// Unsafe because the caller must ensure the invoke function takes the
433432 /// correct arguments.
434- unsafe fn with_invoke ( invoke : unsafe extern "C" fn ( * mut Self , ...) -> R , closure : F ) -> Self {
435- ConcreteBlock {
436- base : BlockBase {
437- isa : unsafe { & ffi:: _NSConcreteStackBlock } ,
438- flags : ffi:: BLOCK_HAS_COPY_DISPOSE ,
439- _reserved : 0 ,
440- invoke : unsafe { mem:: transmute ( invoke) } ,
441- } ,
442- descriptor : & Self :: DESCRIPTOR ,
433+ unsafe fn with_invoke ( invoke : unsafe extern "C" fn ( ) , closure : F ) -> Self {
434+ let layout = ffi:: Block_layout {
435+ isa : unsafe { & ffi:: _NSConcreteStackBlock } ,
436+ flags : Self :: FLAGS ,
437+ reserved : 0 ,
438+ invoke : Some ( invoke) ,
439+ descriptor : & Self :: DESCRIPTOR as * const ffi:: Block_descriptor as * mut c_void ,
440+ } ;
441+ Self {
442+ p : PhantomData ,
443+ layout,
443444 closure,
444445 }
445446 }
@@ -452,48 +453,33 @@ impl<A, R, F: 'static> ConcreteBlock<A, R, F> {
452453 // and we can forget the original block because the heap block will
453454 // drop in our dispose helper. TODO: Verify this.
454455 let mut block = ManuallyDrop :: new ( self ) ;
455- unsafe { RcBlock :: copy ( & mut * * block) }
456+ let ptr: * mut Self = & mut * block;
457+ unsafe { RcBlock :: copy ( ptr. cast ( ) ) }
456458 }
457459}
458460
459461impl < A , R , F : Clone > Clone for ConcreteBlock < A , R , F > {
460462 fn clone ( & self ) -> Self {
461- unsafe {
462- ConcreteBlock :: with_invoke ( mem:: transmute ( self . base . invoke ) , self . closure . clone ( ) )
463- }
463+ unsafe { Self :: with_invoke ( self . layout . invoke . unwrap ( ) , self . closure . clone ( ) ) }
464464 }
465465}
466466
467467impl < A , R , F > Deref for ConcreteBlock < A , R , F > {
468468 type Target = Block < A , R > ;
469469
470- fn deref ( & self ) -> & Block < A , R > {
471- unsafe { & * ( & self . base as * const _ as * const Block < A , R > ) }
472- }
473- }
474-
475- impl < A , R , F > DerefMut for ConcreteBlock < A , R , F > {
476- fn deref_mut ( & mut self ) -> & mut Block < A , R > {
477- unsafe { & mut * ( & mut self . base as * mut _ as * mut Block < A , R > ) }
470+ fn deref ( & self ) -> & Self :: Target {
471+ unsafe { & * ( self as * const Self as * const Block < A , R > ) }
478472 }
479473}
480474
481- unsafe extern "C" fn block_context_dispose < B > ( block : & mut B ) {
482- unsafe { ptr:: drop_in_place ( block) } ;
475+ unsafe extern "C" fn block_context_dispose < B > ( block : * mut c_void ) {
476+ unsafe { ptr:: drop_in_place ( block. cast :: < B > ( ) ) } ;
483477}
484478
485- unsafe extern "C" fn block_context_copy < B > ( _dst : & mut B , _src : & B ) {
479+ unsafe extern "C" fn block_context_copy < B > ( _dst : * mut c_void , _src : * mut c_void ) {
486480 // The runtime memmoves the src block into the dst block, nothing to do
487481}
488482
489- #[ repr( C ) ]
490- struct BlockDescriptor < B > {
491- _reserved : c_ulong ,
492- block_size : c_ulong ,
493- copy_helper : unsafe extern "C" fn ( & mut B , & B ) ,
494- dispose_helper : unsafe extern "C" fn ( & mut B ) ,
495- }
496-
497483#[ cfg( test) ]
498484mod tests {
499485 // Tests live in top level `tests` helper crate
0 commit comments