Skip to content

Commit b8cff8c

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 ed85d21 commit b8cff8c

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
core-foundation = "0.10.0"
2727
core-foundation-sys = "0.8.4"
2828
io-kit-sys = "0.4.0"

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
@@ -63,7 +63,7 @@ pub struct TTYPort {
6363
timeout: Duration,
6464
exclusive: bool,
6565
port_name: Option<String>,
66-
#[cfg(any(target_os = "ios", target_os = "macos"))]
66+
#[cfg(target_vendor = "apple")]
6767
baud_rate: u32,
6868
}
6969

@@ -161,7 +161,7 @@ impl TTYPort {
161161
));
162162
};
163163

164-
#[cfg(any(target_os = "ios", target_os = "macos"))]
164+
#[cfg(target_vendor = "apple")]
165165
if builder.baud_rate > 0 {
166166
unsafe { libc::tcflush(fd.0, libc::TCIOFLUSH) };
167167
}
@@ -175,11 +175,11 @@ impl TTYPort {
175175
termios::set_flow_control(&mut termios, builder.flow_control);
176176
termios::set_data_bits(&mut termios, builder.data_bits);
177177
termios::set_stop_bits(&mut termios, builder.stop_bits);
178-
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
178+
#[cfg(not(target_vendor = "apple"))]
179179
termios::set_baud_rate(&mut termios, builder.baud_rate)?;
180-
#[cfg(any(target_os = "ios", target_os = "macos"))]
180+
#[cfg(target_vendor = "apple")]
181181
termios::set_termios(fd.0, &termios, builder.baud_rate)?;
182-
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
182+
#[cfg(not(target_vendor = "apple"))]
183183
termios::set_termios(fd.0, &termios)?;
184184

185185
// Return the final port object
@@ -188,7 +188,7 @@ impl TTYPort {
188188
timeout: builder.timeout,
189189
exclusive: true,
190190
port_name: Some(builder.path.clone()),
191-
#[cfg(any(target_os = "ios", target_os = "macos"))]
191+
#[cfg(target_vendor = "apple")]
192192
baud_rate: builder.baud_rate,
193193
};
194194

@@ -295,7 +295,7 @@ impl TTYPort {
295295
let ptty_name = nix::pty::ptsname_r(&next_pty_fd)?;
296296

297297
// Open the slave port
298-
#[cfg(any(target_os = "ios", target_os = "macos"))]
298+
#[cfg(target_vendor = "apple")]
299299
let baud_rate = 9600;
300300
let fd = nix::fcntl::open(
301301
Path::new(&ptty_name),
@@ -324,7 +324,7 @@ impl TTYPort {
324324
timeout: Duration::from_millis(100),
325325
exclusive: true,
326326
port_name: Some(ptty_name),
327-
#[cfg(any(target_os = "ios", target_os = "macos"))]
327+
#[cfg(target_vendor = "apple")]
328328
baud_rate,
329329
};
330330

@@ -336,7 +336,7 @@ impl TTYPort {
336336
timeout: Duration::from_millis(100),
337337
exclusive: true,
338338
port_name: None,
339-
#[cfg(any(target_os = "ios", target_os = "macos"))]
339+
#[cfg(target_vendor = "apple")]
340340
baud_rate,
341341
};
342342

@@ -373,7 +373,7 @@ impl TTYPort {
373373
exclusive: self.exclusive,
374374
port_name: self.port_name.clone(),
375375
timeout: self.timeout,
376-
#[cfg(any(target_os = "ios", target_os = "macos"))]
376+
#[cfg(target_vendor = "apple")]
377377
baud_rate: self.baud_rate,
378378
})
379379
}
@@ -403,7 +403,7 @@ impl IntoRawFd for TTYPort {
403403
}
404404

405405
/// Get the baud speed for a port from its file descriptor
406-
#[cfg(any(target_os = "ios", target_os = "macos"))]
406+
#[cfg(target_vendor = "apple")]
407407
fn get_termios_speed(fd: RawFd) -> u32 {
408408
let mut termios = MaybeUninit::uninit();
409409
let res = unsafe { libc::tcgetattr(fd, termios.as_mut_ptr()) };
@@ -425,7 +425,7 @@ impl FromRawFd for TTYPort {
425425
// It's not guaranteed that the baud rate in the `termios` struct is correct, as
426426
// setting an arbitrary baud rate via the `iossiospeed` ioctl overrides that value,
427427
// but extract that value anyways as a best-guess of the actual baud rate.
428-
#[cfg(any(target_os = "ios", target_os = "macos"))]
428+
#[cfg(target_vendor = "apple")]
429429
baud_rate: get_termios_speed(fd),
430430
}
431431
}
@@ -526,7 +526,7 @@ impl SerialPort for TTYPort {
526526
///
527527
/// On some platforms this will be the actual device baud rate, which may differ from the
528528
/// desired baud rate.
529-
#[cfg(any(target_os = "ios", target_os = "macos"))]
529+
#[cfg(target_vendor = "apple")]
530530
fn baud_rate(&self) -> Result<u32> {
531531
Ok(self.baud_rate)
532532
}
@@ -662,7 +662,7 @@ impl SerialPort for TTYPort {
662662
}
663663

664664
// Mac OS needs special logic for setting arbitrary baud rates.
665-
#[cfg(any(target_os = "ios", target_os = "macos"))]
665+
#[cfg(target_vendor = "apple")]
666666
fn set_baud_rate(&mut self, baud_rate: u32) -> Result<()> {
667667
ioctl::iossiospeed(self.fd, &(baud_rate as libc::speed_t))?;
668668
self.baud_rate = baud_rate;
@@ -672,36 +672,36 @@ impl SerialPort for TTYPort {
672672
fn set_flow_control(&mut self, flow_control: FlowControl) -> Result<()> {
673673
let mut termios = termios::get_termios(self.fd)?;
674674
termios::set_flow_control(&mut termios, flow_control);
675-
#[cfg(any(target_os = "ios", target_os = "macos"))]
675+
#[cfg(target_vendor = "apple")]
676676
return termios::set_termios(self.fd, &termios, self.baud_rate);
677-
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
677+
#[cfg(not(target_vendor = "apple"))]
678678
return termios::set_termios(self.fd, &termios);
679679
}
680680

681681
fn set_parity(&mut self, parity: Parity) -> Result<()> {
682682
let mut termios = termios::get_termios(self.fd)?;
683683
termios::set_parity(&mut termios, parity);
684-
#[cfg(any(target_os = "ios", target_os = "macos"))]
684+
#[cfg(target_vendor = "apple")]
685685
return termios::set_termios(self.fd, &termios, self.baud_rate);
686-
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
686+
#[cfg(not(target_vendor = "apple"))]
687687
return termios::set_termios(self.fd, &termios);
688688
}
689689

690690
fn set_data_bits(&mut self, data_bits: DataBits) -> Result<()> {
691691
let mut termios = termios::get_termios(self.fd)?;
692692
termios::set_data_bits(&mut termios, data_bits);
693-
#[cfg(any(target_os = "ios", target_os = "macos"))]
693+
#[cfg(target_vendor = "apple")]
694694
return termios::set_termios(self.fd, &termios, self.baud_rate);
695-
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
695+
#[cfg(not(target_vendor = "apple"))]
696696
return termios::set_termios(self.fd, &termios);
697697
}
698698

699699
fn set_stop_bits(&mut self, stop_bits: StopBits) -> Result<()> {
700700
let mut termios = termios::get_termios(self.fd)?;
701701
termios::set_stop_bits(&mut termios, stop_bits);
702-
#[cfg(any(target_os = "ios", target_os = "macos"))]
702+
#[cfg(target_vendor = "apple")]
703703
return termios::set_termios(self.fd, &termios, self.baud_rate);
704-
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
704+
#[cfg(not(target_vendor = "apple"))]
705705
return termios::set_termios(self.fd, &termios);
706706
}
707707

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)