about summary refs log tree commit diff
path: root/src/libstd/rt/uv/uvio.rs
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-10-16 11:47:12 -0700
committerAlex Crichton <alex@alexcrichton.com>2013-10-24 14:21:57 -0700
commit35756fbcf6572d588929fde64fb4027f47e9d0af (patch)
tree8a2f0ec01c2eb26f5db34887b8b2335a844d5b9d /src/libstd/rt/uv/uvio.rs
parent32b07c6a40bd7e1874244096f413096a6e059a29 (diff)
downloadrust-35756fbcf6572d588929fde64fb4027f47e9d0af.tar.gz
rust-35756fbcf6572d588929fde64fb4027f47e9d0af.zip
Move rt::io::stdio from FileStream to a TTY
We get a little more functionality from libuv for these kinds of streams (things
like terminal dimentions), and it also appears to more gracefully handle the
stream being a window. Beforehand, if you used stdio and hit CTRL+d on a
process, libuv would continually return 0-length successful reads instead of
interpreting that the stream was closed.

I was hoping to be able to write tests for this, but currently the testing
infrastructure doesn't allow tests with a stdin and a stdout, but this has been
manually tested! (not that it means much)
Diffstat (limited to 'src/libstd/rt/uv/uvio.rs')
-rw-r--r--src/libstd/rt/uv/uvio.rs74
1 files changed, 74 insertions, 0 deletions
diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs
index db19bc7463a..f1a5916ee13 100644
--- a/src/libstd/rt/uv/uvio.rs
+++ b/src/libstd/rt/uv/uvio.rs
@@ -869,6 +869,18 @@ impl IoFactory for UvIoFactory {
         }
         return ret;
     }
+
+    fn tty_open(&mut self, fd: c_int, readable: bool, close_on_drop: bool)
+            -> Result<~RtioTTYObject, IoError> {
+        match tty::TTY::new(self.uv_loop(), fd, readable) {
+            Ok(tty) => Ok(~UvTTY {
+                home: get_handle_to_current_scheduler!(),
+                tty: tty,
+                close_on_drop: close_on_drop,
+            }),
+            Err(e) => Err(uv_error_to_io_error(e))
+        }
+    }
 }
 
 pub struct UvTcpListener {
@@ -1734,6 +1746,34 @@ impl RtioUnixListener for UvUnixListener {
     }
 }
 
+pub struct UvTTY {
+    tty: tty::TTY,
+    home: SchedHandle,
+    close_on_drop: bool,
+}
+
+impl HomingIO for UvTTY {
+    fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
+}
+
+impl Drop for UvTTY {
+    fn drop(&mut self) {
+        if self.close_on_drop {
+            let scheduler: ~Scheduler = Local::take();
+            do scheduler.deschedule_running_task_and_then |_, task| {
+                let task = Cell::new(task);
+                do self.tty.close {
+                    let scheduler: ~Scheduler = Local::take();
+                    scheduler.resume_blocked_task_immediately(task.take());
+                }
+            }
+        } else {
+            self.tty.drop_watcher_data();
+            unsafe { uvll::free_handle(self.tty.native_handle()) }
+        }
+    }
+}
+
 pub struct UvUnixAcceptor {
     listener: UvUnixListener,
     incoming: Tube<Result<~RtioPipeObject, IoError>>,
@@ -1769,6 +1809,40 @@ impl RtioUnixAcceptor for UvUnixAcceptor {
     }
 }
 
+impl RtioTTY for UvTTY {
+    fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
+        do self.home_for_io_with_sched |self_, scheduler| {
+            read_stream(self_.tty.as_stream(), scheduler, buf)
+        }
+    }
+
+    fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
+        do self.home_for_io_with_sched |self_, scheduler| {
+            write_stream(self_.tty.as_stream(), scheduler, buf)
+        }
+    }
+
+    fn set_raw(&mut self, raw: bool) -> Result<(), IoError> {
+        do self.home_for_io |self_| {
+            match self_.tty.set_mode(raw) {
+                Ok(p) => Ok(p), Err(e) => Err(uv_error_to_io_error(e))
+            }
+        }
+    }
+
+    fn reset_mode(&mut self) {
+        do self.home_for_io |self_| { self_.tty.reset_mode() }
+    }
+
+    fn get_winsize(&mut self) -> Result<(int, int), IoError> {
+        do self.home_for_io |self_| {
+            match self_.tty.get_winsize() {
+                Ok(p) => Ok(p), Err(e) => Err(uv_error_to_io_error(e))
+            }
+        }
+    }
+}
+
 #[test]
 fn test_simple_io_no_connect() {
     do run_in_mt_newsched_task {