Skip to content

Commit

Permalink
Migrate from libc to rustix.
Browse files Browse the repository at this point in the history
This migrates terminal_size from using libc directly to using rustix,
which eliminates a few unsafe blocks and manual error handling.

It does also add one new unsafe block, though this is because
`terminal_size_using_fd` is a public safe function that has a `RawFd`
argument. With [I/O safety], which is expected to be [stabilized in Rust 1.63],
there will be new guidance saying be that [such functions should be unsafe].
It's not urgent to make any changes for this right now though.

[I/O safety]: https://github.com/rust-lang/rfcs/blob/master/text/3128-io-safety.md
[expected to be stabilized in Rust 1.63]: rust-lang/rust#87074
[such functions should be unsafe]: https://doc.rust-lang.org/nightly/std/os/unix/io/index.html
  • Loading branch information
sunfishcode committed Jul 1, 2022
1 parent 0f36d74 commit 098751c
Show file tree
Hide file tree
Showing 5 changed files with 19 additions and 23 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ license = "MIT OR Apache-2.0"
edition = "2018"


[target.'cfg(not(windows))'.dependencies.libc]
version = "0.2"
[target.'cfg(not(windows))'.dependencies]
rustix = { version = "0.35.6", features = ["termios"] }

[target.'cfg(windows)'.dependencies.winapi]
version = "0.3"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ if let Some((Width(w), Height(h))) = size {

## Minimum Rust Version

This crate requires a minimum rust version of 1.31.0 (2018-12-06)
This crate requires a minimum rust version of 1.48.0 (2020-11-19)

## License

Expand Down
8 changes: 5 additions & 3 deletions examples/get_size.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,19 @@ fn run() {

#[cfg(not(windows))]
fn run() {
use std::os::unix::io::AsRawFd;

println!(
"Size from terminal_size_using_fd(stdout): {:?}",
terminal_size::terminal_size_using_fd(libc::STDOUT_FILENO)
terminal_size::terminal_size_using_fd(std::io::stdout().as_raw_fd())
);
println!(
"Size from terminal_size_using_fd(stderr): {:?}",
terminal_size::terminal_size_using_fd(libc::STDERR_FILENO)
terminal_size::terminal_size_using_fd(std::io::stderr().as_raw_fd())
);
println!(
"Size from terminal_size_using_fd(stdin): {:?}",
terminal_size::terminal_size_using_fd(libc::STDIN_FILENO)
terminal_size::terminal_size_using_fd(std::io::stdin().as_raw_fd())
);
}

Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//!
//! Supports both Linux, MacOS, and Windows.
//!
//! This crate requires a minimum rust version of 1.31.0 (2018-12-06)
//! This crate requires a minimum rust version of 1.48.0 (2020-11-19)
//!
//! # Example
//!
Expand Down
26 changes: 10 additions & 16 deletions src/unix.rs
Original file line number Diff line number Diff line change
@@ -1,37 +1,31 @@
use super::{Height, Width};
use std::os::unix::io::RawFd;
use rustix::fd::{BorrowedFd, AsRawFd};

/// Returns the size of the terminal defaulting to STDOUT, if available.
///
/// If STDOUT is not a tty, returns `None`
pub fn terminal_size() -> Option<(Width, Height)> {
terminal_size_using_fd(libc::STDOUT_FILENO)
terminal_size_using_fd(std::io::stdout().as_raw_fd())
}

/// Returns the size of the terminal using the given file descriptor, if available.
///
/// If the given file descriptor is not a tty, returns `None`
pub fn terminal_size_using_fd(fd: RawFd) -> Option<(Width, Height)> {
use libc::ioctl;
use libc::isatty;
use libc::{winsize as WinSize, TIOCGWINSZ};
let is_tty: bool = unsafe { isatty(fd) == 1 };
use rustix::termios::{isatty, tcgetwinsize};

if !is_tty {
return None;
}
// TODO: Once I/O safety is stabilized, the enlosing function here should
// be unsafe due to taking a `RawFd`. We should then move the main
// logic here into a new function which takes a `BorrowedFd` and is safe.
let fd = unsafe { BorrowedFd::borrow_raw(fd) };

let mut winsize = WinSize {
ws_row: 0,
ws_col: 0,
ws_xpixel: 0,
ws_ypixel: 0,
};

if unsafe { ioctl(fd, TIOCGWINSZ.into(), &mut winsize) } == -1 {
if !isatty(fd) {
return None;
}

let winsize = tcgetwinsize(fd).ok()?;

let rows = winsize.ws_row;
let cols = winsize.ws_col;

Expand Down

0 comments on commit 098751c

Please sign in to comment.