@@ -201,9 +201,9 @@ mod imp {
201
201
202
202
// As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
203
203
// and use underscores in their names - they're most probably
204
- // are considered private and therefore should be avoided
205
- // Here is another way to get arguments using Objective C
206
- // runtime
204
+ // are considered private and therefore should be avoided.
205
+ // Here is another way to get arguments using the Objective- C
206
+ // runtime.
207
207
//
208
208
// In general it looks like:
209
209
// res = Vec::new()
@@ -213,51 +213,60 @@ mod imp {
213
213
// res
214
214
#[ cfg( any( target_os = "ios" , target_os = "tvos" , target_os = "watchos" ) ) ]
215
215
pub fn args ( ) -> Args {
216
- use crate :: ffi:: OsString ;
216
+ use crate :: ffi:: { c_char , c_uchar , c_void , OsString } ;
217
217
use crate :: mem;
218
218
use crate :: str;
219
219
220
- extern "C" {
221
- fn sel_registerName ( name : * const libc:: c_uchar ) -> Sel ;
222
- fn objc_getClass ( class_name : * const libc:: c_uchar ) -> NsId ;
223
- }
220
+ type Sel = * const c_void ;
221
+ type NsId = * const c_void ;
222
+ type NSUInteger = usize ;
224
223
225
- #[ cfg( target_arch = "aarch64" ) ]
226
224
extern "C" {
227
- fn objc_msgSend ( obj : NsId , sel : Sel ) -> NsId ;
228
- #[ allow( clashing_extern_declarations) ]
229
- #[ link_name = "objc_msgSend" ]
230
- fn objc_msgSend_ul ( obj : NsId , sel : Sel , i : libc:: c_ulong ) -> NsId ;
231
- }
225
+ fn sel_registerName ( name : * const c_uchar ) -> Sel ;
226
+ fn objc_getClass ( class_name : * const c_uchar ) -> NsId ;
232
227
233
- #[ cfg( not( target_arch = "aarch64" ) ) ]
234
- extern "C" {
235
- fn objc_msgSend ( obj : NsId , sel : Sel , ...) -> NsId ;
236
- #[ allow( clashing_extern_declarations) ]
237
- #[ link_name = "objc_msgSend" ]
238
- fn objc_msgSend_ul ( obj : NsId , sel : Sel , ...) -> NsId ;
228
+ // This must be transmuted to an appropriate function pointer type before being called.
229
+ fn objc_msgSend ( ) ;
239
230
}
240
231
241
- type Sel = * const libc:: c_void ;
242
- type NsId = * const libc:: c_void ;
232
+ const MSG_SEND_PTR : unsafe extern "C" fn ( ) = objc_msgSend;
233
+ const MSG_SEND_NO_ARGUMENTS_RETURN_PTR : unsafe extern "C" fn ( NsId , Sel ) -> * const c_void =
234
+ unsafe { mem:: transmute ( MSG_SEND_PTR ) } ;
235
+ const MSG_SEND_NO_ARGUMENTS_RETURN_NSUINTEGER : unsafe extern "C" fn (
236
+ NsId ,
237
+ Sel ,
238
+ ) -> NSUInteger = unsafe { mem:: transmute ( MSG_SEND_PTR ) } ;
239
+ const MSG_SEND_NSINTEGER_ARGUMENT_RETURN_PTR : unsafe extern "C" fn (
240
+ NsId ,
241
+ Sel ,
242
+ NSUInteger ,
243
+ )
244
+ -> * const c_void = unsafe { mem:: transmute ( MSG_SEND_PTR ) } ;
243
245
244
246
let mut res = Vec :: new ( ) ;
245
247
246
248
unsafe {
247
249
let process_info_sel = sel_registerName ( "processInfo\0 " . as_ptr ( ) ) ;
248
250
let arguments_sel = sel_registerName ( "arguments\0 " . as_ptr ( ) ) ;
249
- let utf8_sel = sel_registerName ( "UTF8String\0 " . as_ptr ( ) ) ;
250
251
let count_sel = sel_registerName ( "count\0 " . as_ptr ( ) ) ;
251
- let object_at_sel = sel_registerName ( "objectAtIndex:\0 " . as_ptr ( ) ) ;
252
+ let object_at_index_sel = sel_registerName ( "objectAtIndex:\0 " . as_ptr ( ) ) ;
253
+ let utf8string_sel = sel_registerName ( "UTF8String\0 " . as_ptr ( ) ) ;
252
254
253
255
let klass = objc_getClass ( "NSProcessInfo\0 " . as_ptr ( ) ) ;
254
- let info = objc_msgSend ( klass, process_info_sel) ;
255
- let args = objc_msgSend ( info, arguments_sel) ;
256
+ // `+[NSProcessInfo processInfo]` returns an object with +0 retain count, so no need to manually `release`.
257
+ let info = MSG_SEND_NO_ARGUMENTS_RETURN_PTR ( klass, process_info_sel) ;
258
+
259
+ // `-[NSProcessInfo arguments]` returns an object with +0 retain count, so no need to manually `release`.
260
+ let args = MSG_SEND_NO_ARGUMENTS_RETURN_PTR ( info, arguments_sel) ;
256
261
257
- let cnt: usize = mem :: transmute ( objc_msgSend ( args, count_sel) ) ;
262
+ let cnt = MSG_SEND_NO_ARGUMENTS_RETURN_NSUINTEGER ( args, count_sel) ;
258
263
for i in 0 ..cnt {
259
- let tmp = objc_msgSend_ul ( args, object_at_sel, i as libc:: c_ulong ) ;
260
- let utf_c_str: * const libc:: c_char = mem:: transmute ( objc_msgSend ( tmp, utf8_sel) ) ;
264
+ // `-[NSArray objectAtIndex:]` returns an object whose lifetime is tied to the array, so no need to manually `release`.
265
+ let ns_string =
266
+ MSG_SEND_NSINTEGER_ARGUMENT_RETURN_PTR ( args, object_at_index_sel, i) ;
267
+ // The lifetime of this pointer is tied to the NSString, as well as the current autorelease pool, which is why we heap-allocate the string below.
268
+ let utf_c_str: * const c_char =
269
+ MSG_SEND_NO_ARGUMENTS_RETURN_PTR ( ns_string, utf8string_sel) . cast ( ) ;
261
270
let bytes = CStr :: from_ptr ( utf_c_str) . to_bytes ( ) ;
262
271
res. push ( OsString :: from ( str:: from_utf8 ( bytes) . unwrap ( ) ) )
263
272
}
0 commit comments