Skip to content

Commit 32f16ac

Browse files
committed
add stdio
1 parent 46d0188 commit 32f16ac

File tree

2 files changed

+138
-0
lines changed

2 files changed

+138
-0
lines changed

src/io/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ mod cursor;
55
mod empty;
66
mod read;
77
mod seek;
8+
mod stdio;
89
mod streams;
910
mod write;
1011

@@ -14,6 +15,7 @@ pub use cursor::*;
1415
pub use empty::*;
1516
pub use read::*;
1617
pub use seek::*;
18+
pub use stdio::*;
1719
pub use streams::*;
1820
pub use write::*;
1921

src/io/stdio.rs

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
use super::{AsyncInputStream, AsyncOutputStream};
2+
use std::cell::LazyCell;
3+
use wasi::cli::terminal_input::TerminalInput;
4+
use wasi::cli::terminal_output::TerminalOutput;
5+
6+
/// Use the program's stdin as an `AsyncInputStream`.
7+
pub struct Stdin {
8+
stream: AsyncInputStream,
9+
terminput: LazyCell<Option<TerminalInput>>,
10+
}
11+
12+
/// Get the program's stdin for use as an `AsyncInputStream`.
13+
pub fn stdin() -> Stdin {
14+
let stream = AsyncInputStream::new(wasi::cli::stdin::get_stdin());
15+
Stdin {
16+
stream,
17+
terminput: LazyCell::new(|| wasi::cli::terminal_stdin::get_terminal_stdin()),
18+
}
19+
}
20+
21+
impl std::ops::Deref for Stdin {
22+
type Target = AsyncInputStream;
23+
fn deref(&self) -> &AsyncInputStream {
24+
&self.stream
25+
}
26+
}
27+
impl std::ops::DerefMut for Stdin {
28+
fn deref_mut(&mut self) -> &mut AsyncInputStream {
29+
&mut self.stream
30+
}
31+
}
32+
33+
impl Stdin {
34+
/// Check if stdin is a terminal.
35+
pub fn is_terminal(&self) -> bool {
36+
LazyCell::force(&self.terminput).is_some()
37+
}
38+
}
39+
40+
/// Use the program's stdout as an `AsyncOutputStream`.
41+
pub struct Stdout {
42+
stream: AsyncOutputStream,
43+
termoutput: LazyCell<Option<TerminalOutput>>,
44+
}
45+
46+
/// Get the program's stdout for use as an `AsyncOutputStream`.
47+
pub fn stdout() -> Stdout {
48+
let stream = AsyncOutputStream::new(wasi::cli::stdout::get_stdout());
49+
Stdout {
50+
stream,
51+
termoutput: LazyCell::new(|| wasi::cli::terminal_stdout::get_terminal_stdout()),
52+
}
53+
}
54+
55+
impl Stdout {
56+
/// Check if stdout is a terminal.
57+
pub fn is_terminal(&self) -> bool {
58+
LazyCell::force(&self.termoutput).is_some()
59+
}
60+
}
61+
62+
impl std::ops::Deref for Stdout {
63+
type Target = AsyncOutputStream;
64+
fn deref(&self) -> &AsyncOutputStream {
65+
&self.stream
66+
}
67+
}
68+
impl std::ops::DerefMut for Stdout {
69+
fn deref_mut(&mut self) -> &mut AsyncOutputStream {
70+
&mut self.stream
71+
}
72+
}
73+
74+
/// Use the program's stdout as an `AsyncOutputStream`.
75+
pub struct Stderr {
76+
stream: AsyncOutputStream,
77+
termoutput: LazyCell<Option<TerminalOutput>>,
78+
}
79+
80+
/// Get the program's stdout for use as an `AsyncOutputStream`.
81+
pub fn stderr() -> Stderr {
82+
let stream = AsyncOutputStream::new(wasi::cli::stderr::get_stderr());
83+
Stderr {
84+
stream,
85+
termoutput: LazyCell::new(|| wasi::cli::terminal_stderr::get_terminal_stderr()),
86+
}
87+
}
88+
89+
impl Stderr {
90+
/// Check if stderr is a terminal.
91+
pub fn is_terminal(&self) -> bool {
92+
LazyCell::force(&self.termoutput).is_some()
93+
}
94+
}
95+
96+
impl std::ops::Deref for Stderr {
97+
type Target = AsyncOutputStream;
98+
fn deref(&self) -> &AsyncOutputStream {
99+
&self.stream
100+
}
101+
}
102+
impl std::ops::DerefMut for Stderr {
103+
fn deref_mut(&mut self) -> &mut AsyncOutputStream {
104+
&mut self.stream
105+
}
106+
}
107+
108+
#[cfg(test)]
109+
mod test {
110+
use crate::io::AsyncWrite;
111+
use crate::runtime::block_on;
112+
#[test]
113+
// No internal predicate. Run test with --nocapture and inspect output manually.
114+
fn stdout_println_hello_world() {
115+
block_on(async {
116+
let mut stdout = super::stdout();
117+
let term = if stdout.is_terminal() { "is" } else { "is not" };
118+
stdout
119+
.write_all(format!("hello, world! stdout {term} a terminal\n",).as_bytes())
120+
.await
121+
.unwrap();
122+
})
123+
}
124+
#[test]
125+
// No internal predicate. Run test with --nocapture and inspect output manually.
126+
fn stderr_println_hello_world() {
127+
block_on(async {
128+
let mut stdout = super::stdout();
129+
let term = if stdout.is_terminal() { "is" } else { "is not" };
130+
stdout
131+
.write_all(format!("hello, world! stderr {term} a terminal\n",).as_bytes())
132+
.await
133+
.unwrap();
134+
})
135+
}
136+
}

0 commit comments

Comments
 (0)