Skip to content

Commit e2db313

Browse files
authored
Merge pull request #208 from Berrysoft:dev/stdio
feat: add stdio
2 parents 376000c + 284bddc commit e2db313

File tree

7 files changed

+431
-1
lines changed

7 files changed

+431
-1
lines changed

compio-driver/src/iocp/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ pub trait AsRawFd {
5656

5757
/// Construct IO objects from raw fds.
5858
pub trait FromRawFd {
59-
/// Constructs a new IO object from the specified raw fd.
59+
/// Constructs an IO object from the specified raw fd.
6060
///
6161
/// # Safety
6262
///

compio-fs/Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ compio-driver = { workspace = true }
2121
compio-io = { workspace = true }
2222
compio-runtime = { workspace = true }
2323

24+
cfg-if = { workspace = true }
25+
2426
# Windows specific dependencies
2527
[target.'cfg(windows)'.dependencies]
2628
widestring = { workspace = true }
@@ -55,3 +57,9 @@ windows-sys = { workspace = true, features = ["Win32_Security_Authorization"] }
5557
# Unix specific dev dependencies
5658
[target.'cfg(unix)'.dev-dependencies]
5759
nix = { workspace = true, features = ["fs"] }
60+
61+
[features]
62+
default = []
63+
64+
read_buf = ["compio-buf/read_buf", "compio-io/read_buf"]
65+
nightly = ["read_buf"]

compio-fs/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
44
#![warn(missing_docs)]
5+
#![cfg_attr(feature = "read_buf", feature(read_buf, core_io_borrowed_buf))]
56

67
mod file;
78
pub use file::*;
@@ -12,6 +13,9 @@ pub use open_options::*;
1213
mod metadata;
1314
pub use metadata::*;
1415

16+
mod stdio;
17+
pub use stdio::*;
18+
1519
#[cfg(windows)]
1620
pub mod named_pipe;
1721

compio-fs/src/stdio/mod.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
cfg_if::cfg_if! {
2+
if #[cfg(windows)] {
3+
mod windows;
4+
pub use windows::*;
5+
} else if #[cfg(unix)] {
6+
mod unix;
7+
pub use unix::*;
8+
}
9+
}
10+
11+
/// Constructs a handle to the standard input of the current process.
12+
///
13+
/// ## Platform specific
14+
/// * Windows: This handle is best used for non-interactive uses, such as when a
15+
/// file is piped into the application. For technical reasons, if `stdin` is a
16+
/// console handle, the read method is implemented by using an ordinary
17+
/// blocking read on a separate thread, and it is impossible to cancel that
18+
/// read. This can make shutdown of the runtime hang until the user presses
19+
/// enter.
20+
///
21+
/// [`AsyncRead`]: compio_io::AsyncRead
22+
pub fn stdin() -> Stdin {
23+
Stdin::new()
24+
}
25+
26+
/// Constructs a handle to the standard output of the current process.
27+
///
28+
/// Concurrent writes to stdout must be executed with care: Only individual
29+
/// writes to this [`AsyncWrite`] are guaranteed to be intact. In particular
30+
/// you should be aware that writes using [`write_all`] are not guaranteed
31+
/// to occur as a single write, so multiple threads writing data with
32+
/// [`write_all`] may result in interleaved output.
33+
///
34+
/// [`AsyncWrite`]: compio_io::AsyncWrite
35+
/// [`write_all`]: compio_io::AsyncWriteExt::write_all
36+
pub fn stdout() -> Stdout {
37+
Stdout::new()
38+
}
39+
40+
/// Constructs a handle to the standard error of the current process.
41+
///
42+
/// Concurrent writes to stderr must be executed with care: Only individual
43+
/// writes to this [`AsyncWrite`] are guaranteed to be intact. In particular
44+
/// you should be aware that writes using [`write_all`] are not guaranteed
45+
/// to occur as a single write, so multiple threads writing data with
46+
/// [`write_all`] may result in interleaved output.
47+
///
48+
/// [`AsyncWrite`]: compio_io::AsyncWrite
49+
/// [`write_all`]: compio_io::AsyncWriteExt::write_all
50+
pub fn stderr() -> Stderr {
51+
Stderr::new()
52+
}

