Skip to content

Commit 83547a8

Browse files
committed
Allow compiling on tvOS, watchOS and visionOS too
Assuming that the `mach2` crate is updated to support these platforms, or we get rid of that dependency.
1 parent dab9996 commit 83547a8

File tree

8 files changed

+50
-64
lines changed

8 files changed

+50
-64
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ nix = { version = "0.26", default-features = false, features = ["fs", "ioctl", "
2222
libudev = { version = "0.3.0", optional = true }
2323
unescaper = "0.1.3"
2424

25-
[target.'cfg(any(target_os = "ios", target_os = "macos"))'.dependencies]
25+
[target.'cfg(target_vendor = "apple")'.dependencies]
2626
# TODO: Remove pinning this dependency when we are bumping our MSRV.
2727
core-foundation = "=0.10.0"
2828
core-foundation-sys = "0.8.4"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ demand.
152152
- `i686-unknown-linux-musl`
153153
- `x86_64-unknown-linux-gnu`
154154
- `x86_64-unknown-linux-musl`
155-
- macOS/iOS
155+
- macOS/iOS/tvOS/watchOS/visionOS
156156
- `aarch64-apple-darwin`
157157
- `aarch64-apple-ios`
158158
- `x86_64-apple-darwin`

doc/platforms.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ The BSDs basically **only** have the Termios2 API, but they call it Termios. It
3333

3434
* https://man.openbsd.org/tty.4
3535

36-
## macOS and iOS
36+
## Darwin
3737

38-
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.
38+
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.
3939

4040
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.

src/posix/enumerate.rs

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ cfg_if! {
77
}
88

99
cfg_if! {
10-
if #[cfg(any(target_os = "ios", target_os = "macos"))] {
10+
if #[cfg(target_vendor = "apple")] {
1111
use core_foundation::base::CFType;
1212
use core_foundation::base::TCFType;
1313
use core_foundation::dictionary::CFDictionary;
@@ -26,22 +26,16 @@ cfg_if! {
2626
}
2727
}
2828

29-
#[cfg(any(
30-
target_os = "freebsd",
31-
target_os = "ios",
32-
target_os = "linux",
33-
target_os = "macos"
34-
))]
29+
#[cfg(any(target_os = "freebsd", target_os = "linux", target_vendor = "apple"))]
3530
use crate::SerialPortType;
36-
#[cfg(any(target_os = "ios", target_os = "linux", target_os = "macos"))]
31+
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
3732
use crate::UsbPortInfo;
3833
#[cfg(any(
3934
target_os = "android",
40-
target_os = "ios",
4135
all(target_os = "linux", not(target_env = "musl"), feature = "libudev"),
42-
target_os = "macos",
4336
target_os = "netbsd",
4437
target_os = "openbsd",
38+
target_vendor = "apple",
4539
))]
4640
use crate::{Error, ErrorKind};
4741
use crate::{Result, SerialPortInfo};
@@ -265,7 +259,7 @@ fn parse_modalias(moda: &str) -> Option<UsbPortInfo> {
265259
})
266260
}
267261

268-
#[cfg(any(target_os = "ios", target_os = "macos"))]
262+
#[cfg(target_vendor = "apple")]
269263
fn get_parent_device_by_type(
270264
device: io_object_t,
271265
parent_type: *const c_char,
@@ -292,7 +286,7 @@ fn get_parent_device_by_type(
292286
}
293287
}
294288

295-
#[cfg(any(target_os = "ios", target_os = "macos"))]
289+
#[cfg(target_vendor = "apple")]
296290
#[allow(non_upper_case_globals)]
297291
/// Returns a specific property of the given device as an integer.
298292
fn get_int_property(device_type: io_registry_entry_t, property: &str) -> Result<u32> {
@@ -321,7 +315,7 @@ fn get_int_property(device_type: io_registry_entry_t, property: &str) -> Result<
321315
))
322316
}
323317

324-
#[cfg(any(target_os = "ios", target_os = "macos"))]
318+
#[cfg(target_vendor = "apple")]
325319
/// Returns a specific property of the given device as a string.
326320
fn get_string_property(device_type: io_registry_entry_t, property: &str) -> Result<String> {
327321
let cf_property = CFString::new(property);
@@ -345,7 +339,7 @@ fn get_string_property(device_type: io_registry_entry_t, property: &str) -> Resu
345339
.ok_or(Error::new(ErrorKind::Unknown, "Failed to get string value"))
346340
}
347341

