diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1c0d5ce8..87597f9b 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -67,7 +67,7 @@ jobs: disable_extra_builds: true disable_tests: true target: aarch64-apple-darwin - toolchain: "1.59.0" + toolchain: "1.71.0" msrv-arm-linux-androideabi: uses: ./.github/workflows/build.yaml @@ -75,7 +75,7 @@ jobs: disable_extra_builds: true disable_tests: true target: arm-linux-androideabi - toolchain: "1.59.0" + toolchain: "1.71.0" msrv-x86_64-unknown-freebsd: uses: ./.github/workflows/build.yaml @@ -83,7 +83,7 @@ jobs: disable_extra_builds: true disable_tests: true target: x86_64-unknown-freebsd - toolchain: "1.59.0" + toolchain: "1.71.0" msrv-x86_64-unknown-linux-gnu: uses: ./.github/workflows/build.yaml @@ -92,7 +92,7 @@ jobs: disable_tests: true extra_packages: libudev-dev target: x86_64-unknown-linux-gnu - toolchain: "1.59.0" + toolchain: "1.71.0" msrv-x86_64-unknown-linux-musl: uses: ./.github/workflows/build.yaml @@ -101,7 +101,7 @@ jobs: disable_tests: true extra_packages: gcc-aarch64-linux-gnu target: aarch64-unknown-linux-musl - toolchain: "1.59.0" + toolchain: "1.71.0" msrv-x86_64-pc-windows-msvc: uses: ./.github/workflows/build.yaml @@ -110,7 +110,7 @@ jobs: disable_tests: true runs_on: windows-2025 target: x86_64-pc-windows-msvc - toolchain: "1.59.0" + toolchain: "1.71.0" msrv-x86_64-unknown-netbsd: uses: ./.github/workflows/build.yaml @@ -118,7 +118,7 @@ jobs: disable_extra_builds: true disable_tests: true target: x86_64-unknown-netbsd - toolchain: "1.59.0" + toolchain: "1.71.0" # -------------------------------------------------------------------------- # Semantic Versioning diff --git a/CHANGELOG.md b/CHANGELOG.md index 3028fc6d..b0a3d0b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,9 @@ project adheres to [Semantic Versioning](https://semver.org/). * Output USB VID and PID in hexadecimal digits in `UsbPortInfo`'s `Debug` representation. [#290](https://github.com/serialport/serialport-rs/pull/290) +* Migrated away from unmaintainted dependency `mach2`. +* Migrated from `io-kit-sys` to `objc2-io-kit`. +* Migrated from `core-foundation` to `objc2-core-foundation`. ### Fixed ### Removed diff --git a/Cargo.toml b/Cargo.toml index 2790b55a..383cc476 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ authors = [ "Jesse Braham ", ] edition = "2021" -rust-version = "1.59.0" +rust-version = "1.71.0" description = "A cross-platform low-level serial port library." documentation = "https://docs.rs/serialport" repository = "https://github.com/serialport/serialport-rs" @@ -22,12 +22,22 @@ nix = { version = "0.26", default-features = false, features = ["fs", "ioctl", " libudev = { version = "0.3.0", optional = true } unescaper = "0.1.3" -[target.'cfg(any(target_os = "ios", target_os = "macos"))'.dependencies] -# TODO: Remove pinning this dependency when we are bumping our MSRV. -core-foundation = "=0.10.0" -core-foundation-sys = "0.8.4" -io-kit-sys = "0.4.0" -mach2 = "0.4.1" +[target.'cfg(target_vendor = "apple")'.dependencies] +objc2-io-kit = { version = "0.3.2", default-features = false, features = [ + "std", + "libc", + "usb", + "serial", + "IOUSBLib", + "IOUSBHostFamilyDefinitions", +] } +objc2-core-foundation = { version = "0.3.2", default-features = false, features = [ + "std", + "CFBase", + "CFDictionary", + "CFNumber", + "CFString", +] } [target."cfg(windows)".dependencies.windows-sys] version = "0.52.0" diff --git a/README.md b/README.md index 6a782dcf..fb523f69 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ [![crates.io version badge](https://img.shields.io/crates/v/serialport.svg)](https://crates.io/crates/serialport) [![Documentation](https://docs.rs/serialport/badge.svg)](https://docs.rs/serialport) [![GitHub workflow status](https://img.shields.io/github/actions/workflow/status/serialport/serialport-rs/ci.yaml?branch=main&logo=github)](https://github.com/serialport/serialport-rs/actions) -[![Minimum Stable Rust Version](https://img.shields.io/badge/Rust-1.59.0-blue?logo=rust)](https://blog.rust-lang.org/2022/02/24/Rust-1.59.0.html) +[![Minimum Stable Rust Version](https://img.shields.io/badge/Rust-1.71.0-blue?logo=rust)](https://blog.rust-lang.org/2023/07/13/Rust-1.71.0/) # Introduction @@ -116,7 +116,7 @@ can help debug software or hardware errors. # Dependencies -Rust versions 1.59.0 and higher are supported by the library itself. There are +Rust versions 1.71.0 and higher are supported by the library itself. There are examples requiring newer versions of Rust. For GNU/Linux `pkg-config` headers are required: @@ -152,7 +152,7 @@ demand. - `i686-unknown-linux-musl` - `x86_64-unknown-linux-gnu` - `x86_64-unknown-linux-musl` -- macOS/iOS +- macOS/iOS/tvOS/watchOS/visionOS - `aarch64-apple-darwin` - `aarch64-apple-ios` - `x86_64-apple-darwin` diff --git a/doc/platforms.md b/doc/platforms.md index 9c0fd329..247be35a 100644 --- a/doc/platforms.md +++ b/doc/platforms.md @@ -33,8 +33,8 @@ The BSDs basically **only** have the Termios2 API, but they call it Termios. It * https://man.openbsd.org/tty.4 -## macOS and iOS +## Darwin -While macOS and iOS have the heritage of a BSD, their support is slightly different. In theory, they support arbitrary baud rates in their Termios API much like the BSDs, but in practice this doesn't work with many hardware devices, as it's dependent on driver support. Instead, Apple added the `IOSSIOSPEED` ioctl in Mac OS X 10.4, which can set the baud rate to an arbitrary value. As the oldest macOS version supported by Rust is 10.7, it's available on all Mac platforms. +While macOS, iOS, and similar Apple platforms have the heritage of a BSD, their support is slightly different. In theory, they support arbitrary baud rates in their Termios API much like the BSDs, but in practice this doesn't work with many hardware devices, as it's dependent on driver support. Instead, Apple added the `IOSSIOSPEED` ioctl in Mac OS X 10.4, which can set the baud rate to an arbitrary value. As the oldest macOS version supported by Rust is 10.7, it's available on all Mac platforms. This API requires the port to be set into raw mode with `cfmakeraw`, and must be done after every call to `tcsetattr`, as that will reset the baud rate. Additionally, there is no way to retrieve the actual baud rate from the OS. This is therefore the clunkiest API of any platform. diff --git a/src/posix/enumerate.rs b/src/posix/enumerate.rs index 360c0cfc..e2ade32c 100644 --- a/src/posix/enumerate.rs +++ b/src/posix/enumerate.rs @@ -7,41 +7,47 @@ cfg_if! { } cfg_if! { - if #[cfg(any(target_os = "ios", target_os = "macos"))] { - use core_foundation::base::CFType; - use core_foundation::base::TCFType; - use core_foundation::dictionary::CFDictionary; - use core_foundation::dictionary::CFMutableDictionary; - use core_foundation::number::CFNumber; - use core_foundation::string::CFString; - use core_foundation_sys::base::{kCFAllocatorDefault, CFRetain}; - use io_kit_sys::*; - use io_kit_sys::keys::*; - use io_kit_sys::serial::keys::*; - use io_kit_sys::types::*; - use io_kit_sys::usb::lib::*; - use nix::libc::{c_char, c_void}; - use std::ffi::CStr; - use std::mem::MaybeUninit; + if #[cfg(target_vendor = "apple")] { + use core::ffi::{c_char, c_int, c_uint, CStr}; + use core::mem::MaybeUninit; + + use objc2_core_foundation::{ + kCFAllocatorDefault, CFMutableDictionary, CFNumber, CFRetained, CFString, CFType, + }; + #[allow(deprecated)] + use objc2_io_kit::{kIOMasterPortDefault, IOMasterPort}; + use objc2_io_kit::{ + io_object_t, io_registry_entry_t, kIOServiceClass, kIOUSBDeviceClassName, + kIOUSBHostInterfaceClassName, IOIteratorNext, IOObjectGetClass, IOObjectRelease, + IORegistryEntryCreateCFProperties, IORegistryEntryCreateCFProperty, + IORegistryEntryGetParentEntry, IOServiceGetMatchingServices, IOServiceMatching, + kIOSerialBSDServiceValue, kIOSerialBSDTypeKey, kIOSerialBSDAllTypes, + }; + + // NOTE: Do not use `mach` nor `mach2` crates, they're unmaintained, + // and don't work on tvOS/watchOS/visionOS. + // + // Instead, define the types ourselves, we use sufficiently little + // that this is not a very hard task. + #[allow(non_camel_case_types)] + type kern_return_t = c_int; + #[allow(non_camel_case_types)] + type mach_port_t = c_uint; + const KERN_SUCCESS: kern_return_t = 0; + const MACH_PORT_NULL: mach_port_t = 0; } } -#[cfg(any( - target_os = "freebsd", - target_os = "ios", - target_os = "linux", - target_os = "macos" -))] +#[cfg(any(target_os = "freebsd", target_os = "linux", target_vendor = "apple"))] use crate::SerialPortType; -#[cfg(any(target_os = "ios", target_os = "linux", target_os = "macos"))] +#[cfg(any(target_os = "linux", target_vendor = "apple"))] use crate::UsbPortInfo; #[cfg(any( target_os = "android", - target_os = "ios", all(target_os = "linux", not(target_env = "musl"), feature = "libudev"), - target_os = "macos", target_os = "netbsd", target_os = "openbsd", + target_vendor = "apple", ))] use crate::{Error, ErrorKind}; use crate::{Result, SerialPortInfo}; @@ -265,17 +271,15 @@ fn parse_modalias(moda: &str) -> Option { }) } -#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(target_vendor = "apple")] fn get_parent_device_by_type( device: io_object_t, - parent_type: *const c_char, + parent_type: &CStr, ) -> Option { - let parent_type = unsafe { CStr::from_ptr(parent_type) }; - use mach2::kern_return::KERN_SUCCESS; let mut device = device; loop { let mut class_name = MaybeUninit::<[c_char; 128]>::uninit(); - unsafe { IOObjectGetClass(device, class_name.as_mut_ptr() as *mut c_char) }; + unsafe { IOObjectGetClass(device, class_name.as_mut_ptr()) }; let class_name = unsafe { class_name.assume_init() }; let name = unsafe { CStr::from_ptr(&class_name[0]) }; if name == parent_type { @@ -283,8 +287,11 @@ fn get_parent_device_by_type( } let mut parent = MaybeUninit::uninit(); if unsafe { - IORegistryEntryGetParentEntry(device, kIOServiceClass, parent.as_mut_ptr()) - != KERN_SUCCESS + IORegistryEntryGetParentEntry( + device, + kIOServiceClass.as_ptr() as _, + parent.as_mut_ptr(), + ) != KERN_SUCCESS } { return None; } @@ -292,28 +299,21 @@ fn get_parent_device_by_type( } } -#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(target_vendor = "apple")] #[allow(non_upper_case_globals)] /// Returns a specific property of the given device as an integer. fn get_int_property(device_type: io_registry_entry_t, property: &str) -> Result { - let cf_property = CFString::new(property); - - let cf_type_ref = unsafe { - IORegistryEntryCreateCFProperty( - device_type, - cf_property.as_concrete_TypeRef(), - kCFAllocatorDefault, - 0, - ) - }; - if cf_type_ref.is_null() { - return Err(Error::new(ErrorKind::Unknown, "Failed to get property")); + let cf_property = CFString::from_str(property); + + let cf_type = unsafe { + IORegistryEntryCreateCFProperty(device_type, Some(&cf_property), kCFAllocatorDefault, 0) } + .ok_or_else(|| Error::new(ErrorKind::Unknown, "Failed to get property"))?; - let cf_type = unsafe { CFType::wrap_under_create_rule(cf_type_ref) }; cf_type .downcast::() - .and_then(|n| n.to_i64()) + .ok() + .and_then(|n| n.as_i64()) .map(|n| n as u32) .ok_or(Error::new( ErrorKind::Unknown, @@ -321,36 +321,30 @@ fn get_int_property(device_type: io_registry_entry_t, property: &str) -> Result< )) } -#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(target_vendor = "apple")] /// Returns a specific property of the given device as a string. fn get_string_property(device_type: io_registry_entry_t, property: &str) -> Result { - let cf_property = CFString::new(property); - - let cf_type_ref = unsafe { - IORegistryEntryCreateCFProperty( - device_type, - cf_property.as_concrete_TypeRef(), - kCFAllocatorDefault, - 0, - ) - }; - if cf_type_ref.is_null() { - return Err(Error::new(ErrorKind::Unknown, "Failed to get property")); + let cf_property = CFString::from_str(property); + + let cf_type = unsafe { + IORegistryEntryCreateCFProperty(device_type, Some(&cf_property), kCFAllocatorDefault, 0) } + .ok_or_else(|| Error::new(ErrorKind::Unknown, "Failed to get property"))?; - let cf_type = unsafe { CFType::wrap_under_create_rule(cf_type_ref) }; cf_type .downcast::() + .ok() .map(|s| s.to_string()) .ok_or(Error::new(ErrorKind::Unknown, "Failed to get string value")) } -#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(target_vendor = "apple")] /// Determine the serial port type based on the service object (like that returned by /// `IOIteratorNext`). Specific properties are extracted for USB devices. fn port_type(service: io_object_t) -> SerialPortType { - let bluetooth_device_class_name = b"IOBluetoothSerialClient\0".as_ptr() as *const c_char; - let usb_device_class_name = b"IOUSBHostInterface\0".as_ptr() as *const c_char; + let bluetooth_device_class_name = + CStr::from_bytes_with_nul(b"IOBluetoothSerialClient\0").unwrap(); + let usb_device_class_name = kIOUSBHostInterfaceClassName; let legacy_usb_device_class_name = kIOUSBDeviceClassName; let maybe_usb_device = get_parent_device_by_type(service, usb_device_class_name) @@ -381,35 +375,27 @@ fn port_type(service: io_object_t) -> SerialPortType { } cfg_if! { - if #[cfg(any(target_os = "ios", target_os = "macos"))] { + if #[cfg(target_vendor = "apple")] { /// Scans the system for serial ports and returns a list of them. /// The `SerialPortInfo` struct contains the name of the port which can be used for opening it. + #[allow(deprecated)] pub fn available_ports() -> Result> { - use mach2::kern_return::KERN_SUCCESS; - use mach2::port::{mach_port_t, MACH_PORT_NULL}; - let mut vec = Vec::new(); unsafe { // Create a dictionary for specifying the search terms against the IOService - let classes_to_match = IOServiceMatching(kIOSerialBSDServiceValue); - if classes_to_match.is_null() { - return Err(Error::new( - ErrorKind::Unknown, - "IOServiceMatching returned a NULL dictionary.", - )); - } - let mut classes_to_match = CFMutableDictionary::wrap_under_create_rule(classes_to_match); + let classes_to_match = IOServiceMatching(kIOSerialBSDServiceValue.as_ptr()) + .ok_or_else(|| Error::new(ErrorKind::Unknown, "IOServiceMatching returned a NULL dictionary."))?; + let classes_to_match = classes_to_match.cast_unchecked::(); // Populate the search dictionary with a single key/value pair indicating that we're // searching for serial devices matching the RS232 device type. - let search_key = CStr::from_ptr(kIOSerialBSDTypeKey); - let search_key = CFString::from_static_string(search_key.to_str().map_err(|_| Error::new(ErrorKind::Unknown, "Failed to convert search key string"))?); - let search_value = CStr::from_ptr(kIOSerialBSDAllTypes); - let search_value = CFString::from_static_string(search_value.to_str().map_err(|_| Error::new(ErrorKind::Unknown, "Failed to convert search key string"))?); - classes_to_match.set(search_key, search_value); + let search_key = CFString::from_static_str(kIOSerialBSDTypeKey.to_str().map_err(|_| Error::new(ErrorKind::Unknown, "Failed to convert search key string"))?); + let search_value = CFString::from_static_str(kIOSerialBSDAllTypes.to_str().map_err(|_| Error::new(ErrorKind::Unknown, "Failed to convert search key string"))?); + classes_to_match.set(&search_key, &search_value); // Get an interface to IOKit let mut master_port: mach_port_t = MACH_PORT_NULL; + #[allow(deprecated)] let mut kern_result = IOMasterPort(MACH_PORT_NULL, &mut master_port); if kern_result != KERN_SUCCESS { return Err(Error::new( @@ -418,17 +404,11 @@ cfg_if! { )); } - // Run the search. IOServiceGetMatchingServices consumes one reference count of - // classes_to_match, so explicitly retain. - // - // TODO: We could also just mem::forget classes_to_match like in - // TCFType::into_CFType. Is there a special reason that there is no - // TCFType::into_concrete_TypeRef()? - CFRetain(classes_to_match.as_CFTypeRef()); + // Run the search. let mut matching_services = MaybeUninit::uninit(); kern_result = IOServiceGetMatchingServices( kIOMasterPortDefault, - classes_to_match.as_concrete_TypeRef(), + Some(classes_to_match.as_opaque().into()), matching_services.as_mut_ptr(), ); if kern_result != KERN_SUCCESS { @@ -466,15 +446,15 @@ cfg_if! { // properties dict has been allocated and we as the caller are in charge of // releasing it. let props = props.assume_init(); - let props: CFDictionary = CFDictionary::wrap_under_create_rule(props); + let props: CFRetained = CFRetained::from_raw(core::ptr::NonNull::new(props).unwrap()); + let props = props.cast_unchecked::(); for key in ["IOCalloutDevice", "IODialinDevice"].iter() { - let cf_key = CFString::new(key); + let cf_key = CFString::from_str(key); - if let Some(cf_ref) = props.find(cf_key) { - let cf_type = CFType::wrap_under_get_rule(*cf_ref); + if let Some(cf_type) = props.get(&cf_key) { match cf_type - .downcast::() + .downcast_ref::() .map(|s| s.to_string()) { Some(path) => { diff --git a/src/posix/ioctl.rs b/src/posix/ioctl.rs index ced1c091..ffefd409 100644 --- a/src/posix/ioctl.rs +++ b/src/posix/ioctl.rs @@ -23,10 +23,9 @@ mod raw { #[cfg(any( target_os = "dragonfly", target_os = "freebsd", - target_os = "ios", - target_os = "macos", target_os = "netbsd", - target_os = "openbsd" + target_os = "openbsd", + target_vendor = "apple", ))] ioctl_read!(fionread, b'f', 127, libc::c_int); @@ -37,10 +36,9 @@ mod raw { #[cfg(any( target_os = "dragonfly", target_os = "freebsd", - target_os = "ios", - target_os = "macos", target_os = "netbsd", - target_os = "openbsd" + target_os = "openbsd", + target_vendor = "apple" ))] ioctl_read!(tiocoutq, b't', 115, libc::c_int); @@ -80,10 +78,10 @@ mod raw { 0x2B, libc::termios2 ); - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(target_vendor = "apple")] const IOSSIOSPEED: libc::c_ulong = 0x80045402; ioctl_write_ptr_bad!( - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(target_vendor = "apple")] iossiospeed, IOSSIOSPEED, libc::speed_t @@ -199,7 +197,7 @@ pub fn tcsets2(fd: RawFd, options: &libc::termios2) -> Result<()> { .map_err(|e| e.into()) } -#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(target_vendor = "apple")] pub fn iossiospeed(fd: RawFd, baud_rate: &libc::speed_t) -> Result<()> { unsafe { raw::iossiospeed(fd, baud_rate) } .map(|_| ()) diff --git a/src/posix/termios.rs b/src/posix/termios.rs index 23988218..42594b03 100644 --- a/src/posix/termios.rs +++ b/src/posix/termios.rs @@ -10,8 +10,6 @@ cfg_if! { if #[cfg(any( target_os = "dragonfly", target_os = "freebsd", - target_os = "ios", - target_os = "macos", target_os = "netbsd", target_os = "openbsd", all( @@ -21,7 +19,8 @@ cfg_if! { target_arch = "powerpc", target_arch = "powerpc64" ) - ) + ), + target_vendor = "apple", ))] { pub(crate) type Termios = libc::termios; } else if #[cfg(any( @@ -45,7 +44,7 @@ cfg_if! { // calls in this lib to the IOSSIOSPEED ioctl. So whenever we get this struct, make sure to // reset the input & output baud rates to a safe default. This is accounted for by the // corresponding set_termios that is mac-specific and always calls IOSSIOSPEED. -#[cfg(any(target_os = "ios", target_os = "macos",))] +#[cfg(target_vendor = "apple")] pub(crate) fn get_termios(fd: RawFd) -> Result { use std::mem::MaybeUninit; @@ -96,7 +95,7 @@ pub(crate) fn get_termios(fd: RawFd) -> Result { crate::posix::ioctl::tcgets2(fd) } -#[cfg(any(target_os = "ios", target_os = "macos",))] +#[cfg(target_vendor = "apple")] pub(crate) fn set_termios(fd: RawFd, termios: &libc::termios, baud_rate: u32) -> Result<()> { let res = unsafe { libc::tcsetattr(fd, libc::TCSANOW, termios) }; nix::errno::Errno::result(res)?; diff --git a/src/posix/tty.rs b/src/posix/tty.rs index 678c7c94..66ffb33e 100644 --- a/src/posix/tty.rs +++ b/src/posix/tty.rs @@ -68,7 +68,7 @@ pub struct TTYPort { timeout: Duration, exclusive: bool, port_name: Option, - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(target_vendor = "apple")] baud_rate: u32, } @@ -169,7 +169,7 @@ impl TTYPort { )); }; - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(target_vendor = "apple")] if builder.baud_rate > 0 { unsafe { libc::tcflush(fd.0, libc::TCIOFLUSH) }; } @@ -183,11 +183,11 @@ impl TTYPort { termios::set_flow_control(&mut termios, builder.flow_control); termios::set_data_bits(&mut termios, builder.data_bits); termios::set_stop_bits(&mut termios, builder.stop_bits); - #[cfg(not(any(target_os = "ios", target_os = "macos")))] + #[cfg(not(target_vendor = "apple"))] termios::set_baud_rate(&mut termios, builder.baud_rate)?; - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(target_vendor = "apple")] termios::set_termios(fd.0, &termios, builder.baud_rate)?; - #[cfg(not(any(target_os = "ios", target_os = "macos")))] + #[cfg(not(target_vendor = "apple"))] termios::set_termios(fd.0, &termios)?; // Return the final port object @@ -196,7 +196,7 @@ impl TTYPort { timeout: builder.timeout, exclusive: true, port_name: Some(builder.path.clone()), - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(target_vendor = "apple")] baud_rate: builder.baud_rate, }; @@ -318,7 +318,7 @@ impl TTYPort { let ptty_name = nix::pty::ptsname_r(&next_pty_fd)?; // Open the slave port - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(target_vendor = "apple")] let baud_rate = 9600; let fd = nix::fcntl::open( Path::new(&ptty_name), @@ -347,7 +347,7 @@ impl TTYPort { timeout: Duration::from_millis(100), exclusive: true, port_name: Some(ptty_name), - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(target_vendor = "apple")] baud_rate, }; @@ -359,7 +359,7 @@ impl TTYPort { timeout: Duration::from_millis(100), exclusive: true, port_name: None, - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(target_vendor = "apple")] baud_rate, }; @@ -396,7 +396,7 @@ impl TTYPort { exclusive: self.exclusive, port_name: self.port_name.clone(), timeout: self.timeout, - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(target_vendor = "apple")] baud_rate: self.baud_rate, }) } @@ -426,7 +426,7 @@ impl IntoRawFd for TTYPort { } /// Get the baud speed for a port from its file descriptor -#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(target_vendor = "apple")] fn get_termios_speed(fd: RawFd) -> u32 { let mut termios = MaybeUninit::uninit(); let res = unsafe { libc::tcgetattr(fd, termios.as_mut_ptr()) }; @@ -458,7 +458,7 @@ impl FromRawFd for TTYPort { // It's not guaranteed that the baud rate in the `termios` struct is correct, as // setting an arbitrary baud rate via the `iossiospeed` ioctl overrides that value, // but extract that value anyways as a best-guess of the actual baud rate. - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(target_vendor = "apple")] baud_rate: get_termios_speed(fd), } } @@ -559,7 +559,7 @@ impl SerialPort for TTYPort { /// /// On some platforms this will be the actual device baud rate, which may differ from the /// desired baud rate. - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(target_vendor = "apple")] fn baud_rate(&self) -> Result { Ok(self.baud_rate) } @@ -695,7 +695,7 @@ impl SerialPort for TTYPort { } // Mac OS needs special logic for setting arbitrary baud rates. - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(target_vendor = "apple")] fn set_baud_rate(&mut self, baud_rate: u32) -> Result<()> { ioctl::iossiospeed(self.fd, &(baud_rate as libc::speed_t))?; self.baud_rate = baud_rate; @@ -705,36 +705,36 @@ impl SerialPort for TTYPort { fn set_flow_control(&mut self, flow_control: FlowControl) -> Result<()> { let mut termios = termios::get_termios(self.fd)?; termios::set_flow_control(&mut termios, flow_control); - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(target_vendor = "apple")] return termios::set_termios(self.fd, &termios, self.baud_rate); - #[cfg(not(any(target_os = "ios", target_os = "macos")))] + #[cfg(not(target_vendor = "apple"))] return termios::set_termios(self.fd, &termios); } fn set_parity(&mut self, parity: Parity) -> Result<()> { let mut termios = termios::get_termios(self.fd)?; termios::set_parity(&mut termios, parity); - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(target_vendor = "apple")] return termios::set_termios(self.fd, &termios, self.baud_rate); - #[cfg(not(any(target_os = "ios", target_os = "macos")))] + #[cfg(not(target_vendor = "apple"))] return termios::set_termios(self.fd, &termios); } fn set_data_bits(&mut self, data_bits: DataBits) -> Result<()> { let mut termios = termios::get_termios(self.fd)?; termios::set_data_bits(&mut termios, data_bits); - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(target_vendor = "apple")] return termios::set_termios(self.fd, &termios, self.baud_rate); - #[cfg(not(any(target_os = "ios", target_os = "macos")))] + #[cfg(not(target_vendor = "apple"))] return termios::set_termios(self.fd, &termios); } fn set_stop_bits(&mut self, stop_bits: StopBits) -> Result<()> { let mut termios = termios::get_termios(self.fd)?; termios::set_stop_bits(&mut termios, stop_bits); - #[cfg(any(target_os = "ios", target_os = "macos"))] + #[cfg(target_vendor = "apple")] return termios::set_termios(self.fd, &termios, self.baud_rate); - #[cfg(not(any(target_os = "ios", target_os = "macos")))] + #[cfg(not(target_vendor = "apple"))] return termios::set_termios(self.fd, &termios); } diff --git a/tests/test_tty.rs b/tests/test_tty.rs index 46f4ae72..0b242553 100644 --- a/tests/test_tty.rs +++ b/tests/test_tty.rs @@ -91,7 +91,7 @@ fn test_ttyport_timeout() { } #[test] -#[cfg(any(target_os = "ios", target_os = "macos"))] +#[cfg(target_vendor = "apple")] fn test_osx_pty_pair() { #![allow(unused_variables)] let (mut master, slave) = TTYPort::pair().expect("Unable to create ptty pair"); @@ -116,7 +116,7 @@ fn test_osx_pty_pair() { // On Mac this should work (in fact used to in b77768a) but now fails. It's not functionality that // should be required, and the ptys work otherwise. So going to just disable this test instead. #[test] -#[cfg_attr(any(target_os = "ios", target_os = "macos"), ignore)] +#[cfg_attr(target_vendor = "apple", ignore)] fn test_ttyport_set_standard_baud() { // `master` must be used here as Dropping it causes slave to be deleted by the OS. // TODO: Convert this to a statement-level attribute once @@ -133,15 +133,10 @@ fn test_ttyport_set_standard_baud() { assert_eq!(slave.baud_rate().unwrap(), 115_200); } -// On mac this fails because you can't set nonstandard baud rates for these virtual ports #[test] #[cfg_attr( - any( - target_os = "ios", - all(target_os = "linux", target_env = "musl"), - target_os = "macos" - ), - ignore + any(all(target_os = "linux", target_env = "musl"), target_vendor = "apple"), + ignore = "fails on Mac because you can't set nonstandard baud rates for these virtual ports" )] fn test_ttyport_set_nonstandard_baud() { // `master` must be used here as Dropping it causes slave to be deleted by the OS.