@@ -201,9 +201,9 @@ mod imp {
201201
202202 // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
203203 // 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.
207207 //
208208 // In general it looks like:
209209 // res = Vec::new()
@@ -213,53 +213,60 @@ mod imp {
213213 // res
214214 #[ cfg( any( target_os = "ios" , target_os = "tvos" , target_os = "watchos" ) ) ]
215215 pub fn args ( ) -> Args {
216- use crate :: ffi:: OsString ;
216+ use crate :: ffi:: { c_char , c_void , OsString } ;
217217 use crate :: mem;
218218 use crate :: str;
219219
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 ;
224223
225- #[ cfg( target_arch = "aarch64" ) ]
226224 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_char ) -> Sel ;
226+ fn objc_getClass ( class_name : * const c_char ) -> NsId ;
232227
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 ( ) ;
239230 }
240231
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 ) } ;
243245
244246 let mut res = Vec :: new ( ) ;
245247
246248 unsafe {
247- let process_info_sel =
248- sel_registerName ( c"processInfo" . as_ptr ( ) as * const libc:: c_uchar ) ;
249- let arguments_sel = sel_registerName ( c"arguments" . as_ptr ( ) as * const libc:: c_uchar ) ;
250- let utf8_sel = sel_registerName ( c"UTF8String" . as_ptr ( ) as * const libc:: c_uchar ) ;
251- let count_sel = sel_registerName ( c"count" . as_ptr ( ) as * const libc:: c_uchar ) ;
252- let object_at_sel =
253- sel_registerName ( c"objectAtIndex:" . as_ptr ( ) as * const libc:: c_uchar ) ;
254-
255- let klass = objc_getClass ( c"NSProcessInfo" . as_ptr ( ) as * const libc:: c_uchar ) ;
256- let info = objc_msgSend ( klass, process_info_sel) ;
257- let args = objc_msgSend ( info, arguments_sel) ;
258-
259- let cnt: usize = mem:: transmute ( objc_msgSend ( args, count_sel) ) ;
249+ let process_info_sel = sel_registerName ( c"processInfo" . as_ptr ( ) ) ;
250+ let arguments_sel = sel_registerName ( c"arguments" . as_ptr ( ) ) ;
251+ let count_sel = sel_registerName ( c"count" . as_ptr ( ) ) ;
252+ let object_at_index_sel = sel_registerName ( c"objectAtIndex:" . as_ptr ( ) ) ;
253+ let utf8string_sel = sel_registerName ( c"UTF8String" . as_ptr ( ) ) ;
254+
255+ let klass = objc_getClass ( c"NSProcessInfo" . as_ptr ( ) ) ;
256+ // `+[NSProcessInfo processInfo]` returns an object with +0 retain count, so no need to manually `retain/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 `retain/release`.
260+ let args = MSG_SEND_NO_ARGUMENTS_RETURN_PTR ( info, arguments_sel) ;
261+
262+ let cnt = MSG_SEND_NO_ARGUMENTS_RETURN_NSUINTEGER ( args, count_sel) ;
260263 for i in 0 ..cnt {
261- let tmp = objc_msgSend_ul ( args, object_at_sel, i as libc:: c_ulong ) ;
262- 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 `retain/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 ( ) ;
263270 let bytes = CStr :: from_ptr ( utf_c_str) . to_bytes ( ) ;
264271 res. push ( OsString :: from ( str:: from_utf8 ( bytes) . unwrap ( ) ) )
265272 }
0 commit comments