forked from anoma/namada
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathio.rs
215 lines (190 loc) · 5.54 KB
/
io.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
//! Traits for implementing IO handlers. This is to enable
//! generic IO. The defaults are the obvious Rust native
//! functions.
use crate::{MaybeSend, MaybeSync};
/// A trait that abstracts out I/O operations
#[cfg_attr(feature = "async-send", async_trait::async_trait)]
#[cfg_attr(not(feature = "async-send"), async_trait::async_trait(?Send))]
pub trait Io {
/// Print the given string
fn print(&self, output: impl AsRef<str>) {
print!("{}", output.as_ref());
}
/// Flush the output
fn flush(&self) {
use std::io::Write;
std::io::stdout().flush().unwrap();
}
/// Print the given string with a newline
fn println(&self, output: impl AsRef<str>) {
println!("{}", output.as_ref());
}
/// Print the given string into the given Writer
fn write<W: std::io::Write>(
&self,
mut writer: W,
output: impl AsRef<str>,
) -> std::io::Result<()> {
write!(writer, "{}", output.as_ref())
}
/// Print the given string into the given Writer and terminate with newline
fn writeln<W: std::io::Write>(
&self,
mut writer: W,
output: impl AsRef<str>,
) -> std::io::Result<()> {
writeln!(writer, "{}", output.as_ref())
}
/// Print the given error string
fn eprintln(&self, output: impl AsRef<str>) {
eprintln!("{}", output.as_ref());
}
/// Read a string from input
async fn read(&self) -> std::io::Result<String> {
#[cfg(not(target_family = "wasm"))]
{
read_aux(tokio::io::stdin()).await
}
#[cfg(target_family = "wasm")]
{
unreachable!("Wasm should not perform general IO")
}
}
/// Display the given prompt and return the string input
async fn prompt(
&self,
question: impl AsRef<str> + MaybeSync + MaybeSend,
) -> String {
#[cfg(not(target_family = "wasm"))]
{
prompt_aux(
tokio::io::stdin(),
tokio::io::stdout(),
question.as_ref(),
)
.await
}
#[cfg(target_family = "wasm")]
{
unreachable!(
"Wasm should not perform general IO; received call for input \
with question\n: {}",
question.as_ref()
)
}
}
}
/// Rust native I/O handling.
#[derive(Default)]
pub struct StdIo;
#[cfg_attr(feature = "async-send", async_trait::async_trait)]
#[cfg_attr(not(feature = "async-send"), async_trait::async_trait(?Send))]
impl Io for StdIo {}
/// Ignores all I/O operations.
pub struct NullIo;
#[cfg_attr(feature = "async-send", async_trait::async_trait)]
#[cfg_attr(not(feature = "async-send"), async_trait::async_trait(?Send))]
impl Io for NullIo {
fn print(&self, _output: impl AsRef<str>) {}
fn flush(&self) {}
fn println(&self, _output: impl AsRef<str>) {}
fn write<W: std::io::Write>(
&self,
mut _writer: W,
_output: impl AsRef<str>,
) -> std::io::Result<()> {
Ok(())
}
fn writeln<W: std::io::Write>(
&self,
mut _writer: W,
_output: impl AsRef<str>,
) -> std::io::Result<()> {
Ok(())
}
fn eprintln(&self, _output: impl AsRef<str>) {}
async fn read(&self) -> std::io::Result<String> {
panic!("Unsupported operation")
}
async fn prompt(
&self,
_question: impl AsRef<str> + MaybeSend + MaybeSync,
) -> String {
panic!("Unsupported operation")
}
}
/// A generic function for displaying a prompt to users and reading
/// in their response.
#[cfg(not(target_family = "wasm"))]
pub async fn prompt_aux<R, W>(
mut reader: R,
mut writer: W,
question: &str,
) -> String
where
R: tokio::io::AsyncReadExt + Unpin,
W: tokio::io::AsyncWriteExt + Unpin,
{
writer
.write_all(question.as_bytes())
.await
.expect("Unable to write");
writer.flush().await.unwrap();
let mut s = String::new();
reader.read_to_string(&mut s).await.expect("Unable to read");
s
}
/// A generic function for reading input from users
#[cfg(not(target_family = "wasm"))]
pub async fn read_aux<R>(mut reader: R) -> tokio::io::Result<String>
where
R: tokio::io::AsyncReadExt + Unpin,
{
let mut s = String::new();
reader.read_to_string(&mut s).await?;
Ok(s)
}
/// Convenience macro for formatting arguments to
/// [`Io::print`]
#[macro_export]
macro_rules! display {
($io:expr) => {
$io.print("")
};
($io:expr, $w:expr; $($args:tt)*) => {
$io.write($w, format_args!($($args)*).to_string())
};
($io:expr,$($args:tt)*) => {
$io.print(format_args!($($args)*).to_string())
};
}
/// Convenience macro for formatting arguments to
/// [`Io::println`] and [`Io::writeln`]
#[macro_export]
macro_rules! display_line {
($io:expr) => {
$io.println("")
};
($io:expr, $w:expr; $($args:tt)*) => {
$io.writeln($w, format_args!($($args)*).to_string())
};
($io:expr,$($args:tt)*) => {
$io.println(format_args!($($args)*).to_string())
};
}
/// Convenience macro for formatting arguments to
/// [`Io::eprintln`]
#[macro_export]
macro_rules! edisplay_line {
($io:expr,$($args:tt)*) => {
$io.eprintln(format_args!($($args)*).to_string())
};
}
#[macro_export]
/// A convenience macro for formatting the user prompt before
/// forwarding it to the [`Io::prompt`] method.
macro_rules! prompt {
($io:expr,$($arg:tt)*) => {{
$io.prompt(format!("{}", format_args!($($arg)*)))
}}
}