@@ -124,6 +124,7 @@ use std::ffi::CString;
124
124
125
125
use crate :: encode:: { Encode , EncodeArguments , Encoding , RefEncode } ;
126
126
use crate :: ffi;
127
+ use crate :: rc:: Allocated ;
127
128
use crate :: runtime:: { Bool , Class , Imp , Object , Protocol , Sel } ;
128
129
use crate :: sel;
129
130
use crate :: Message ;
@@ -196,6 +197,37 @@ macro_rules! method_decl_impl {
196
197
}
197
198
}
198
199
} ;
200
+ ( @<> Allocated <T >, $f: ty, $( $t: ident) ,* ) => {
201
+ #[ doc( hidden) ]
202
+ impl <T , $( $t) ,* > private:: Sealed for $f
203
+ where
204
+ T : Message + ?Sized ,
205
+ $( $t: Encode , ) *
206
+ { }
207
+
208
+ #[ doc( hidden) ]
209
+ impl <T , $( $t) ,* > MethodImplementation for $f
210
+ where
211
+ T : Message + ?Sized ,
212
+ $( $t: Encode , ) *
213
+ {
214
+ type Callee = T ;
215
+ type Ret = __IdReturnValue;
216
+ type Args = ( $( $t, ) * ) ;
217
+
218
+ fn __imp( self ) -> Imp {
219
+ // SAFETY: `Allocated<T>` is the same as `NonNull<T>`, except
220
+ // with the assumption of a +1 calling convention.
221
+ //
222
+ // The calling convention is ensured to be upheld by having
223
+ // `__IdReturnValue` in the type, since that type is private
224
+ // and hence only internal macros like `#[method_id]` will be
225
+ // able to produce it (and that, in turn, only allows it if
226
+ // the selector is `init` as checked by `MessageRecieveId`).
227
+ unsafe { mem:: transmute( self ) }
228
+ }
229
+ }
230
+ } ;
199
231
( # $abi: literal; $( $t: ident) ,* ) => {
200
232
method_decl_impl!( @<' a> T , R , extern $abi fn ( & ' a T , Sel $( , $t) * ) -> R , $( $t) ,* ) ;
201
233
method_decl_impl!( @<' a> T , R , extern $abi fn ( & ' a mut T , Sel $( , $t) * ) -> R , $( $t) ,* ) ;
@@ -207,6 +239,9 @@ macro_rules! method_decl_impl {
207
239
method_decl_impl!( @<' a> Class , R , extern $abi fn ( & ' a Class , Sel $( , $t) * ) -> R , $( $t) ,* ) ;
208
240
method_decl_impl!( @<> Class , R , unsafe extern $abi fn ( * const Class , Sel $( , $t) * ) -> R , $( $t) ,* ) ;
209
241
method_decl_impl!( @<' a> Class , R , unsafe extern $abi fn ( & ' a Class , Sel $( , $t) * ) -> R , $( $t) ,* ) ;
242
+
243
+ method_decl_impl!( @<> Allocated <T >, extern $abi fn ( Allocated <T >, Sel $( , $t) * ) -> __IdReturnValue, $( $t) ,* ) ;
244
+ method_decl_impl!( @<> Allocated <T >, unsafe extern $abi fn ( Allocated <T >, Sel $( , $t) * ) -> __IdReturnValue, $( $t) ,* ) ;
210
245
} ;
211
246
( $( $t: ident) ,* ) => {
212
247
method_decl_impl!( # "C" ; $( $t) ,* ) ;
@@ -229,6 +264,17 @@ method_decl_impl!(A, B, C, D, E, F, G, H, I, J);
229
264
method_decl_impl ! ( A , B , C , D , E , F , G , H , I , J , K ) ;
230
265
method_decl_impl ! ( A , B , C , D , E , F , G , H , I , J , K , L ) ;
231
266
267
+ /// Helper type for implementing `MethodImplementation` with a receiver of
268
+ /// `Allocated<T>`, without exposing that implementation to users.
269
+ #[ doc( hidden) ]
270
+ #[ repr( transparent) ]
271
+ pub struct __IdReturnValue ( pub ( crate ) * mut Object ) ;
272
+
273
+ // SAFETY: `__IdReturnValue` is `#[repr(transparent)]`
274
+ unsafe impl Encode for __IdReturnValue {
275
+ const ENCODING : Encoding = <* mut Object >:: ENCODING ;
276
+ }
277
+
232
278
fn method_type_encoding ( ret : & Encoding , args : & [ Encoding ] ) -> CString {
233
279
// First two arguments are always self and the selector
234
280
let mut types = format ! ( "{ret}{}{}" , <* mut Object >:: ENCODING , Sel :: ENCODING ) ;
@@ -630,6 +676,7 @@ impl ProtocolBuilder {
630
676
#[ cfg( test) ]
631
677
mod tests {
632
678
use super :: * ;
679
+ use crate :: rc:: { Id , Shared } ;
633
680
use crate :: runtime:: { NSObject , NSZone } ;
634
681
use crate :: test_utils;
635
682
use crate :: { declare_class, extern_protocol, msg_send, ClassType , ConformsTo , ProtocolType } ;
@@ -641,8 +688,8 @@ mod tests {
641
688
const NAME : & ' static str = "NSCopying" ;
642
689
643
690
#[ allow( unused) ]
644
- #[ method ( copyWithZone: ) ]
645
- fn copy_with_zone( & self , _zone: * const NSZone ) -> * mut Self ;
691
+ #[ method_id ( copyWithZone: ) ]
692
+ fn copy_with_zone( & self , _zone: * const NSZone ) -> Id < Self , Shared > ;
646
693
}
647
694
) ;
648
695
@@ -814,9 +861,8 @@ mod tests {
814
861
}
815
862
816
863
unsafe impl ConformsTo <NSCopyingObject > for Custom {
817
- #[ method( copyWithZone: ) ]
818
- #[ allow( unreachable_code) ]
819
- fn copy_with_zone( & self , _zone: * const NSZone ) -> * mut Self {
864
+ #[ method_id( copyWithZone: ) ]
865
+ fn copy_with_zone( & self , _zone: * const NSZone ) -> Id <Self , Shared > {
820
866
unimplemented!( )
821
867
}
822
868
}
@@ -910,9 +956,8 @@ mod tests {
910
956
}
911
957
912
958
unsafe impl ConformsTo <NSCopyingObject > for Custom {
913
- #[ method( copyWithZone: ) ]
914
- #[ allow( unreachable_code) ]
915
- fn copy_with_zone( & self , _zone: * const NSZone ) -> * mut Self {
959
+ #[ method_id( copyWithZone: ) ]
960
+ fn copy_with_zone( & self , _zone: * const NSZone ) -> Id <Self , Shared > {
916
961
unimplemented!( )
917
962
}
918
963
@@ -924,4 +969,50 @@ mod tests {
924
969
925
970
let _cls = Custom :: class ( ) ;
926
971
}
972
+
973
+ // Proof-of-concept how we could make declare_class! accept generic.
974
+ #[ test]
975
+ fn test_generic ( ) {
976
+ struct GenericDeclareClass < T > ( T ) ;
977
+
978
+ unsafe impl < T > RefEncode for GenericDeclareClass < T > {
979
+ const ENCODING_REF : Encoding = Encoding :: Object ;
980
+ }
981
+ unsafe impl < T > Message for GenericDeclareClass < T > { }
982
+
983
+ unsafe impl < T > ClassType for GenericDeclareClass < T > {
984
+ type Super = NSObject ;
985
+ const NAME : & ' static str = "GenericDeclareClass" ;
986
+
987
+ #[ inline]
988
+ fn as_super ( & self ) -> & Self :: Super {
989
+ unimplemented ! ( )
990
+ }
991
+
992
+ #[ inline]
993
+ fn as_super_mut ( & mut self ) -> & mut Self :: Super {
994
+ unimplemented ! ( )
995
+ }
996
+
997
+ fn class ( ) -> & ' static Class {
998
+ let superclass = NSObject :: class ( ) ;
999
+ let mut builder = ClassBuilder :: new ( Self :: NAME , superclass) . unwrap ( ) ;
1000
+
1001
+ unsafe {
1002
+ builder. add_method (
1003
+ sel ! ( generic) ,
1004
+ <GenericDeclareClass < T > >:: generic as unsafe extern "C" fn ( _, _) ,
1005
+ ) ;
1006
+ }
1007
+
1008
+ builder. register ( )
1009
+ }
1010
+ }
1011
+
1012
+ impl < T > GenericDeclareClass < T > {
1013
+ extern "C" fn generic ( & self , _cmd : Sel ) { }
1014
+ }
1015
+
1016
+ let _ = GenericDeclareClass :: < ( ) > :: class ( ) ;
1017
+ }
927
1018
}
0 commit comments