@@ -8,21 +8,22 @@ cfg_if! {
88
99cfg_if ! {
1010 if #[ cfg( target_vendor = "apple" ) ] {
11- use core_foundation:: base:: CFType ;
12- use core_foundation:: base:: TCFType ;
13- use core_foundation:: dictionary:: CFDictionary ;
14- use core_foundation:: dictionary:: CFMutableDictionary ;
15- use core_foundation:: number:: CFNumber ;
16- use core_foundation:: string:: CFString ;
17- use core_foundation_sys:: base:: { kCFAllocatorDefault, CFRetain } ;
18- use io_kit_sys:: * ;
19- use io_kit_sys:: keys:: * ;
20- use io_kit_sys:: serial:: keys:: * ;
21- use io_kit_sys:: types:: * ;
22- use io_kit_sys:: usb:: lib:: * ;
23- use core:: ffi:: { c_char, c_int, c_uint, c_void, CStr } ;
11+ use core:: ffi:: { c_char, c_int, c_uint, CStr } ;
2412 use core:: mem:: MaybeUninit ;
2513
14+ use objc2_core_foundation:: {
15+ kCFAllocatorDefault, CFMutableDictionary , CFNumber , CFRetained , CFString , CFType ,
16+ } ;
17+ #[ allow( deprecated) ]
18+ use objc2_io_kit:: { kIOMasterPortDefault, IOMasterPort } ;
19+ use objc2_io_kit:: {
20+ io_object_t, io_registry_entry_t, kIOServiceClass, kIOUSBDeviceClassName,
21+ kIOUSBHostInterfaceClassName, IOIteratorNext , IOObjectGetClass , IOObjectRelease ,
22+ IORegistryEntryCreateCFProperties , IORegistryEntryCreateCFProperty ,
23+ IORegistryEntryGetParentEntry , IOServiceGetMatchingServices , IOServiceMatching ,
24+ kIOSerialBSDServiceValue, kIOSerialBSDTypeKey, kIOSerialBSDAllTypes,
25+ } ;
26+
2627 // NOTE: Do not use `mach` nor `mach2` crates, they're unmaintained,
2728 // and don't work on tvOS/watchOS/visionOS.
2829 //
@@ -273,22 +274,24 @@ fn parse_modalias(moda: &str) -> Option<UsbPortInfo> {
273274#[ cfg( target_vendor = "apple" ) ]
274275fn get_parent_device_by_type (
275276 device : io_object_t ,
276- parent_type : * const c_char ,
277+ parent_type : & CStr ,
277278) -> Option < io_registry_entry_t > {
278- let parent_type = unsafe { CStr :: from_ptr ( parent_type) } ;
279279 let mut device = device;
280280 loop {
281281 let mut class_name = MaybeUninit :: < [ c_char ; 128 ] > :: uninit ( ) ;
282- unsafe { IOObjectGetClass ( device, class_name. as_mut_ptr ( ) as * mut c_char ) } ;
282+ unsafe { IOObjectGetClass ( device, class_name. as_mut_ptr ( ) ) } ;
283283 let class_name = unsafe { class_name. assume_init ( ) } ;
284284 let name = unsafe { CStr :: from_ptr ( & class_name[ 0 ] ) } ;
285285 if name == parent_type {
286286 return Some ( device) ;
287287 }
288288 let mut parent = MaybeUninit :: uninit ( ) ;
289289 if unsafe {
290- IORegistryEntryGetParentEntry ( device, kIOServiceClass, parent. as_mut_ptr ( ) )
291- != KERN_SUCCESS
290+ IORegistryEntryGetParentEntry (
291+ device,
292+ kIOServiceClass. as_ptr ( ) as _ ,
293+ parent. as_mut_ptr ( ) ,
294+ ) != KERN_SUCCESS
292295 } {
293296 return None ;
294297 }
@@ -300,24 +303,17 @@ fn get_parent_device_by_type(
300303#[ allow( non_upper_case_globals) ]
301304/// Returns a specific property of the given device as an integer.
302305fn get_int_property ( device_type : io_registry_entry_t , property : & str ) -> Result < u32 > {
303- let cf_property = CFString :: new ( property) ;
304-
305- let cf_type_ref = unsafe {
306- IORegistryEntryCreateCFProperty (
307- device_type,
308- cf_property. as_concrete_TypeRef ( ) ,
309- kCFAllocatorDefault,
310- 0 ,
311- )
312- } ;
313- if cf_type_ref. is_null ( ) {
314- return Err ( Error :: new ( ErrorKind :: Unknown , "Failed to get property" ) ) ;
306+ let cf_property = CFString :: from_str ( property) ;
307+
308+ let cf_type = unsafe {
309+ IORegistryEntryCreateCFProperty ( device_type, Some ( & cf_property) , kCFAllocatorDefault, 0 )
315310 }
311+ . ok_or_else ( || Error :: new ( ErrorKind :: Unknown , "Failed to get property" ) ) ?;
316312
317- let cf_type = unsafe { CFType :: wrap_under_create_rule ( cf_type_ref) } ;
318313 cf_type
319314 . downcast :: < CFNumber > ( )
320- . and_then ( |n| n. to_i64 ( ) )
315+ . ok ( )
316+ . and_then ( |n| n. as_i64 ( ) )
321317 . map ( |n| n as u32 )
322318 . ok_or ( Error :: new (
323319 ErrorKind :: Unknown ,
@@ -328,23 +324,16 @@ fn get_int_property(device_type: io_registry_entry_t, property: &str) -> Result<
328324#[ cfg( target_vendor = "apple" ) ]
329325/// Returns a specific property of the given device as a string.
330326fn get_string_property ( device_type : io_registry_entry_t , property : & str ) -> Result < String > {
331- let cf_property = CFString :: new ( property) ;
332-
333- let cf_type_ref = unsafe {
334- IORegistryEntryCreateCFProperty (
335- device_type,
336- cf_property. as_concrete_TypeRef ( ) ,
337- kCFAllocatorDefault,
338- 0 ,
339- )
340- } ;
341- if cf_type_ref. is_null ( ) {
342- return Err ( Error :: new ( ErrorKind :: Unknown , "Failed to get property" ) ) ;
327+ let cf_property = CFString :: from_str ( property) ;
328+
329+ let cf_type = unsafe {
330+ IORegistryEntryCreateCFProperty ( device_type, Some ( & cf_property) , kCFAllocatorDefault, 0 )
343331 }
332+ . ok_or_else ( || Error :: new ( ErrorKind :: Unknown , "Failed to get property" ) ) ?;
344333
345- let cf_type = unsafe { CFType :: wrap_under_create_rule ( cf_type_ref) } ;
346334 cf_type
347335 . downcast :: < CFString > ( )
336+ . ok ( )
348337 . map ( |s| s. to_string ( ) )
349338 . ok_or ( Error :: new ( ErrorKind :: Unknown , "Failed to get string value" ) )
350339}
@@ -353,8 +342,9 @@ fn get_string_property(device_type: io_registry_entry_t, property: &str) -> Resu
353342/// Determine the serial port type based on the service object (like that returned by
354343/// `IOIteratorNext`). Specific properties are extracted for USB devices.
355344fn port_type ( service : io_object_t ) -> SerialPortType {
356- let bluetooth_device_class_name = b"IOBluetoothSerialClient\0 " . as_ptr ( ) as * const c_char ;
357- let usb_device_class_name = b"IOUSBHostInterface\0 " . as_ptr ( ) as * const c_char ;
345+ let bluetooth_device_class_name =
346+ CStr :: from_bytes_with_nul ( b"IOBluetoothSerialClient\0 " ) . unwrap ( ) ;
347+ let usb_device_class_name = kIOUSBHostInterfaceClassName;
358348 let legacy_usb_device_class_name = kIOUSBDeviceClassName;
359349
360350 let maybe_usb_device = get_parent_device_by_type ( service, usb_device_class_name)
@@ -388,29 +378,24 @@ cfg_if! {
388378 if #[ cfg( target_vendor = "apple" ) ] {
389379 /// Scans the system for serial ports and returns a list of them.
390380 /// The `SerialPortInfo` struct contains the name of the port which can be used for opening it.
381+ #[ allow( deprecated) ]
391382 pub fn available_ports( ) -> Result <Vec <SerialPortInfo >> {
392383 let mut vec = Vec :: new( ) ;
393384 unsafe {
394385 // Create a dictionary for specifying the search terms against the IOService
395- let classes_to_match = IOServiceMatching ( kIOSerialBSDServiceValue) ;
396- if classes_to_match. is_null( ) {
397- return Err ( Error :: new(
398- ErrorKind :: Unknown ,
399- "IOServiceMatching returned a NULL dictionary." ,
400- ) ) ;
401- }
402- let mut classes_to_match = CFMutableDictionary :: wrap_under_create_rule( classes_to_match) ;
386+ let classes_to_match = IOServiceMatching ( kIOSerialBSDServiceValue. as_ptr( ) )
387+ . ok_or_else( || Error :: new( ErrorKind :: Unknown , "IOServiceMatching returned a NULL dictionary." ) ) ?;
388+ let classes_to_match = classes_to_match. cast_unchecked:: <CFString , CFType >( ) ;
403389
404390 // Populate the search dictionary with a single key/value pair indicating that we're
405391 // searching for serial devices matching the RS232 device type.
406- let search_key = CStr :: from_ptr( kIOSerialBSDTypeKey) ;
407- let search_key = CFString :: from_static_string( search_key. to_str( ) . map_err( |_| Error :: new( ErrorKind :: Unknown , "Failed to convert search key string" ) ) ?) ;
408- let search_value = CStr :: from_ptr( kIOSerialBSDAllTypes) ;
409- let search_value = CFString :: from_static_string( search_value. to_str( ) . map_err( |_| Error :: new( ErrorKind :: Unknown , "Failed to convert search key string" ) ) ?) ;
410- classes_to_match. set( search_key, search_value) ;
392+ let search_key = CFString :: from_static_str( kIOSerialBSDTypeKey. to_str( ) . map_err( |_| Error :: new( ErrorKind :: Unknown , "Failed to convert search key string" ) ) ?) ;
393+ let search_value = CFString :: from_static_str( kIOSerialBSDAllTypes. to_str( ) . map_err( |_| Error :: new( ErrorKind :: Unknown , "Failed to convert search key string" ) ) ?) ;
394+ classes_to_match. set( & search_key, & search_value) ;
411395
412396 // Get an interface to IOKit
413397 let mut master_port: mach_port_t = MACH_PORT_NULL ;
398+ #[ allow( deprecated) ]
414399 let mut kern_result = IOMasterPort ( MACH_PORT_NULL , & mut master_port) ;
415400 if kern_result != KERN_SUCCESS {
416401 return Err ( Error :: new(
@@ -419,17 +404,11 @@ cfg_if! {
419404 ) ) ;
420405 }
421406
422- // Run the search. IOServiceGetMatchingServices consumes one reference count of
423- // classes_to_match, so explicitly retain.
424- //
425- // TODO: We could also just mem::forget classes_to_match like in
426- // TCFType::into_CFType. Is there a special reason that there is no
427- // TCFType::into_concrete_TypeRef()?
428- CFRetain ( classes_to_match. as_CFTypeRef( ) ) ;
407+ // Run the search.
429408 let mut matching_services = MaybeUninit :: uninit( ) ;
430409 kern_result = IOServiceGetMatchingServices (
431410 kIOMasterPortDefault,
432- classes_to_match. as_concrete_TypeRef ( ) ,
411+ Some ( classes_to_match. as_opaque ( ) . into ( ) ) ,
433412 matching_services. as_mut_ptr( ) ,
434413 ) ;
435414 if kern_result != KERN_SUCCESS {
@@ -467,15 +446,15 @@ cfg_if! {
467446 // properties dict has been allocated and we as the caller are in charge of
468447 // releasing it.
469448 let props = props. assume_init( ) ;
470- let props: CFDictionary <CFString , * const c_void> = CFDictionary :: wrap_under_create_rule( props) ;
449+ let props: CFRetained <CFMutableDictionary > = CFRetained :: from_raw( core:: ptr:: NonNull :: new( props) . unwrap( ) ) ;
450+ let props = props. cast_unchecked:: <CFString , CFType >( ) ;
471451
472452 for key in [ "IOCalloutDevice" , "IODialinDevice" ] . iter( ) {
473- let cf_key = CFString :: new ( key) ;
453+ let cf_key = CFString :: from_str ( key) ;
474454
475- if let Some ( cf_ref) = props. find( cf_key) {
476- let cf_type = CFType :: wrap_under_get_rule( * cf_ref) ;
455+ if let Some ( cf_type) = props. get( & cf_key) {
477456 match cf_type
478- . downcast :: <CFString >( )
457+ . downcast_ref :: <CFString >( )
479458 . map( |s| s. to_string( ) )
480459 {
481460 Some ( path) => {
0 commit comments