compio-fs/src/stdio/unix.rs

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
use std::{io, mem::ManuallyDrop};
2+
3+
use compio_buf::{BufResult, IoBuf, IoBufMut, IoVectoredBuf, IoVectoredBufMut};
4+
use compio_driver::{FromRawFd, RawFd};
5+
use compio_io::{AsyncRead, AsyncWrite};
6+
use compio_runtime::TryAsRawFd;
7+
8+
use crate::pipe::{Receiver, Sender};
9+
10+
/// A handle to the standard input stream of a process.
11+
///
12+
/// See [`stdin`].
13+
pub struct Stdin(ManuallyDrop<Receiver>);
14+
15+
impl Stdin {
16+
pub(crate) fn new() -> Self {
17+
// SAFETY: we don't drop it
18+
Self(ManuallyDrop::new(unsafe {
19+
Receiver::from_raw_fd(libc::STDIN_FILENO)
20+
}))
21+
}
22+
}
23+
24+
impl AsyncRead for Stdin {
25+
async fn read<B: IoBufMut>(&mut self, buf: B) -> BufResult<usize, B> {
26+
self.0.read(buf).await
27+
}
28+
29+
async fn read_vectored<V: IoVectoredBufMut>(&mut self, buf: V) -> BufResult<usize, V> {
30+
self.0.read_vectored(buf).await
31+
}
32+
}
33+
34+
impl TryAsRawFd for Stdin {
35+
fn try_as_raw_fd(&self) -> io::Result<RawFd> {
36+
self.0.try_as_raw_fd()
37+
}
38+
39+
unsafe fn as_raw_fd_unchecked(&self) -> RawFd {
40+
self.0.as_raw_fd_unchecked()
41+
}
42+
}
43+
44+
/// A handle to the standard output stream of a process.
45+
///
46+
/// See [`stdout`].
47+
pub struct Stdout(ManuallyDrop<Sender>);
48+
49+
impl Stdout {
50+
pub(crate) fn new() -> Self {
51+
// SAFETY: we don't drop it
52+
Self(ManuallyDrop::new(unsafe {
53+
Sender::from_raw_fd(libc::STDOUT_FILENO)
54+
}))
55+
}
56+
}
57+
58+
impl AsyncWrite for Stdout {
59+
async fn write<T: IoBuf>(&mut self, buf: T) -> BufResult<usize, T> {
60+
self.0.write(buf).await
61+
}
62+
63+
async fn write_vectored<T: IoVectoredBuf>(&mut self, buf: T) -> BufResult<usize, T> {
64+
self.0.write_vectored(buf).await
65+
}
66+
67+
async fn flush(&mut self) -> io::Result<()> {
68+
self.0.flush().await
69+
}
70+
71+
async fn shutdown(&mut self) -> io::Result<()> {
72+
self.0.shutdown().await
73+
}
74+
}
75+
76+
impl TryAsRawFd for Stdout {
77+
fn try_as_raw_fd(&self) -> io::Result<RawFd> {
78+
self.0.try_as_raw_fd()
79+
}
80+
81+
unsafe fn as_raw_fd_unchecked(&self) -> RawFd {
82+
self.0.as_raw_fd_unchecked()
83+
}
84+
}
85+
86+
/// A handle to the standard output stream of a process.
87+
///
88+
/// See [`stderr`].
89+
pub struct Stderr(ManuallyDrop<Sender>);
90+
91+
impl Stderr {
92+
pub(crate) fn new() -> Self {
93+
// SAFETY: we don't drop it
94+
Self(ManuallyDrop::new(unsafe {
95+
Sender::from_raw_fd(libc::STDERR_FILENO)
96+
}))
97+
}
98+
}
99+
100+
impl AsyncWrite for Stderr {
101+
async fn write<T: IoBuf>(&mut self, buf: T) -> BufResult<usize, T> {
102+
self.0.write(buf).await
103+
}
104+
105+
async fn write_vectored<T: IoVectoredBuf>(&mut self, buf: T) -> BufResult<usize, T> {
106+
self.0.write_vectored(buf).await
107+
}
108+
109+
async fn flush(&mut self) -> io::Result<()> {
110+
self.0.flush().await
111+
}
112+
113+
async fn shutdown(&mut self) -> io::Result<()> {
114+
self.0.shutdown().await
115+
}
116+
}
117+
118+
impl TryAsRawFd for Stderr {
119+
fn try_as_raw_fd(&self) -> io::Result<RawFd> {
120+
self.0.try_as_raw_fd()
121+
}
122+
123+
unsafe fn as_raw_fd_unchecked(&self) -> RawFd {
124+
self.0.as_raw_fd_unchecked()
125+
}
126+
}

0 commit comments

Comments
 (0)