Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sys/termios: add cross-platform API for arbitrary baud rates #1632

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -33,6 +33,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).
(#[1615](https://github.com/nix-rust/nix/pull/1615))
- Added `getresuid`, `setresuid`, `getresgid`, and `setresgid` on DragonFly, FreeBSD, and OpenBSD.
(#[1628](https://github.com/nix-rust/nix/pull/1628))
- Added `sys::termios::ArbitraryBaudRate` and `TryFrom<ArbitraryBaudRate> for BaudRate`,a cross-platform API for arbitrary baud rate conversion.
(#[1632](https://github.com/nix-rust/nix/pull/1632))

### Changed
### Fixed
Expand Down
126 changes: 125 additions & 1 deletion src/sys/termios.rs
Expand Up @@ -70,6 +70,19 @@
//! # }
//! ```
//!
//! For convenience a cross-platform [`ArbitraryBaudRate`] is available that converts a `u32` to a `BaudRate`:
//!
//! ```rust
//! # use nix::sys::termios::{BaudRate, cfsetispeed, cfsetospeed, cfsetspeed, Termios, ArbitraryBaudRate};
//! # use std::convert::TryFrom;
//! # fn main() {
//! # let mut t: Termios = unsafe { std::mem::zeroed() };
//! cfsetispeed(&mut t, BaudRate::try_from(ArbitraryBaudRate(9600)).unwrap());
//! cfsetospeed(&mut t, BaudRate::try_from(ArbitraryBaudRate(9600)).unwrap());
//! cfsetspeed(&mut t, BaudRate::try_from(ArbitraryBaudRate(9600)).unwrap());
//! # }
//! ```
//!
//! Additionally round-tripping baud rates is consistent across platforms:
//!
//! ```rust
Expand Down Expand Up @@ -159,6 +172,7 @@ use std::cell::{Ref, RefCell};
use std::convert::From;
use std::mem;
use std::os::unix::io::RawFd;
use std::convert::TryFrom;

#[cfg(feature = "process")]
use crate::unistd::Pid;
Expand Down Expand Up @@ -374,6 +388,110 @@ impl From<BaudRate> for u32 {
}
}

/// Representation for arbitrary baud rates for systems that do not
/// otherwise support it.
///
/// ```rust
/// # use nix::sys::termios::{BaudRate, ArbitraryBaudRate};
/// # use std::convert::TryFrom;
/// assert_eq!(Ok(BaudRate::B9600), BaudRate::try_from(ArbitraryBaudRate(9600)));
/// ```
#[derive(Copy, Debug, Clone)]
pub struct ArbitraryBaudRate(pub u32);

impl TryFrom<ArbitraryBaudRate> for BaudRate {
type Error = Errno;

fn try_from(abr: ArbitraryBaudRate) -> Result<BaudRate> {
use BaudRate::*;

Ok(match abr.0 {
0 => B0,
50 => B50,
75 => B75,
110 => B110,
134 => B134,
150 => B150,
200 => B200,
300 => B300,
600 => B600,
1200 => B1200,
1800 => B1800,
2400 => B2400,
4800 => B4800,
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
7200 => B7200,
9600 => B9600,
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
14400 => B14400,
19200 => B19200,
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
28800 => B28800,
38400 => B38400,
57600 => B57600,
#[cfg(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd"))]
76800 => B76800,
115200 => B115200,
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
153600 => B153600,
230400 => B230400,
#[cfg(any(target_os = "illumos", target_os = "solaris"))]
307200 => B307200,
#[cfg(any(target_os = "android",
target_os = "freebsd",
target_os = "illumos",
target_os = "linux",
target_os = "netbsd",
target_os = "solaris"))]
460800 => B460800,
#[cfg(any(target_os = "android", target_os = "linux"))]
500000 => B500000,
#[cfg(any(target_os = "android", target_os = "linux"))]
576000 => B576000,
#[cfg(any(target_os = "android",
target_os = "freebsd",
target_os = "illumos",
target_os = "linux",
target_os = "netbsd",
target_os = "solaris"))]
921600 => B921600,
#[cfg(any(target_os = "android", target_os = "linux"))]
1000000 => B1000000,
#[cfg(any(target_os = "android", target_os = "linux"))]
1152000 => B1152000,
#[cfg(any(target_os = "android", target_os = "linux"))]
1500000 => B1500000,
#[cfg(any(target_os = "android", target_os = "linux"))]
2000000 => B2000000,
#[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
2500000 => B2500000,
#[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
3000000 => B3000000,
#[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
3500000 => B3500000,
#[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
4000000 => B4000000,
_ => return Err(Errno::EINVAL),
})
}
}

// TODO: Add TCSASOFT, which will require treating this as a bitfield.
libc_enum! {
/// Specify when a port configuration change should occur.
Expand Down Expand Up @@ -1092,8 +1210,14 @@ mod test {
use std::convert::TryFrom;

#[test]
fn try_from() {
fn try_from_speed_t() {
assert_eq!(Ok(BaudRate::B0), BaudRate::try_from(libc::B0));
assert!(BaudRate::try_from(999999999).is_err());
}

#[test]
fn try_from_arbitrary_baud_rate() {
assert_eq!(Ok(BaudRate::B9600), BaudRate::try_from(ArbitraryBaudRate(9600)));
assert!(BaudRate::try_from(ArbitraryBaudRate(999999999)).is_err());
}
}