Skip to content

Commit aed0b05

Browse files
xtqqczzesylvestre
authored andcommitted
feat: refactor stdio handling
1 parent f1e051b commit aed0b05

7 files changed

Lines changed: 73 additions & 12 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/uu/cat/src/cat.rs

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -480,31 +480,25 @@ fn get_input_type(path: &OsString) -> CatResult<InputType> {
480480
/// Writes handle to stdout with no configuration. This allows a
481481
/// simple memory copy.
482482
fn print_fast<R: FdReadable>(handle: &mut InputHandle<R>) -> CatResult<()> {
483-
let stdout = io::stdout();
484-
#[cfg(any(target_os = "linux", target_os = "android"))]
485-
let mut stdout = stdout;
486483
#[cfg(any(target_os = "linux", target_os = "android"))]
487484
{
488485
// If we're on Linux or Android, try to use the splice() system call
489486
// for faster writing. If it works, we're done.
490-
if !splice::write_fast_using_splice(handle, &mut stdout)? {
487+
if !splice::write_fast_using_splice(handle, &mut *uucore::stdio::stdout_raw())? {
491488
return Ok(());
492489
}
493490
}
494491
// If we're not on Linux or Android, or the splice() call failed,
495492
// fall back on slower writing.
496-
print_unbuffered(handle, stdout)
493+
print_unbuffered(handle)
497494
}
498495

499496
#[cfg_attr(any(target_os = "linux", target_os = "android"), inline(never))] // splice fast-path does not require this allocation
500-
fn print_unbuffered<R: FdReadable>(
501-
handle: &mut InputHandle<R>,
502-
stdout: io::Stdout,
503-
) -> CatResult<()> {
497+
fn print_unbuffered<R: FdReadable>(handle: &mut InputHandle<R>) -> CatResult<()> {
504498
#[cfg(any(unix, target_os = "wasi"))]
505-
let mut stdout = uucore::io::RawWriter(stdout); // use raw syscall to remove buffering
499+
let mut stdout = uucore::stdio::stdout_raw();
506500
#[cfg(not(any(unix, target_os = "wasi")))]
507-
let mut stdout = stdout.lock();
501+
let mut stdout = io::stdout().lock();
508502
let mut buf = [0; 1024 * 64];
509503
loop {
510504
match handle.reader.read(&mut buf) {

src/uu/dd/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ doctest = false
2222
clap = { workspace = true }
2323
gcd = { workspace = true }
2424
libc = { workspace = true }
25+
rustix = { workspace = true }
2526
uucore = { workspace = true, features = [
2627
"format",
2728
"parser-size",

src/uucore/Cargo.toml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,13 @@ jiff = { workspace = true, optional = true, features = [
3636
"tzdb-concatenated",
3737
] }
3838
rustc-hash = { workspace = true }
39-
rustix = { workspace = true, features = ["fs", "net", "pipe", "process"] }
39+
rustix = { workspace = true, features = [
40+
"fs",
41+
"net",
42+
"pipe",
43+
"process",
44+
"stdio",
45+
] }
4046
time = { workspace = true, optional = true, features = [
4147
"formatting",
4248
"local-offset",

src/uucore/src/lib/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ pub use crate::mods::locale;
3232
pub use crate::mods::os;
3333
pub use crate::mods::panic;
3434
pub use crate::mods::posix;
35+
#[cfg(any(unix, target_os = "wasi"))]
36+
pub use crate::mods::stdio;
3537

3638
// * feature-gated modules
3739
#[cfg(feature = "backup-control")]

src/uucore/src/lib/mods.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@ pub mod locale;
1414
pub mod os;
1515
pub mod panic;
1616
pub mod posix;
17+
#[cfg(any(unix, target_os = "wasi"))]
18+
pub mod stdio;

src/uucore/src/lib/mods/stdio.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// This file is part of the uutils coreutils package.
2+
//
3+
// For the full copyright and license information, please view the LICENSE
4+
// file that was distributed with this source code.
5+
6+
//! Abstractions for raw access to stdin and stdout, without buffering.
7+
8+
use core::ops::{Deref, DerefMut};
9+
use std::{fs::File, mem::ManuallyDrop};
10+
11+
pub struct StdinRaw(ManuallyDrop<File>);
12+
13+
pub struct StdoutRaw(ManuallyDrop<File>);
14+
15+
pub fn stdin_raw() -> StdinRaw {
16+
// SAFETY: We ensure that the file descriptor is never closed by
17+
// wrapping the `File` in `ManuallyDrop`.
18+
let fd = unsafe { rustix::stdio::take_stdin() };
19+
StdinRaw(ManuallyDrop::new(File::from(fd)))
20+
}
21+
22+
pub fn stdout_raw() -> StdoutRaw {
23+
// SAFETY: We ensure that the file descriptor is never closed by
24+
// wrapping the `File` in `ManuallyDrop`.
25+
let fd = unsafe { rustix::stdio::take_stdout() };
26+
StdoutRaw(ManuallyDrop::new(File::from(fd)))
27+
}
28+
29+
impl Deref for StdinRaw {
30+
type Target = File;
31+
32+
fn deref(&self) -> &Self::Target {
33+
&self.0
34+
}
35+
}
36+
37+
impl DerefMut for StdinRaw {
38+
fn deref_mut(&mut self) -> &mut Self::Target {
39+
&mut self.0
40+
}
41+
}
42+
43+
impl Deref for StdoutRaw {
44+
type Target = File;
45+
46+
fn deref(&self) -> &Self::Target {
47+
&self.0
48+
}
49+
}
50+
51+
impl DerefMut for StdoutRaw {
52+
fn deref_mut(&mut self) -> &mut Self::Target {
53+
&mut self.0
54+
}
55+
}

0 commit comments

Comments
 (0)