Skip to content

Commit 42429d9

Browse files
committed
Use objc2-core-foundation and objc2-io-kit crates
1 parent bc212fb commit 42429d9

File tree

2 files changed

+67
-77
lines changed

2 files changed

+67
-77
lines changed

Cargo.toml

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,21 @@ libudev = { version = "0.3.0", optional = true }
2323
unescaper = "0.1.3"
2424

2525
[target.'cfg(target_vendor = "apple")'.dependencies]
26-
# TODO: Remove pinning this dependency when we are bumping our MSRV.
27-
core-foundation = "=0.10.0"
28-
core-foundation-sys = "0.8.4"
29-
io-kit-sys = "0.4.0"
26+
objc2-io-kit = { version = "0.3.2", default-features = false, features = [
27+
"std",
28+
"libc",
29+
"usb",
30+
"serial",
31+
"IOUSBLib",
32+
"IOUSBHostFamilyDefinitions",
33+
] }
34+
objc2-core-foundation = { version = "0.3.2", default-features = false, features = [
35+
"std",
36+
"CFBase",
37+
"CFDictionary",
38+
"CFNumber",
39+
"CFString",
40+
] }
3041

3142
[target."cfg(windows)".dependencies.windows-sys]
3243
version = "0.52.0"

src/posix/enumerate.rs

Lines changed: 52 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,22 @@ cfg_if! {
88

99
cfg_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")]
274275
fn 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.
302305
fn 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.
330326
fn 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.
355344
fn 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

Comments
 (0)