348-
#[cfg(any(target_os = "ios", target_os = "macos"))]
342+
#[cfg(target_vendor = "apple")]
349343
/// Determine the serial port type based on the service object (like that returned by
350344
/// `IOIteratorNext`). Specific properties are extracted for USB devices.
351345
fn port_type(service: io_object_t) -> SerialPortType {
@@ -381,7 +375,7 @@ fn port_type(service: io_object_t) -> SerialPortType {
381375
}
382376

383377
cfg_if! {
384-
if #[cfg(any(target_os = "ios", target_os = "macos"))] {
378+
if #[cfg(target_vendor = "apple")] {
385379
/// Scans the system for serial ports and returns a list of them.
386380
/// The `SerialPortInfo` struct contains the name of the port which can be used for opening it.
387381
pub fn available_ports() -> Result<Vec<SerialPortInfo>> {

src/posix/ioctl.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,9 @@ mod raw {
2323
#[cfg(any(
2424
target_os = "dragonfly",
2525
target_os = "freebsd",
26-
target_os = "ios",
27-
target_os = "macos",
2826
target_os = "netbsd",
29-
target_os = "openbsd"
27+
target_os = "openbsd",
28+
target_vendor = "apple",
3029
))]
3130
ioctl_read!(fionread, b'f', 127, libc::c_int);
3231

@@ -37,10 +36,9 @@ mod raw {
3736
#[cfg(any(
3837
target_os = "dragonfly",
3938
target_os = "freebsd",
40-
target_os = "ios",
41-
target_os = "macos",
4239
target_os = "netbsd",
43-
target_os = "openbsd"
40+
target_os = "openbsd",
41+
target_vendor = "apple"
4442
))]
4543
ioctl_read!(tiocoutq, b't', 115, libc::c_int);
4644

