summaryrefslogtreecommitdiffstats
path: root/third_party/rust/termion/src/async.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/termion/src/async.rs')
-rw-r--r--third_party/rust/termion/src/async.rs78
1 files changed, 78 insertions, 0 deletions
diff --git a/third_party/rust/termion/src/async.rs b/third_party/rust/termion/src/async.rs
new file mode 100644
index 0000000000..f58b0444c6
--- /dev/null
+++ b/third_party/rust/termion/src/async.rs
@@ -0,0 +1,78 @@
+use std::io::{self, Read};
+use std::sync::mpsc;
+use std::thread;
+
+use sys::tty::get_tty;
+
+/// Construct an asynchronous handle to the TTY standard input.
+///
+/// This allows you to read from standard input _without blocking_ the current thread.
+/// Specifically, it works by firing up another thread to handle the event stream, which will then
+/// be buffered in a mpsc queue, which will eventually be read by the current thread.
+///
+/// This will not read the piped standard input, but rather read from the TTY device, since reading
+/// asyncronized from piped input would rarely make sense. In other words, if you pipe standard
+/// output from another process, it won't be reflected in the stream returned by this function, as
+/// this represents the TTY device, and not the piped standard input.
+pub fn async_stdin() -> AsyncReader {
+ let (send, recv) = mpsc::channel();
+
+ thread::spawn(move || for i in get_tty().unwrap().bytes() {
+ if send.send(i).is_err() {
+ return;
+ }
+ });
+
+ AsyncReader { recv: recv }
+}
+
+/// An asynchronous reader.
+///
+/// This acts as any other stream, with the exception that reading from it won't block. Instead,
+/// the buffer will only be partially updated based on how much the internal buffer holds.
+pub struct AsyncReader {
+ /// The underlying mpsc receiver.
+ recv: mpsc::Receiver<io::Result<u8>>,
+}
+
+// FIXME: Allow constructing an async reader from an arbitrary stream.
+
+impl Read for AsyncReader {
+ /// Read from the byte stream.
+ ///
+ /// This will never block, but try to drain the event queue until empty. If the total number of
+ /// bytes written is lower than the buffer's length, the event queue is empty or that the event
+ /// stream halted.
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ let mut total = 0;
+
+ loop {
+ if total >= buf.len() {
+ break;
+ }
+
+ match self.recv.try_recv() {
+ Ok(Ok(b)) => {
+ buf[total] = b;
+ total += 1;
+ }
+ Ok(Err(e)) => return Err(e),
+ Err(_) => break,
+ }
+ }
+
+ Ok(total)
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use std::io::Read;
+
+ #[test]
+ fn test_async_stdin() {
+ let stdin = async_stdin();
+ stdin.bytes().next();
+ }
+}