@@ -80,10 +78,10 @@ mod raw {
8078
0x2B,
8179
libc::termios2
8280
);
83-
#[cfg(any(target_os = "ios", target_os = "macos"))]
81+
#[cfg(target_vendor = "apple")]
8482
const IOSSIOSPEED: libc::c_ulong = 0x80045402;
8583
ioctl_write_ptr_bad!(
86-
#[cfg(any(target_os = "ios", target_os = "macos"))]
84+
#[cfg(target_vendor = "apple")]
8785
iossiospeed,
8886
IOSSIOSPEED,
8987
libc::speed_t
@@ -199,7 +197,7 @@ pub fn tcsets2(fd: RawFd, options: &libc::termios2) -> Result<()> {
199197
.map_err(|e| e.into())
200198
}
201199

202-
#[cfg(any(target_os = "ios", target_os = "macos"))]
200+
#[cfg(target_vendor = "apple")]
203201
pub fn iossiospeed(fd: RawFd, baud_rate: &libc::speed_t) -> Result<()> {
204202
unsafe { raw::iossiospeed(fd, baud_rate) }
205203
.map(|_| ())

src/posix/termios.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ cfg_if! {
1010
if #[cfg(any(
1111
target_os = "dragonfly",
1212
target_os = "freebsd",
13-
target_os = "ios",
14-
target_os = "macos",
1513
target_os = "netbsd",
1614
target_os = "openbsd",
1715
all(
@@ -21,7 +19,8 @@ cfg_if! {
2119
target_arch = "powerpc",
2220
target_arch = "powerpc64"
2321
)
24-
)
22+
),
23+
target_vendor = "apple",
2524
))] {
2625
pub(crate) type Termios = libc::termios;
2726
} else if #[cfg(any(
@@ -45,7 +44,7 @@ cfg_if! {
4544
// calls in this lib to the IOSSIOSPEED ioctl. So whenever we get this struct, make sure to
4645
// reset the input & output baud rates to a safe default. This is accounted for by the
4746
// corresponding set_termios that is mac-specific and always calls IOSSIOSPEED.
48-
#[cfg(any(target_os = "ios", target_os = "macos",))]
47+
#[cfg(target_vendor = "apple")]
4948
pub(crate) fn get_termios(fd: RawFd) -> Result<Termios> {
5049
use std::mem::MaybeUninit;
5150

@@ -96,7 +95,7 @@ pub(crate) fn get_termios(fd: RawFd) -> Result<Termios> {
9695
crate::posix::ioctl::tcgets2(fd)
9796
}
9897

99-
#[cfg(any(target_os = "ios", target_os = "macos",))]
98+
#[cfg(target_vendor = "apple")]
10099
pub(crate) fn set_termios(fd: RawFd, termios: &libc::termios, baud_rate: u32) -> Result<()> {
101100
let res = unsafe { libc::tcsetattr(fd, libc::TCSANOW, termios) };
102101
nix::errno::Errno::result(res)?;

src/posix/tty.rs

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ pub struct TTYPort {
6868
timeout: Duration,
6969
exclusive: bool,
7070
port_name: Option<String>,
71-
#[cfg(any(target_os = "ios", target_os = "macos"))]
71+
#[cfg(target_vendor = "apple")]
7272
baud_rate: u32,
7373
}
7474

@@ -169,7 +169,7 @@ impl TTYPort {
169169
));
170170
};
171171

172-
#[cfg(any(target_os = "ios", target_os = "macos"))]
172+
#[cfg(target_vendor = "apple")]
173173
if builder.baud_rate > 0 {
174174
unsafe { libc::tcflush(fd.0, libc::TCIOFLUSH) };
175175
}
@@ -183,11 +183,11 @@ impl TTYPort {
183183
termios::set_flow_control(&mut termios, builder.flow_control);
184184
termios::set_data_bits(&mut termios, builder.data_bits);
185185
termios::set_stop_bits(&mut termios, builder.stop_bits);
186-
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
186+
#[cfg(not(target_vendor = "apple"))]
187187
termios::set_baud_rate(&mut termios, builder.baud_rate)?;
188-
#[cfg(any(target_os = "ios", target_os = "macos"))]
188+
#[cfg(target_vendor = "apple")]
189189
termios::set_termios(fd.0, &termios, builder.baud_rate)?;
190-
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
190+
#[cfg(not(target_vendor = "apple"))]
191191
termios::set_termios(fd.0, &termios)?;
192192

193193
// Return the final port object
@@ -196,7 +196,7 @@ impl TTYPort {
196196
timeout: builder.timeout,
197197
exclusive: true,
198198
port_name: Some(builder.path.clone()),
199-
#[cfg(any(target_os = "ios", target_os = "macos"))]
199+
#[cfg(target_vendor = "apple")]
200200
baud_rate: builder.baud_rate,
201201
};
202202

@@ -318,7 +318,7 @@ impl TTYPort {
318318
let ptty_name = nix::pty::ptsname_r(&next_pty_fd)?;
319319

320320
// Open the slave port
321-
#[cfg(any(target_os = "ios", target_os = "macos"))]
321+
#[cfg(target_vendor = "apple")]
322322
let baud_rate = 9600;
323323
let fd = nix::fcntl::open(
324324
Path::new(&ptty_name),
@@ -347,7 +347,7 @@ impl TTYPort {
347347
timeout: Duration::from_millis(100),
348348
exclusive: true,
349349
port_name: Some(ptty_name),
350-
#[cfg(any(target_os = "ios", target_os = "macos"))]
350+
#[cfg(target_vendor = "apple")]
351351
baud_rate,
352352
};
353353

@@ -359,7 +359,7 @@ impl TTYPort {
359359
timeout: Duration::from_millis(100),
360360
exclusive: true,
361361
port_name: None,
362-
#[cfg(any(target_os = "ios", target_os = "macos"))]
362+
#[cfg(target_vendor = "apple")]
363363
baud_rate,
364364
};
365365

@@ -396,7 +396,7 @@ impl TTYPort {
396396
exclusive: self.exclusive,
397397
port_name: self.port_name.clone(),
398398
timeout: self.timeout,
399-
#[cfg(any(target_os = "ios", target_os = "macos"))]
399+
#[cfg(target_vendor = "apple")]
400400
baud_rate: self.baud_rate,
401401
})
402402
}
@@ -426,7 +426,7 @@ impl IntoRawFd for TTYPort {
426426
}
427427

428428
/// Get the baud speed for a port from its file descriptor
429-
#[cfg(any(target_os = "ios", target_os = "macos"))]
429+
#[cfg(target_vendor = "apple")]
430430
fn get_termios_speed(fd: RawFd) -> u32 {
431431
let mut termios = MaybeUninit::uninit();
432432
let res = unsafe { libc::tcgetattr(fd, termios.as_mut_ptr()) };
@@ -458,7 +458,7 @@ impl FromRawFd for TTYPort {
458458
// It's not guaranteed that the baud rate in the `termios` struct is correct, as
459459
// setting an arbitrary baud rate via the `iossiospeed` ioctl overrides that value,
460460
// but extract that value anyways as a best-guess of the actual baud rate.
461-
#[cfg(any(target_os = "ios", target_os = "macos"))]
461+
#[cfg(target_vendor = "apple")]
462462
baud_rate: get_termios_speed(fd),
463463
}
464464
}
@@ -559,7 +559,7 @@ impl SerialPort for TTYPort {
559559
///
560560
/// On some platforms this will be the actual device baud rate, which may differ from the
561561
/// desired baud rate.
562-
#[cfg(any(target_os = "ios", target_os = "macos"))]
562+
#[cfg(target_vendor = "apple")]
563563
fn baud_rate(&self) -> Result<u32> {
564564
Ok(self.baud_rate)
565565
}
@@ -695,7 +695,7 @@ impl SerialPort for TTYPort {
695695
}
696696

697697
// Mac OS needs special logic for setting arbitrary baud rates.
698-
#[cfg(any(target_os = "ios", target_os = "macos"))]
698+
#[cfg(target_vendor = "apple")]
699699
fn set_baud_rate(&mut self, baud_rate: u32) -> Result<()> {
700700
ioctl::iossiospeed(self.fd, &(baud_rate as libc::speed_t))?;
701701
self.baud_rate = baud_rate;
@@ -705,36 +705,36 @@ impl SerialPort for TTYPort {
705705
fn set_flow_control(&mut self, flow_control: FlowControl) -> Result<()> {
706706
let mut termios = termios::get_termios(self.fd)?;
707707
termios::set_flow_control(&mut termios, flow_control);
708-
#[cfg(any(target_os = "ios", target_os = "macos"))]
708+
#[cfg(target_vendor = "apple")]
709709
return termios::set_termios(self.fd, &termios, self.baud_rate);
710-
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
710+
#[cfg(not(target_vendor = "apple"))]
711711
return termios::set_termios(self.fd, &termios);
712712
}
713713

714714
fn set_parity(&mut self, parity: Parity) -> Result<()> {
715715
let mut termios = termios::get_termios(self.fd)?;
716716
termios::set_parity(&mut termios, parity);
717-
#[cfg(any(target_os = "ios", target_os = "macos"))]
717+
#[cfg(target_vendor = "apple")]
718718
return termios::set_termios(self.fd, &termios, self.baud_rate);
719-
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
719+
#[cfg(not(target_vendor = "apple"))]
720720
return termios::set_termios(self.fd, &termios);
721721
}
722722

723723
fn set_data_bits(&mut self, data_bits: DataBits) -> Result<()> {
724724
let mut termios = termios::get_termios(self.fd)?;
725725
termios::set_data_bits(&mut termios, data_bits);
726-
#[cfg(any(target_os = "ios", target_os = "macos"))]
726+
#[cfg(target_vendor = "apple")]
727727
return termios::set_termios(self.fd, &termios, self.baud_rate);
728-
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
728+
#[cfg(not(target_vendor = "apple"))]
729729
return termios::set_termios(self.fd, &termios);
730730
}
731731

732732
fn set_stop_bits(&mut self, stop_bits: StopBits) -> Result<()> {
733733
let mut termios = termios::get_termios(self.fd)?;
734734
termios::set_stop_bits(&mut termios, stop_bits);
735-
#[cfg(any(target_os = "ios", target_os = "macos"))]
735+
#[cfg(target_vendor = "apple")]
736736
return termios::set_termios(self.fd, &termios, self.baud_rate);
737-
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
737+
#[cfg(not(target_vendor = "apple"))]
738738
return termios::set_termios(self.fd, &termios);
739739
}
740740

tests/test_tty.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ fn test_ttyport_timeout() {
9191
}
9292

9393
#[test]
94-
#[cfg(any(target_os = "ios", target_os = "macos"))]
94+
#[cfg(target_vendor = "apple")]
9595
fn test_osx_pty_pair() {
9696
#![allow(unused_variables)]
9797
let (mut master, slave) = TTYPort::pair().expect("Unable to create ptty pair");
@@ -116,7 +116,7 @@ fn test_osx_pty_pair() {
116116
// On Mac this should work (in fact used to in b77768a) but now fails. It's not functionality that
117117
// should be required, and the ptys work otherwise. So going to just disable this test instead.
118118
#[test]
119-
#[cfg_attr(any(target_os = "ios", target_os = "macos"), ignore)]
119+
#[cfg_attr(target_vendor = "apple", ignore)]
120120
fn test_ttyport_set_standard_baud() {
121121
// `master` must be used here as Dropping it causes slave to be deleted by the OS.
122122
// TODO: Convert this to a statement-level attribute once
@@ -133,15 +133,10 @@ fn test_ttyport_set_standard_baud() {
133133
assert_eq!(slave.baud_rate().unwrap(), 115_200);
134134
}
135135

136-
// On mac this fails because you can't set nonstandard baud rates for these virtual ports
137136
#[test]
138137
#[cfg_attr(
139-
any(
140-
target_os = "ios",
141-
all(target_os = "linux", target_env = "musl"),
142-
target_os = "macos"
143-
),
144-
ignore
138+
any(all(target_os = "linux", target_env = "musl"), target_vendor = "apple"),
139+
ignore = "fails on Mac because you can't set nonstandard baud rates for these virtual ports"
145140
)]
146141
fn test_ttyport_set_nonstandard_baud() {
147142
// `master` must be used here as Dropping it causes slave to be deleted by the OS.

0 commit comments

Comments
 (0)