From bac96818580a97c049532e50702c2a8204e11754 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 15 Oct 2013 19:44:08 -0700 Subject: [PATCH 01/23] Implement io::net::unix --- src/libstd/rt/io/net/unix.rs | 284 +++++++++++++++++++++++++++++++++-- src/libstd/rt/io/pipe.rs | 4 +- src/libstd/rt/io/process.rs | 2 +- src/libstd/rt/rtio.rs | 19 ++- src/libstd/rt/test.rs | 10 ++ src/libstd/rt/uv/net.rs | 73 +++++---- src/libstd/rt/uv/pipe.rs | 51 ++++++- src/libstd/rt/uv/process.rs | 6 +- src/libstd/rt/uv/uvio.rs | 205 +++++++++++++++++++++---- src/libstd/rt/uv/uvll.rs | 19 +++ src/rt/rustrt.def.in | 15 ++ 11 files changed, 602 insertions(+), 86 deletions(-) diff --git a/src/libstd/rt/io/net/unix.rs b/src/libstd/rt/io/net/unix.rs index 1771a963ba78c..9428c1f800d15 100644 --- a/src/libstd/rt/io/net/unix.rs +++ b/src/libstd/rt/io/net/unix.rs @@ -8,44 +8,296 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +/*! + +Named pipes + +This module contains the ability to communicate over named pipes with +synchronous I/O. On windows, this corresponds to talking over a Named Pipe, +while on Unix it corresponds to UNIX domain sockets. + +These pipes are similar to TCP in the sense that you can have both a stream to a +server and a server itself. The server provided accepts other `UnixStream` +instances as clients. + +*/ + use prelude::*; -use super::super::*; + use super::super::support::PathLike; +use rt::rtio::{IoFactory, IoFactoryObject, RtioUnixListenerObject}; +use rt::rtio::{RtioUnixAcceptorObject, RtioPipeObject, RtioUnixListener}; +use rt::rtio::RtioUnixAcceptor; +use rt::io::pipe::PipeStream; +use rt::io::{io_error, Listener, Acceptor, Reader, Writer}; +use rt::local::Local; -pub struct UnixStream; +/// A stream which communicates over a named pipe. +pub struct UnixStream { + priv obj: PipeStream, +} impl UnixStream { - pub fn connect(_path: &P) -> Option { - fail!() + fn new(obj: ~RtioPipeObject) -> UnixStream { + UnixStream { obj: PipeStream::new_bound(obj) } + } + + /// Connect to a pipe named by `path`. This will attempt to open a + /// connection to the underlying socket. + /// + /// The returned stream will be closed when the object falls out of scope. + /// + /// # Failure + /// + /// This function will raise on the `io_error` condition if the connection + /// could not be made. + /// + /// # Example + /// + /// use std::rt::io::net::unix::UnixStream; + /// + /// let server = Path("path/to/my/socket"); + /// let mut stream = UnixStream::connect(&server); + /// stream.write([1, 2, 3]); + /// + pub fn connect(path: &P) -> Option { + let pipe = unsafe { + let io: *mut IoFactoryObject = Local::unsafe_borrow(); + (*io).unix_connect(path) + }; + + match pipe { + Ok(s) => Some(UnixStream::new(s)), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } + } } } impl Reader for UnixStream { - fn read(&mut self, _buf: &mut [u8]) -> Option { fail!() } - - fn eof(&mut self) -> bool { fail!() } + fn read(&mut self, buf: &mut [u8]) -> Option { self.obj.read(buf) } + fn eof(&mut self) -> bool { self.obj.eof() } } impl Writer for UnixStream { - fn write(&mut self, _v: &[u8]) { fail!() } - - fn flush(&mut self) { fail!() } + fn write(&mut self, buf: &[u8]) { self.obj.write(buf) } + fn flush(&mut self) { self.obj.flush() } } -pub struct UnixListener; +pub struct UnixListener { + priv obj: ~RtioUnixListenerObject, +} impl UnixListener { - pub fn bind(_path: &P) -> Option { - fail!() + + /// Creates a new listener, ready to receive incoming connections on the + /// specified socket. The server will be named by `path`. + /// + /// This listener will be closed when it falls out of scope. + /// + /// # Failure + /// + /// This function will raise on the `io_error` condition if the specified + /// path could not be bound. + /// + /// # Example + /// + /// use std::rt::io::net::unix::UnixListener; + /// + /// let server = Path("path/to/my/socket"); + /// let mut stream = UnixListener::bind(&server); + /// for client in stream.incoming() { + /// let mut client = client; + /// client.write([1, 2, 3, 4]); + /// } + /// + pub fn bind(path: &P) -> Option { + let listener = unsafe { + let io: *mut IoFactoryObject = Local::unsafe_borrow(); + (*io).unix_bind(path) + }; + match listener { + Ok(s) => Some(UnixListener{ obj: s }), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } + } } } impl Listener for UnixListener { - fn listen(self) -> Option { fail!() } + fn listen(self) -> Option { + match self.obj.listen() { + Ok(acceptor) => Some(UnixAcceptor { obj: acceptor }), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } + } + } } -pub struct UnixAcceptor; +pub struct UnixAcceptor { + priv obj: ~RtioUnixAcceptorObject, +} impl Acceptor for UnixAcceptor { - fn accept(&mut self) -> Option { fail!() } + fn accept(&mut self) -> Option { + match self.obj.accept() { + Ok(s) => Some(UnixStream::new(s)), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } + } + } +} + +#[cfg(test)] +mod tests { + use prelude::*; + use super::*; + use cell::Cell; + use rt::test::*; + use rt::io::*; + use rt::comm::oneshot; + use os; + + fn smalltest(server: ~fn(UnixStream), client: ~fn(UnixStream)) { + let server = Cell::new(server); + let client = Cell::new(client); + do run_in_mt_newsched_task { + let server = Cell::new(server.take()); + let client = Cell::new(client.take()); + let path1 = next_test_unix(); + let path2 = path1.clone(); + let (port, chan) = oneshot(); + let port = Cell::new(port); + let chan = Cell::new(chan); + + do spawntask { + let mut acceptor = UnixListener::bind(&path1).listen(); + chan.take().send(()); + server.take()(acceptor.accept().unwrap()); + } + + do spawntask { + port.take().recv(); + client.take()(UnixStream::connect(&path2).unwrap()); + } + } + } + + #[test] + fn bind_error() { + do run_in_mt_newsched_task { + let mut called = false; + do io_error::cond.trap(|e| { + assert!(e.kind == PermissionDenied); + called = true; + }).inside { + let listener = UnixListener::bind(&("path/to/nowhere")); + assert!(listener.is_none()); + } + assert!(called); + } + } + + #[test] + fn connect_error() { + do run_in_mt_newsched_task { + let mut called = false; + do io_error::cond.trap(|e| { + assert_eq!(e.kind, OtherIoError); + called = true; + }).inside { + let stream = UnixStream::connect(&("path/to/nowhere")); + assert!(stream.is_none()); + } + assert!(called); + } + } + + #[test] + fn smoke() { + smalltest(|mut server| { + let mut buf = [0]; + server.read(buf); + assert!(buf[0] == 99); + }, |mut client| { + client.write([99]); + }) + } + + #[test] + fn read_eof() { + smalltest(|mut server| { + let mut buf = [0]; + assert!(server.read(buf).is_none()); + assert!(server.read(buf).is_none()); + }, |_client| { + // drop the client + }) + } + + #[test] + fn write_begone() { + smalltest(|mut server| { + let buf = [0]; + let mut stop = false; + while !stop{ + do io_error::cond.trap(|e| { + assert_eq!(e.kind, BrokenPipe); + stop = true; + }).inside { + server.write(buf); + } + } + }, |_client| { + // drop the client + }) + } + + #[test] + fn accept_lots() { + do run_in_mt_newsched_task { + let times = 10; + let path1 = next_test_unix(); + let path2 = path1.clone(); + let (port, chan) = oneshot(); + let port = Cell::new(port); + let chan = Cell::new(chan); + + do spawntask { + let mut acceptor = UnixListener::bind(&path1).listen(); + chan.take().send(()); + do times.times { + let mut client = acceptor.accept(); + let mut buf = [0]; + client.read(buf); + assert_eq!(buf[0], 100); + } + } + + do spawntask { + port.take().recv(); + do times.times { + let mut stream = UnixStream::connect(&path2); + stream.write([100]); + } + } + } + } + + #[test] + fn path_exists() { + do run_in_mt_newsched_task { + let path = next_test_unix(); + let _acceptor = UnixListener::bind(&path).listen(); + assert!(os::path_exists(&path)); + } + } } diff --git a/src/libstd/rt/io/pipe.rs b/src/libstd/rt/io/pipe.rs index d2cd531ed266f..ff1bd55d594b7 100644 --- a/src/libstd/rt/io/pipe.rs +++ b/src/libstd/rt/io/pipe.rs @@ -21,7 +21,7 @@ use rt::rtio::{RtioPipe, RtioPipeObject, IoFactoryObject, IoFactory}; use rt::rtio::RtioUnboundPipeObject; pub struct PipeStream { - priv obj: RtioPipeObject + priv obj: ~RtioPipeObject } // This should not be a newtype, but rt::uv::process::set_stdio needs to reach @@ -45,7 +45,7 @@ impl PipeStream { } } - pub fn bind(inner: RtioPipeObject) -> PipeStream { + pub fn new_bound(inner: ~RtioPipeObject) -> PipeStream { PipeStream { obj: inner } } } diff --git a/src/libstd/rt/io/process.rs b/src/libstd/rt/io/process.rs index 5f2453852ee7f..e0ffa82b59fe3 100644 --- a/src/libstd/rt/io/process.rs +++ b/src/libstd/rt/io/process.rs @@ -100,7 +100,7 @@ impl Process { Ok((p, io)) => Some(Process{ handle: p, io: io.move_iter().map(|p| - p.map(|p| io::PipeStream::bind(p)) + p.map(|p| io::PipeStream::new_bound(p)) ).collect() }), Err(ioerr) => { diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index 501def8b06079..0964f94d6d528 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -36,6 +36,8 @@ pub type PausibleIdleCallback = uvio::UvPausibleIdleCallback; pub type RtioPipeObject = uvio::UvPipeStream; pub type RtioUnboundPipeObject = uvio::UvUnboundPipe; pub type RtioProcessObject = uvio::UvProcess; +pub type RtioUnixListenerObject = uvio::UvUnixListener; +pub type RtioUnixAcceptorObject = uvio::UvUnixAcceptor; pub trait EventLoop { fn run(&mut self); @@ -86,7 +88,12 @@ pub trait IoFactory { Result<~[Path], IoError>; fn pipe_init(&mut self, ipc: bool) -> Result<~RtioUnboundPipeObject, IoError>; fn spawn(&mut self, config: ProcessConfig) - -> Result<(~RtioProcessObject, ~[Option]), IoError>; + -> Result<(~RtioProcessObject, ~[Option<~RtioPipeObject>]), IoError>; + + fn unix_bind(&mut self, path: &P) -> + Result<~RtioUnixListenerObject, IoError>; + fn unix_connect(&mut self, path: &P) -> + Result<~RtioPipeObject, IoError>; } pub trait RtioTcpListener : RtioSocket { @@ -154,3 +161,13 @@ pub trait RtioPipe { fn read(&mut self, buf: &mut [u8]) -> Result; fn write(&mut self, buf: &[u8]) -> Result<(), IoError>; } + +pub trait RtioUnixListener { + fn listen(self) -> Result<~RtioUnixAcceptorObject, IoError>; +} + +pub trait RtioUnixAcceptor { + fn accept(&mut self) -> Result<~RtioPipeObject, IoError>; + fn accept_simultaneously(&mut self) -> Result<(), IoError>; + fn dont_accept_simultaneously(&mut self) -> Result<(), IoError>; +} diff --git a/src/libstd/rt/test.rs b/src/libstd/rt/test.rs index 4f7ebb4a72195..759550e5cbd03 100644 --- a/src/libstd/rt/test.rs +++ b/src/libstd/rt/test.rs @@ -8,8 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use rand; +use rand::Rng; +use os; use libc; use option::{Some, None}; +use path::{Path, GenericPath}; use cell::Cell; use clone::Clone; use container::Container; @@ -327,6 +331,12 @@ pub fn next_test_port() -> u16 { } } +/// Get a temporary path which could be the location of a unix socket +#[fixed_stack_segment] #[inline(never)] +pub fn next_test_unix() -> Path { + os::tmpdir().push(rand::task_rng().gen_ascii_str(20)) +} + /// Get a unique IPv4 localhost:port pair starting at 9600 pub fn next_test_ip4() -> SocketAddr { SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: next_test_port() } diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs index a2608bf6b2406..2e85900a3f23c 100644 --- a/src/libstd/rt/uv/net.rs +++ b/src/libstd/rt/uv/net.rs @@ -206,12 +206,6 @@ impl StreamWatcher { } } - pub fn accept(&mut self, stream: StreamWatcher) { - let self_handle = self.native_handle() as *c_void; - let stream_handle = stream.native_handle() as *c_void; - assert_eq!(0, unsafe { uvll::accept(self_handle, stream_handle) } ); - } - pub fn close(self, cb: NullCallback) { { let mut this = self; @@ -230,6 +224,36 @@ impl StreamWatcher { cb(); } } + + pub fn listen(&mut self, cb: ConnectionCallback) -> Result<(), UvError> { + { + let data = self.get_watcher_data(); + assert!(data.connect_cb.is_none()); + data.connect_cb = Some(cb); + } + + unsafe { + static BACKLOG: c_int = 128; // XXX should be configurable + match uvll::listen(self.native_handle(), BACKLOG, connection_cb) { + 0 => Ok(()), + n => Err(UvError(n)) + } + } + + extern fn connection_cb(handle: *uvll::uv_stream_t, status: c_int) { + rtdebug!("connection_cb"); + let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(handle); + let cb = stream_watcher.get_watcher_data().connect_cb.get_ref(); + let status = status_to_maybe_uv_error(status); + (*cb)(stream_watcher, status); + } + } + + pub fn accept(&mut self, stream: StreamWatcher) { + let self_handle = self.native_handle() as *c_void; + let stream_handle = stream.native_handle() as *c_void; + assert_eq!(0, unsafe { uvll::accept(self_handle, stream_handle) } ); + } } impl NativeHandle<*uvll::uv_stream_t> for StreamWatcher { @@ -300,28 +324,6 @@ impl TcpWatcher { } } - pub fn listen(&mut self, cb: ConnectionCallback) { - { - let data = self.get_watcher_data(); - assert!(data.connect_cb.is_none()); - data.connect_cb = Some(cb); - } - - unsafe { - static BACKLOG: c_int = 128; // XXX should be configurable - // XXX: This can probably fail - assert_eq!(0, uvll::listen(self.native_handle(), BACKLOG, connection_cb)); - } - - extern fn connection_cb(handle: *uvll::uv_stream_t, status: c_int) { - rtdebug!("connection_cb"); - let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(handle); - let cb = stream_watcher.get_watcher_data().connect_cb.get_ref(); - let status = status_to_maybe_uv_error(status); - (*cb)(stream_watcher, status); - } - } - pub fn as_stream(&self) -> StreamWatcher { NativeHandle::from_native_handle(self.native_handle() as *uvll::uv_stream_t) } @@ -644,7 +646,8 @@ mod test { server_tcp_watcher.bind(addr); let loop_ = loop_; rtdebug!("listening"); - do server_tcp_watcher.listen |mut server_stream_watcher, status| { + let mut stream = server_tcp_watcher.as_stream(); + let res = do stream.listen |mut server_stream_watcher, status| { rtdebug!("listened!"); assert!(status.is_none()); let mut loop_ = loop_; @@ -678,7 +681,9 @@ mod test { } count_cell.put_back(count); } - } + }; + + assert!(res.is_ok()); let client_thread = do Thread::start { rtdebug!("starting client thread"); @@ -705,7 +710,7 @@ mod test { loop_.run(); loop_.close(); client_thread.join(); - } + }; } #[test] @@ -718,7 +723,8 @@ mod test { server_tcp_watcher.bind(addr); let loop_ = loop_; rtdebug!("listening"); - do server_tcp_watcher.listen |mut server_stream_watcher, status| { + let mut stream = server_tcp_watcher.as_stream(); + let res = do stream.listen |mut server_stream_watcher, status| { rtdebug!("listened!"); assert!(status.is_none()); let mut loop_ = loop_; @@ -754,7 +760,8 @@ mod test { } count_cell.put_back(count); } - } + }; + assert!(res.is_ok()); let client_thread = do Thread::start { rtdebug!("starting client thread"); diff --git a/src/libstd/rt/uv/pipe.rs b/src/libstd/rt/uv/pipe.rs index 1147c731a60c5..1cb86d4df2ca2 100644 --- a/src/libstd/rt/uv/pipe.rs +++ b/src/libstd/rt/uv/pipe.rs @@ -10,6 +10,7 @@ use prelude::*; use libc; +use c_str::CString; use rt::uv; use rt::uv::net; @@ -37,6 +38,54 @@ impl Pipe { net::StreamWatcher(**self as *uvll::uv_stream_t) } + #[fixed_stack_segment] #[inline(never)] + pub fn open(&mut self, file: libc::c_int) -> Result<(), uv::UvError> { + match unsafe { uvll::uv_pipe_open(self.native_handle(), file) } { + 0 => Ok(()), + n => Err(uv::UvError(n)) + } + } + + #[fixed_stack_segment] #[inline(never)] + pub fn bind(&mut self, name: &CString) -> Result<(), uv::UvError> { + do name.with_ref |name| { + match unsafe { uvll::uv_pipe_bind(self.native_handle(), name) } { + 0 => Ok(()), + n => Err(uv::UvError(n)) + } + } + } + + #[fixed_stack_segment] #[inline(never)] + pub fn connect(&mut self, name: &CString, cb: uv::ConnectionCallback) { + { + let data = self.get_watcher_data(); + assert!(data.connect_cb.is_none()); + data.connect_cb = Some(cb); + } + + let connect = net::ConnectRequest::new(); + let name = do name.with_ref |p| { p }; + + unsafe { + uvll::uv_pipe_connect(connect.native_handle(), + self.native_handle(), + name, + connect_cb) + } + + extern "C" fn connect_cb(req: *uvll::uv_connect_t, status: libc::c_int) { + let connect_request: net::ConnectRequest = + uv::NativeHandle::from_native_handle(req); + let mut stream_watcher = connect_request.stream(); + connect_request.delete(); + + let cb = stream_watcher.get_watcher_data().connect_cb.take_unwrap(); + let status = uv::status_to_maybe_uv_error(status); + cb(stream_watcher, status); + } + } + pub fn close(self, cb: uv::NullCallback) { { let mut this = self; @@ -47,7 +96,7 @@ impl Pipe { unsafe { uvll::close(self.native_handle(), close_cb); } - extern fn close_cb(handle: *uvll::uv_pipe_t) { + extern "C" fn close_cb(handle: *uvll::uv_pipe_t) { let mut process: Pipe = uv::NativeHandle::from_native_handle(handle); process.get_watcher_data().close_cb.take_unwrap()(); process.drop_watcher_data(); diff --git a/src/libstd/rt/uv/process.rs b/src/libstd/rt/uv/process.rs index 176754de8f745..3c629a783cf7a 100644 --- a/src/libstd/rt/uv/process.rs +++ b/src/libstd/rt/uv/process.rs @@ -44,7 +44,7 @@ impl Process { /// occurred. pub fn spawn(&mut self, loop_: &uv::Loop, mut config: ProcessConfig, exit_cb: uv::ExitCallback) - -> Result<~[Option], uv::UvError> + -> Result<~[Option<~UvPipeStream>], uv::UvError> { let cwd = config.cwd.map(|s| s.to_c_str()); @@ -144,7 +144,7 @@ impl Process { } unsafe fn set_stdio(dst: *uvll::uv_stdio_container_t, - io: StdioContainer) -> Option { + io: StdioContainer) -> Option<~UvPipeStream> { match io { Ignored => { uvll::set_stdio_container_flags(dst, uvll::STDIO_IGNORE); @@ -166,7 +166,7 @@ unsafe fn set_stdio(dst: *uvll::uv_stdio_container_t, let handle = pipe.pipe.as_stream().native_handle(); uvll::set_stdio_container_flags(dst, flags); uvll::set_stdio_container_stream(dst, handle); - Some(pipe.bind()) + Some(~UvPipeStream::new(**pipe)) } } } diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 8dd0f8a6b106e..6888aa23e99e7 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -746,11 +746,11 @@ impl IoFactory for UvIoFactory { fn pipe_init(&mut self, ipc: bool) -> Result<~RtioUnboundPipeObject, IoError> { let home = get_handle_to_current_scheduler!(); - Ok(~UvUnboundPipe { pipe: Pipe::new(self.uv_loop(), ipc), home: home }) + Ok(~UvUnboundPipe::new(Pipe::new(self.uv_loop(), ipc), home)) } fn spawn(&mut self, config: ProcessConfig) - -> Result<(~RtioProcessObject, ~[Option]), IoError> + -> Result<(~RtioProcessObject, ~[Option<~RtioPipeObject>]), IoError> { // Sadly, we must create the UvProcess before we actually call uv_spawn // so that the exit_cb can close over it and notify it when the process @@ -801,6 +801,74 @@ impl IoFactory for UvIoFactory { } } } + + fn unix_bind(&mut self, path: &P) -> + Result<~RtioUnixListenerObject, IoError> { + let mut pipe = Pipe::new(self.uv_loop(), false); + match pipe.bind(&path.path_as_str(|s| s.to_c_str())) { + Ok(()) => { + let handle = get_handle_to_current_scheduler!(); + let pipe = UvUnboundPipe::new(pipe, handle); + Ok(~UvUnixListener::new(pipe)) + } + Err(e) => { + let scheduler: ~Scheduler = Local::take(); + do scheduler.deschedule_running_task_and_then |_, task| { + let task_cell = Cell::new(task); + do pipe.close { + let scheduler: ~Scheduler = Local::take(); + scheduler.resume_blocked_task_immediately( + task_cell.take()); + } + } + Err(uv_error_to_io_error(e)) + } + } + } + + fn unix_connect(&mut self, path: &P) -> + Result<~RtioPipeObject, IoError> + { + let scheduler: ~Scheduler = Local::take(); + let mut pipe = Pipe::new(self.uv_loop(), false); + let result_cell = Cell::new_empty(); + let result_cell_ptr: *Cell> = &result_cell; + + do scheduler.deschedule_running_task_and_then |_, task| { + let task_cell = Cell::new(task); + let cstr = do path.path_as_str |s| { s.to_c_str() }; + do pipe.connect(&cstr) |stream, err| { + let res = match err { + None => { + let handle = stream.native_handle(); + let pipe = NativeHandle::from_native_handle( + handle as *uvll::uv_pipe_t); + let home = get_handle_to_current_scheduler!(); + let pipe = UvUnboundPipe::new(pipe, home); + Ok(~UvPipeStream::new(pipe)) + } + Some(e) => { Err(uv_error_to_io_error(e)) } + }; + unsafe { (*result_cell_ptr).put_back(res); } + let scheduler: ~Scheduler = Local::take(); + scheduler.resume_blocked_task_immediately(task_cell.take()); + } + } + + assert!(!result_cell.is_empty()); + let ret = result_cell.take(); + if ret.is_err() { + let scheduler: ~Scheduler = Local::take(); + do scheduler.deschedule_running_task_and_then |_, task| { + let task_cell = Cell::new(task); + do pipe.close { + let scheduler: ~Scheduler = Local::take(); + scheduler.resume_blocked_task_immediately(task_cell.take()); + } + } + } + return ret; + } } pub struct UvTcpListener { @@ -843,9 +911,10 @@ impl RtioSocket for UvTcpListener { impl RtioTcpListener for UvTcpListener { fn listen(self) -> Result<~RtioTcpAcceptorObject, IoError> { do self.home_for_io_consume |self_| { - let mut acceptor = ~UvTcpAcceptor::new(self_); + let acceptor = ~UvTcpAcceptor::new(self_); let incoming = Cell::new(acceptor.incoming.clone()); - do acceptor.listener.watcher.listen |mut server, status| { + let mut stream = acceptor.listener.watcher.as_stream(); + let res = do stream.listen |mut server, status| { do incoming.with_mut_ref |incoming| { let inc = match status { Some(_) => Err(standard_error(OtherIoError)), @@ -860,7 +929,10 @@ impl RtioTcpListener for UvTcpListener { incoming.send(inc); } }; - Ok(acceptor) + match res { + Ok(()) => Ok(acceptor), + Err(e) => Err(uv_error_to_io_error(e)), + } } } } @@ -888,6 +960,17 @@ impl RtioSocket for UvTcpAcceptor { } } +fn accept_simultaneously(stream: StreamWatcher, a: int) -> Result<(), IoError> { + let r = unsafe { + uvll::tcp_simultaneous_accepts(stream.native_handle(), a as c_int) + }; + + match status_to_maybe_uv_error(r) { + Some(err) => Err(uv_error_to_io_error(err)), + None => Ok(()) + } +} + impl RtioTcpAcceptor for UvTcpAcceptor { fn accept(&mut self) -> Result<~RtioTcpStreamObject, IoError> { do self.home_for_io |self_| { @@ -897,27 +980,13 @@ impl RtioTcpAcceptor for UvTcpAcceptor { fn accept_simultaneously(&mut self) -> Result<(), IoError> { do self.home_for_io |self_| { - let r = unsafe { - uvll::tcp_simultaneous_accepts(self_.listener.watcher.native_handle(), 1 as c_int) - }; - - match status_to_maybe_uv_error(r) { - Some(err) => Err(uv_error_to_io_error(err)), - None => Ok(()) - } + accept_simultaneously(self_.listener.watcher.as_stream(), 1) } } fn dont_accept_simultaneously(&mut self) -> Result<(), IoError> { do self.home_for_io |self_| { - let r = unsafe { - uvll::tcp_simultaneous_accepts(self_.listener.watcher.native_handle(), 0 as c_int) - }; - - match status_to_maybe_uv_error(r) { - Some(err) => Err(uv_error_to_io_error(err)), - None => Ok(()) - } + accept_simultaneously(self_.listener.watcher.as_stream(), 0) } } } @@ -994,6 +1063,12 @@ pub struct UvUnboundPipe { priv home: SchedHandle, } +impl UvUnboundPipe { + fn new(pipe: Pipe, home: SchedHandle) -> UvUnboundPipe { + UvUnboundPipe { pipe: pipe, home: home } + } +} + impl HomingIO for UvUnboundPipe { fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home } } @@ -1013,18 +1088,12 @@ impl Drop for UvUnboundPipe { } } -impl UvUnboundPipe { - pub unsafe fn bind(~self) -> UvPipeStream { - UvPipeStream { inner: self } - } -} - pub struct UvPipeStream { - priv inner: ~UvUnboundPipe, + priv inner: UvUnboundPipe, } impl UvPipeStream { - pub fn new(inner: ~UvUnboundPipe) -> UvPipeStream { + pub fn new(inner: UvUnboundPipe) -> UvPipeStream { UvPipeStream { inner: inner } } } @@ -1612,6 +1681,84 @@ impl RtioProcess for UvProcess { } } +pub struct UvUnixListener { + priv inner: UvUnboundPipe +} + +impl HomingIO for UvUnixListener { + fn home<'r>(&'r mut self) -> &'r mut SchedHandle { self.inner.home() } +} + +impl UvUnixListener { + fn new(pipe: UvUnboundPipe) -> UvUnixListener { + UvUnixListener { inner: pipe } + } +} + +impl RtioUnixListener for UvUnixListener { + fn listen(self) -> Result<~RtioUnixAcceptorObject, IoError> { + do self.home_for_io_consume |self_| { + let acceptor = ~UvUnixAcceptor::new(self_); + let incoming = Cell::new(acceptor.incoming.clone()); + let mut stream = acceptor.listener.inner.pipe.as_stream(); + let res = do stream.listen |mut server, status| { + do incoming.with_mut_ref |incoming| { + let inc = match status { + Some(e) => Err(uv_error_to_io_error(e)), + None => { + let inc = Pipe::new(&server.event_loop(), false); + server.accept(inc.as_stream()); + let home = get_handle_to_current_scheduler!(); + let pipe = UvUnboundPipe::new(inc, home); + Ok(~UvPipeStream::new(pipe)) + } + }; + incoming.send(inc); + } + }; + match res { + Ok(()) => Ok(acceptor), + Err(e) => Err(uv_error_to_io_error(e)), + } + } + } +} + +pub struct UvUnixAcceptor { + listener: UvUnixListener, + incoming: Tube>, +} + +impl HomingIO for UvUnixAcceptor { + fn home<'r>(&'r mut self) -> &'r mut SchedHandle { self.listener.home() } +} + +impl UvUnixAcceptor { + fn new(listener: UvUnixListener) -> UvUnixAcceptor { + UvUnixAcceptor { listener: listener, incoming: Tube::new() } + } +} + +impl RtioUnixAcceptor for UvUnixAcceptor { + fn accept(&mut self) -> Result<~RtioPipeObject, IoError> { + do self.home_for_io |self_| { + self_.incoming.recv() + } + } + + fn accept_simultaneously(&mut self) -> Result<(), IoError> { + do self.home_for_io |self_| { + accept_simultaneously(self_.listener.inner.pipe.as_stream(), 1) + } + } + + fn dont_accept_simultaneously(&mut self) -> Result<(), IoError> { + do self.home_for_io |self_| { + accept_simultaneously(self_.listener.inner.pipe.as_stream(), 0) + } + } +} + #[test] fn test_simple_io_no_connect() { do run_in_mt_newsched_task { diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index 367585b0f0ee4..eb770d0807074 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -1102,4 +1102,23 @@ extern { fn rust_set_stdio_container_stream(c: *uv_stdio_container_t, stream: *uv_stream_t); fn rust_uv_pipe_init(loop_ptr: *c_void, p: *uv_pipe_t, ipc: c_int) -> c_int; + + pub fn uv_pipe_open(pipe: *uv_pipe_t, file: c_int) -> c_int; + pub fn uv_pipe_bind(pipe: *uv_pipe_t, name: *c_char) -> c_int; + pub fn uv_pipe_connect(req: *uv_connect_t, handle: *uv_pipe_t, + name: *c_char, cb: uv_connect_cb); + + // These should all really be constants... + #[rust_stack] pub fn rust_SOCK_STREAM() -> c_int; + #[rust_stack] pub fn rust_SOCK_DGRAM() -> c_int; + #[rust_stack] pub fn rust_SOCK_RAW() -> c_int; + #[rust_stack] pub fn rust_IPPROTO_UDP() -> c_int; + #[rust_stack] pub fn rust_IPPROTO_TCP() -> c_int; + #[rust_stack] pub fn rust_AI_ADDRCONFIG() -> c_int; + #[rust_stack] pub fn rust_AI_ALL() -> c_int; + #[rust_stack] pub fn rust_AI_CANONNAME() -> c_int; + #[rust_stack] pub fn rust_AI_NUMERICHOST() -> c_int; + #[rust_stack] pub fn rust_AI_NUMERICSERV() -> c_int; + #[rust_stack] pub fn rust_AI_PASSIVE() -> c_int; + #[rust_stack] pub fn rust_AI_V4MAPPED() -> c_int; } diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 7323397508e2e..b144820c44246 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -199,3 +199,18 @@ bufrelease bufnew rust_take_dlerror_lock rust_drop_dlerror_lock +rust_SOCK_STREAM +rust_SOCK_DGRAM +rust_SOCK_RAW +rust_IPPROTO_UDP +rust_IPPROTO_TCP +rust_AI_ADDRCONFIG +rust_AI_ALL +rust_AI_CANONNAME +rust_AI_NUMERICHOST +rust_AI_NUMERICSERV +rust_AI_PASSIVE +rust_AI_V4MAPPED +uv_pipe_open +uv_pipe_bind +uv_pipe_connect From 1db783bdcf05954e066adf6cefbbc5ac72e13173 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 15 Oct 2013 20:37:39 -0700 Subject: [PATCH 02/23] Finish implementing io::net::addrinfo This fills in the `hints` structure and exposes libuv's full functionality for doing dns lookups. --- src/libstd/rt/io/net/addrinfo.rs | 127 +++++++++++++++++++++++++++++++ src/libstd/rt/io/net/mod.rs | 48 +----------- src/libstd/rt/rtio.rs | 4 +- src/libstd/rt/uv/addrinfo.rs | 109 +++++++++++++++++++++++--- src/libstd/rt/uv/net.rs | 32 ++------ src/libstd/rt/uv/uvio.rs | 21 +++-- src/rt/rust_uv.cpp | 13 ++++ 7 files changed, 262 insertions(+), 92 deletions(-) create mode 100644 src/libstd/rt/io/net/addrinfo.rs diff --git a/src/libstd/rt/io/net/addrinfo.rs b/src/libstd/rt/io/net/addrinfo.rs new file mode 100644 index 0000000000000..ae0d542acbe47 --- /dev/null +++ b/src/libstd/rt/io/net/addrinfo.rs @@ -0,0 +1,127 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! + +Synchronous DNS Resolution + +Contains the functionality to perform DNS resolution in a style related to +getaddrinfo() + +*/ + +use option::{Option, Some, None}; +use result::{Ok, Err}; +use rt::io::io_error; +use rt::io::net::ip::{SocketAddr, IpAddr}; +use rt::rtio::{IoFactory, IoFactoryObject}; +use rt::local::Local; + +/// Hints to the types of sockets that are desired when looking up hosts +pub enum SocketType { + Stream, Datagram, Raw +} + +/// Flags which can be or'd into the `flags` field of a `Hint`. These are used +/// to manipulate how a query is performed. +/// +/// The meaning of each of these flags can be found with `man -s 3 getaddrinfo` +pub enum Flag { + AddrConfig, + All, + CanonName, + NumericHost, + NumericServ, + Passive, + V4Mapped, +} + +/// A transport protocol associated with either a hint or a return value of +/// `lookup` +pub enum Protocol { + TCP, UDP +} + +/// This structure is used to provide hints when fetching addresses for a +/// remote host to control how the lookup is performed. +/// +/// For details on these fields, see their corresponding definitions via +/// `man -s 3 getaddrinfo` +pub struct Hint { + family: uint, + socktype: Option, + protocol: Option, + flags: uint, +} + +pub struct Info { + address: SocketAddr, + family: uint, + socktype: Option, + protocol: Option, + flags: uint, +} + +/// Easy name resolution. Given a hostname, returns the list of IP addresses for +/// that hostname. +/// +/// # Failure +/// +/// On failure, this will raise on the `io_error` condition. +pub fn get_host_addresses(host: &str) -> Option<~[IpAddr]> { + lookup(Some(host), None, None).map(|a| a.map(|i| i.address.ip)) +} + +/// Full-fleged resolution. This function will perform a synchronous call to +/// getaddrinfo, controlled by the parameters +/// +/// # Arguments +/// +/// * hostname - an optional hostname to lookup against +/// * servname - an optional service name, listed in the system services +/// * hint - see the hint structure, and "man -s 3 getaddrinfo", for how this +/// controls lookup +/// +/// # Failure +/// +/// On failure, this will raise on the `io_error` condition. +pub fn lookup(hostname: Option<&str>, servname: Option<&str>, + hint: Option) -> Option<~[Info]> { + let ipaddrs = unsafe { + let io: *mut IoFactoryObject = Local::unsafe_borrow(); + (*io).get_host_addresses(hostname, servname, hint) + }; + + match ipaddrs { + Ok(i) => Some(i), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } + } +} + +#[cfg(test)] +mod test { + use option::Some; + use rt::io::net::ip::Ipv4Addr; + use super::*; + + #[test] + fn dns_smoke_test() { + let ipaddrs = get_host_addresses("localhost").unwrap(); + let mut found_local = false; + let local_addr = &Ipv4Addr(127, 0, 0, 1); + for addr in ipaddrs.iter() { + found_local = found_local || addr == local_addr; + } + assert!(found_local); + } +} diff --git a/src/libstd/rt/io/net/mod.rs b/src/libstd/rt/io/net/mod.rs index f44e879a63a2a..cf109167089d4 100644 --- a/src/libstd/rt/io/net/mod.rs +++ b/src/libstd/rt/io/net/mod.rs @@ -8,55 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use option::{Option, Some, None}; -use result::{Ok, Err}; -use rt::io::io_error; -use rt::io::net::ip::IpAddr; -use rt::rtio::{IoFactory, IoFactoryObject}; -use rt::local::Local; +pub use self::addrinfo::get_host_addresses; +pub mod addrinfo; pub mod tcp; pub mod udp; pub mod ip; #[cfg(unix)] pub mod unix; - -/// Simplistic name resolution -pub fn get_host_addresses(host: &str) -> Option<~[IpAddr]> { - /*! - * Get the IP addresses for a given host name. - * - * Raises io_error on failure. - */ - - let ipaddrs = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).get_host_addresses(host) - }; - - match ipaddrs { - Ok(i) => Some(i), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None - } - } -} - -#[cfg(test)] -mod test { - use option::Some; - use rt::io::net::ip::Ipv4Addr; - use super::*; - - #[test] - fn dns_smoke_test() { - let ipaddrs = get_host_addresses("localhost").unwrap(); - let mut found_local = false; - let local_addr = &Ipv4Addr(127, 0, 0, 1); - for addr in ipaddrs.iter() { - found_local = found_local || addr == local_addr; - } - assert!(found_local); - } -} diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index 0964f94d6d528..4a290ca46e50e 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -13,6 +13,7 @@ use option::*; use result::*; use libc::c_int; +use ai = rt::io::net::addrinfo; use rt::io::IoError; use super::io::process::ProcessConfig; use super::io::net::ip::{IpAddr, SocketAddr}; @@ -80,7 +81,8 @@ pub trait IoFactory { fn fs_open(&mut self, path: &P, fm: FileMode, fa: FileAccess) -> Result<~RtioFileStream, IoError>; fn fs_unlink(&mut self, path: &P) -> Result<(), IoError>; - fn get_host_addresses(&mut self, host: &str) -> Result<~[IpAddr], IoError>; + fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>, + hint: Option) -> Result<~[ai::Info], IoError>; fn fs_stat(&mut self, path: &P) -> Result; fn fs_mkdir(&mut self, path: &P) -> Result<(), IoError>; fn fs_rmdir(&mut self, path: &P) -> Result<(), IoError>; diff --git a/src/libstd/rt/uv/addrinfo.rs b/src/libstd/rt/uv/addrinfo.rs index f2abcd3aca7e3..7556d7db665ef 100644 --- a/src/libstd/rt/uv/addrinfo.rs +++ b/src/libstd/rt/uv/addrinfo.rs @@ -18,9 +18,10 @@ use rt::uv::uvll; use rt::uv::uvll::UV_GETADDRINFO; use rt::uv::{Loop, UvError, NativeHandle}; use rt::uv::status_to_maybe_uv_error; -use rt::uv::net::UvAddrInfo; +use rt::uv::net; +use ai = rt::io::net::addrinfo; -type GetAddrInfoCallback = ~fn(GetAddrInfoRequest, &UvAddrInfo, Option); +type GetAddrInfoCallback = ~fn(GetAddrInfoRequest, &net::UvAddrInfo, Option); pub struct GetAddrInfoRequest(*uvll::uv_getaddrinfo_t); @@ -38,7 +39,7 @@ impl GetAddrInfoRequest { } pub fn getaddrinfo(&mut self, loop_: &Loop, node: Option<&str>, - service: Option<&str>, hints: Option, + service: Option<&str>, hints: Option, cb: GetAddrInfoCallback) { assert!(node.is_some() || service.is_some()); @@ -72,8 +73,37 @@ impl GetAddrInfoRequest { cb(req, addrinfo, err) }; - // XXX: Implement hints - assert!(hints.is_none()); + let hint = hints.map(|hint| unsafe { + let mut flags = 0; + do each_ai_flag |cval, aival| { + if hint.flags & (aival as uint) != 0 { + flags |= cval as i32; + } + } + let socktype = match hint.socktype { + Some(ai::Stream) => uvll::rust_SOCK_STREAM(), + Some(ai::Datagram) => uvll::rust_SOCK_DGRAM(), + Some(ai::Raw) => uvll::rust_SOCK_RAW(), + None => 0, + }; + let protocol = match hint.protocol { + Some(ai::UDP) => uvll::rust_IPPROTO_UDP(), + Some(ai::TCP) => uvll::rust_IPPROTO_TCP(), + _ => 0, + }; + + uvll::addrinfo { + ai_flags: flags, + ai_family: hint.family as c_int, + ai_socktype: socktype, + ai_protocol: protocol, + ai_addrlen: 0, + ai_canonname: null(), + ai_addr: null(), + ai_next: null(), + } + }); + let hint_ptr = hint.as_ref().map_default(null(), |x| x as *uvll::addrinfo); self.get_req_data().getaddrinfo_cb = Some(wrapper_cb); @@ -83,7 +113,7 @@ impl GetAddrInfoRequest { getaddrinfo_cb, c_node_ptr, c_service_ptr, - null())); + hint_ptr)); } extern "C" fn getaddrinfo_cb(req: *uvll::uv_getaddrinfo_t, @@ -91,7 +121,7 @@ impl GetAddrInfoRequest { res: *uvll::addrinfo) { let mut req: GetAddrInfoRequest = NativeHandle::from_native_handle(req); let err = status_to_maybe_uv_error(status); - let addrinfo = UvAddrInfo(res); + let addrinfo = net::UvAddrInfo(res); let data = req.get_req_data(); (*data.getaddrinfo_cb.get_ref())(req, &addrinfo, err); unsafe { @@ -137,6 +167,66 @@ impl GetAddrInfoRequest { } } +fn each_ai_flag(f: &fn(c_int, ai::Flag)) { + unsafe { + f(uvll::rust_AI_ADDRCONFIG(), ai::AddrConfig); + f(uvll::rust_AI_ALL(), ai::All); + f(uvll::rust_AI_CANONNAME(), ai::CanonName); + f(uvll::rust_AI_NUMERICHOST(), ai::NumericHost); + f(uvll::rust_AI_NUMERICSERV(), ai::NumericServ); + f(uvll::rust_AI_PASSIVE(), ai::Passive); + f(uvll::rust_AI_V4MAPPED(), ai::V4Mapped); + } +} + +// Traverse the addrinfo linked list, producing a vector of Rust socket addresses +pub fn accum_addrinfo(addr: &net::UvAddrInfo) -> ~[ai::Info] { + unsafe { + let &net::UvAddrInfo(addr) = addr; + let mut addr = addr; + + let mut addrs = ~[]; + loop { + let uvaddr = net::sockaddr_to_UvSocketAddr((*addr).ai_addr); + let rustaddr = net::uv_socket_addr_to_socket_addr(uvaddr); + + let mut flags = 0; + do each_ai_flag |cval, aival| { + if (*addr).ai_flags & cval != 0 { + flags |= aival as uint; + } + } + + let protocol = match (*addr).ai_protocol { + p if p == uvll::rust_IPPROTO_UDP() => Some(ai::UDP), + p if p == uvll::rust_IPPROTO_TCP() => Some(ai::TCP), + _ => None, + }; + let socktype = match (*addr).ai_socktype { + p if p == uvll::rust_SOCK_STREAM() => Some(ai::Stream), + p if p == uvll::rust_SOCK_DGRAM() => Some(ai::Datagram), + p if p == uvll::rust_SOCK_RAW() => Some(ai::Raw), + _ => None, + }; + + addrs.push(ai::Info { + address: rustaddr, + family: (*addr).ai_family as uint, + socktype: socktype, + protocol: protocol, + flags: flags, + }); + if (*addr).ai_next.is_not_null() { + addr = (*addr).ai_next; + } else { + break; + } + } + + return addrs; + } +} + impl NativeHandle<*uvll::uv_getaddrinfo_t> for GetAddrInfoRequest { fn from_native_handle(handle: *uvll::uv_getaddrinfo_t) -> GetAddrInfoRequest { GetAddrInfoRequest(handle) @@ -150,7 +240,6 @@ impl NativeHandle<*uvll::uv_getaddrinfo_t> for GetAddrInfoRequest { mod test { use option::{Some, None}; use rt::uv::Loop; - use rt::uv::net::accum_sockaddrs; use rt::io::net::ip::{SocketAddr, Ipv4Addr}; use super::*; @@ -159,14 +248,14 @@ mod test { let mut loop_ = Loop::new(); let mut req = GetAddrInfoRequest::new(); do req.getaddrinfo(&loop_, Some("localhost"), None, None) |_, addrinfo, _| { - let sockaddrs = accum_sockaddrs(addrinfo); + let sockaddrs = accum_addrinfo(addrinfo); let mut found_local = false; let local_addr = &SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 0 }; for addr in sockaddrs.iter() { - found_local = found_local || addr == local_addr; + found_local = found_local || addr.address == *local_addr; } assert!(found_local); } diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs index 2e85900a3f23c..e2f2510c48781 100644 --- a/src/libstd/rt/uv/net.rs +++ b/src/libstd/rt/uv/net.rs @@ -27,7 +27,7 @@ pub enum UvSocketAddr { UvIpv6SocketAddr(*sockaddr_in6), } -fn sockaddr_to_UvSocketAddr(addr: *uvll::sockaddr) -> UvSocketAddr { +pub fn sockaddr_to_UvSocketAddr(addr: *uvll::sockaddr) -> UvSocketAddr { unsafe { assert!((is_ip4_addr(addr) || is_ip6_addr(addr))); assert!(!(is_ip4_addr(addr) && is_ip6_addr(addr))); @@ -96,28 +96,6 @@ pub fn uv_socket_addr_to_socket_addr(addr: UvSocketAddr) -> SocketAddr { uv_socket_addr_as_socket_addr(addr, util::id) } -// Traverse the addrinfo linked list, producing a vector of Rust socket addresses -pub fn accum_sockaddrs(addr: &UvAddrInfo) -> ~[SocketAddr] { - unsafe { - let &UvAddrInfo(addr) = addr; - let mut addr = addr; - - let mut addrs = ~[]; - loop { - let uvaddr = sockaddr_to_UvSocketAddr((*addr).ai_addr); - let rustaddr = uv_socket_addr_to_socket_addr(uvaddr); - addrs.push(rustaddr); - if (*addr).ai_next.is_not_null() { - addr = (*addr).ai_next; - } else { - break; - } - } - - return addrs; - } -} - #[cfg(test)] #[test] fn test_ip4_conversion() { @@ -232,13 +210,13 @@ impl StreamWatcher { data.connect_cb = Some(cb); } - unsafe { + return unsafe { static BACKLOG: c_int = 128; // XXX should be configurable match uvll::listen(self.native_handle(), BACKLOG, connection_cb) { 0 => Ok(()), n => Err(UvError(n)) } - } + }; extern fn connection_cb(handle: *uvll::uv_stream_t, status: c_int) { rtdebug!("connection_cb"); @@ -466,12 +444,12 @@ impl NativeHandle<*uvll::uv_udp_t> for UdpWatcher { } // uv_connect_t is a subclass of uv_req_t -struct ConnectRequest(*uvll::uv_connect_t); +pub struct ConnectRequest(*uvll::uv_connect_t); impl Request for ConnectRequest { } impl ConnectRequest { - fn new() -> ConnectRequest { + pub fn new() -> ConnectRequest { let connect_handle = unsafe { malloc_req(UV_CONNECT) }; assert!(connect_handle.is_not_null()); ConnectRequest(connect_handle as *uvll::uv_connect_t) diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 6888aa23e99e7..bc9be40cde563 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -32,8 +32,8 @@ use rt::tube::Tube; use rt::task::SchedHome; use rt::uv::*; use rt::uv::idle::IdleWatcher; -use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr, accum_sockaddrs}; -use rt::uv::addrinfo::GetAddrInfoRequest; +use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr}; +use rt::uv::addrinfo::{GetAddrInfoRequest, accum_addrinfo}; use unstable::sync::Exclusive; use path::{GenericPath, Path}; use super::super::io::support::PathLike; @@ -43,6 +43,7 @@ use rt::io::{FileMode, FileAccess, OpenOrCreate, Open, Create, CreateOrTruncate, Append, Truncate, Read, Write, ReadWrite, FileStat}; use task; +use ai = rt::io::net::addrinfo; #[cfg(test)] use container::Container; #[cfg(test)] use unstable::run_in_bare_thread; @@ -658,12 +659,16 @@ impl IoFactory for UvIoFactory { return result_cell.take(); } - fn get_host_addresses(&mut self, host: &str) -> Result<~[IpAddr], IoError> { + fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>, + hint: Option) -> Result<~[ai::Info], IoError> { let result_cell = Cell::new_empty(); - let result_cell_ptr: *Cell> = &result_cell; - let host_ptr: *&str = &host; + let result_cell_ptr: *Cell> = &result_cell; + let host_ptr: *Option<&str> = &host; + let servname_ptr: *Option<&str> = &servname; + let hint_ptr: *Option = &hint; let addrinfo_req = GetAddrInfoRequest::new(); let addrinfo_req_cell = Cell::new(addrinfo_req); + do task::unkillable { // FIXME(#8674) let scheduler: ~Scheduler = Local::take(); do scheduler.deschedule_running_task_and_then |_, task| { @@ -671,10 +676,10 @@ impl IoFactory for UvIoFactory { let mut addrinfo_req = addrinfo_req_cell.take(); unsafe { do addrinfo_req.getaddrinfo(self.uv_loop(), - Some(*host_ptr), - None, None) |_, addrinfo, err| { + *host_ptr, *servname_ptr, + *hint_ptr) |_, addrinfo, err| { let res = match err { - None => Ok(accum_sockaddrs(addrinfo).map(|addr| addr.ip.clone())), + None => Ok(accum_addrinfo(addrinfo)), Some(err) => Err(uv_error_to_io_error(err)) }; (*result_cell_ptr).put_back(res); diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index 3e9b8ba136eaa..29d0800237b6b 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -637,3 +637,16 @@ extern "C" int rust_uv_pipe_init(uv_loop_t *loop, uv_pipe_t* p, int ipc) { return uv_pipe_init(loop, p, ipc); } + +extern "C" int rust_SOCK_STREAM() { return SOCK_STREAM; } +extern "C" int rust_SOCK_DGRAM() { return SOCK_DGRAM; } +extern "C" int rust_SOCK_RAW() { return SOCK_RAW; } +extern "C" int rust_IPPROTO_UDP() { return IPPROTO_UDP; } +extern "C" int rust_IPPROTO_TCP() { return IPPROTO_TCP; } +extern "C" int rust_AI_ADDRCONFIG() { return AI_ADDRCONFIG; } +extern "C" int rust_AI_ALL() { return AI_ALL; } +extern "C" int rust_AI_CANONNAME() { return AI_CANONNAME; } +extern "C" int rust_AI_NUMERICHOST() { return AI_NUMERICHOST; } +extern "C" int rust_AI_NUMERICSERV() { return AI_NUMERICSERV; } +extern "C" int rust_AI_PASSIVE() { return AI_PASSIVE; } +extern "C" int rust_AI_V4MAPPED() { return AI_V4MAPPED; } From c6fa4e277f5eb873e979d8ac1ae7a4c3ccb1e9cc Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 15 Oct 2013 20:55:50 -0700 Subject: [PATCH 03/23] Address a few XXX comments throughout the runtime * Implement Seek for Option * Remove outdated comment for io::process * De-pub a component which didn't need to be pub --- src/libstd/rt/io/mod.rs | 3 +-- src/libstd/rt/io/option.rs | 22 +++++++++++++++++++--- src/libstd/rt/io/process.rs | 7 ------- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/libstd/rt/io/mod.rs b/src/libstd/rt/io/mod.rs index a80c1aab39889..a703f9885ac09 100644 --- a/src/libstd/rt/io/mod.rs +++ b/src/libstd/rt/io/mod.rs @@ -332,8 +332,7 @@ pub mod native { mod mock; /// The default buffer size for various I/O operations -/// XXX: Not pub -pub static DEFAULT_BUF_SIZE: uint = 1024 * 64; +static DEFAULT_BUF_SIZE: uint = 1024 * 64; /// The type passed to I/O condition handlers to indicate error /// diff --git a/src/libstd/rt/io/option.rs b/src/libstd/rt/io/option.rs index 2ea1b6154830a..ecfc4a832bfb5 100644 --- a/src/libstd/rt/io/option.rs +++ b/src/libstd/rt/io/option.rs @@ -13,11 +13,9 @@ //! I/O constructors return option types to allow errors to be handled. //! These implementations allow e.g. `Option` to be used //! as a `Reader` without unwrapping the option first. -//! -//! # XXX Seek and Close use option::*; -use super::{Reader, Writer, Listener, Acceptor}; +use super::{Reader, Writer, Listener, Acceptor, Seek, SeekStyle}; use super::{standard_error, PreviousIoError, io_error, read_error, IoError}; fn prev_io_error() -> IoError { @@ -62,6 +60,24 @@ impl Reader for Option { } } +impl Seek for Option { + fn tell(&self) -> u64 { + match *self { + Some(ref seeker) => seeker.tell(), + None => { + io_error::cond.raise(prev_io_error()); + 0 + } + } + } + fn seek(&mut self, pos: i64, style: SeekStyle) { + match *self { + Some(ref mut seeker) => seeker.seek(pos, style), + None => io_error::cond.raise(prev_io_error()) + } + } +} + impl, L: Listener> Listener for Option { fn listen(self) -> Option { match self { diff --git a/src/libstd/rt/io/process.rs b/src/libstd/rt/io/process.rs index e0ffa82b59fe3..0da9c2166b18d 100644 --- a/src/libstd/rt/io/process.rs +++ b/src/libstd/rt/io/process.rs @@ -70,13 +70,6 @@ pub enum StdioContainer { /// specified for. InheritFd(libc::c_int), - // XXX: these two shouldn't have libuv-specific implementation details - - /// The specified libuv stream is inherited for the corresponding file - /// descriptor it is assigned to. - // XXX: this needs to be thought out more. - //InheritStream(uv::net::StreamWatcher), - /// Creates a pipe for the specified file descriptor which will be directed /// into the previously-initialized pipe passed in. /// From 32b07c6a40bd7e1874244096f413096a6e059a29 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 16 Oct 2013 11:39:51 -0700 Subject: [PATCH 04/23] Remove unbound pipes from io::pipe This isn't necessary for creating processes (or at least not right now), and it inherently attempts to expose implementation details. --- src/libstd/rt/io/mod.rs | 1 - src/libstd/rt/io/pipe.rs | 24 +----------------------- src/libstd/rt/io/process.rs | 8 +++----- src/libstd/rt/rtio.rs | 2 -- src/libstd/rt/uv/process.rs | 13 ++++++++----- src/libstd/rt/uv/uvio.rs | 15 ++++++++++----- src/test/run-pass/rtio-processes.rs | 13 ++++--------- 7 files changed, 26 insertions(+), 50 deletions(-) diff --git a/src/libstd/rt/io/mod.rs b/src/libstd/rt/io/mod.rs index a703f9885ac09..eaff43378f2ed 100644 --- a/src/libstd/rt/io/mod.rs +++ b/src/libstd/rt/io/mod.rs @@ -261,7 +261,6 @@ pub use self::net::tcp::TcpListener; pub use self::net::tcp::TcpStream; pub use self::net::udp::UdpStream; pub use self::pipe::PipeStream; -pub use self::pipe::UnboundPipeStream; pub use self::process::Process; // Some extension traits that all Readers and Writers get. diff --git a/src/libstd/rt/io/pipe.rs b/src/libstd/rt/io/pipe.rs index ff1bd55d594b7..67e04f57f4f2f 100644 --- a/src/libstd/rt/io/pipe.rs +++ b/src/libstd/rt/io/pipe.rs @@ -16,35 +16,13 @@ use prelude::*; use super::{Reader, Writer}; use rt::io::{io_error, read_error, EndOfFile}; -use rt::local::Local; -use rt::rtio::{RtioPipe, RtioPipeObject, IoFactoryObject, IoFactory}; -use rt::rtio::RtioUnboundPipeObject; +use rt::rtio::{RtioPipe, RtioPipeObject}; pub struct PipeStream { priv obj: ~RtioPipeObject } -// This should not be a newtype, but rt::uv::process::set_stdio needs to reach -// into the internals of this :( -pub struct UnboundPipeStream(~RtioUnboundPipeObject); - impl PipeStream { - /// Creates a new pipe initialized, but not bound to any particular - /// source/destination - pub fn new() -> Option { - let pipe = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).pipe_init(false) - }; - match pipe { - Ok(p) => Some(UnboundPipeStream(p)), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None - } - } - } - pub fn new_bound(inner: ~RtioPipeObject) -> PipeStream { PipeStream { obj: inner } } diff --git a/src/libstd/rt/io/process.rs b/src/libstd/rt/io/process.rs index 0da9c2166b18d..f6e8b87344f98 100644 --- a/src/libstd/rt/io/process.rs +++ b/src/libstd/rt/io/process.rs @@ -70,15 +70,13 @@ pub enum StdioContainer { /// specified for. InheritFd(libc::c_int), - /// Creates a pipe for the specified file descriptor which will be directed - /// into the previously-initialized pipe passed in. + /// Creates a pipe for the specified file descriptor which will be created + /// when the process is spawned. /// /// The first boolean argument is whether the pipe is readable, and the /// second is whether it is writable. These properties are from the view of /// the *child* process, not the parent process. - CreatePipe(io::UnboundPipeStream, - bool /* readable */, - bool /* writable */), + CreatePipe(bool /* readable */, bool /* writable */), } impl Process { diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index 4a290ca46e50e..c37d9bf913b7b 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -35,7 +35,6 @@ pub type RtioUdpSocketObject = uvio::UvUdpSocket; pub type RtioTimerObject = uvio::UvTimer; pub type PausibleIdleCallback = uvio::UvPausibleIdleCallback; pub type RtioPipeObject = uvio::UvPipeStream; -pub type RtioUnboundPipeObject = uvio::UvUnboundPipe; pub type RtioProcessObject = uvio::UvProcess; pub type RtioUnixListenerObject = uvio::UvUnixListener; pub type RtioUnixAcceptorObject = uvio::UvUnixAcceptor; @@ -88,7 +87,6 @@ pub trait IoFactory { fn fs_rmdir(&mut self, path: &P) -> Result<(), IoError>; fn fs_readdir(&mut self, path: &P, flags: c_int) -> Result<~[Path], IoError>; - fn pipe_init(&mut self, ipc: bool) -> Result<~RtioUnboundPipeObject, IoError>; fn spawn(&mut self, config: ProcessConfig) -> Result<(~RtioProcessObject, ~[Option<~RtioPipeObject>]), IoError>; diff --git a/src/libstd/rt/uv/process.rs b/src/libstd/rt/uv/process.rs index 3c629a783cf7a..25c516b600872 100644 --- a/src/libstd/rt/uv/process.rs +++ b/src/libstd/rt/uv/process.rs @@ -17,7 +17,7 @@ use vec; use rt::io::process::*; use rt::uv; -use rt::uv::uvio::UvPipeStream; +use rt::uv::uvio::{UvPipeStream, UvUnboundPipe}; use rt::uv::uvll; /// A process wraps the handle of the underlying uv_process_t. @@ -68,7 +68,8 @@ impl Process { unsafe { vec::raw::set_len(&mut stdio, io.len()); for (slot, other) in stdio.iter().zip(io.move_iter()) { - let io = set_stdio(slot as *uvll::uv_stdio_container_t, other); + let io = set_stdio(slot as *uvll::uv_stdio_container_t, other, + loop_); ret_io.push(io); } } @@ -144,7 +145,8 @@ impl Process { } unsafe fn set_stdio(dst: *uvll::uv_stdio_container_t, - io: StdioContainer) -> Option<~UvPipeStream> { + io: StdioContainer, + loop_: &uv::Loop) -> Option<~UvPipeStream> { match io { Ignored => { uvll::set_stdio_container_flags(dst, uvll::STDIO_IGNORE); @@ -155,7 +157,7 @@ unsafe fn set_stdio(dst: *uvll::uv_stdio_container_t, uvll::set_stdio_container_fd(dst, fd); None } - CreatePipe(pipe, readable, writable) => { + CreatePipe(readable, writable) => { let mut flags = uvll::STDIO_CREATE_PIPE as libc::c_int; if readable { flags |= uvll::STDIO_READABLE_PIPE as libc::c_int; @@ -163,10 +165,11 @@ unsafe fn set_stdio(dst: *uvll::uv_stdio_container_t, if writable { flags |= uvll::STDIO_WRITABLE_PIPE as libc::c_int; } + let pipe = UvUnboundPipe::new_fresh(loop_); let handle = pipe.pipe.as_stream().native_handle(); uvll::set_stdio_container_flags(dst, flags); uvll::set_stdio_container_stream(dst, handle); - Some(~UvPipeStream::new(**pipe)) + Some(~UvPipeStream::new(pipe)) } } } diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index bc9be40cde563..db19bc7463a9c 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -749,11 +749,6 @@ impl IoFactory for UvIoFactory { return result_cell.take(); } - fn pipe_init(&mut self, ipc: bool) -> Result<~RtioUnboundPipeObject, IoError> { - let home = get_handle_to_current_scheduler!(); - Ok(~UvUnboundPipe::new(Pipe::new(self.uv_loop(), ipc), home)) - } - fn spawn(&mut self, config: ProcessConfig) -> Result<(~RtioProcessObject, ~[Option<~RtioPipeObject>]), IoError> { @@ -1069,9 +1064,19 @@ pub struct UvUnboundPipe { } impl UvUnboundPipe { + /// Takes ownership of an unbound pipe along with the scheduler that it is + /// homed on. fn new(pipe: Pipe, home: SchedHandle) -> UvUnboundPipe { UvUnboundPipe { pipe: pipe, home: home } } + + /// Creates a fresh new unbound pipe on the specified I/O loop + pub fn new_fresh(loop_: &Loop) -> UvUnboundPipe { + UvUnboundPipe { + pipe: Pipe::new(loop_, false), + home: get_handle_to_current_scheduler!(), + } + } } impl HomingIO for UvUnboundPipe { diff --git a/src/test/run-pass/rtio-processes.rs b/src/test/run-pass/rtio-processes.rs index 70d8b8fe5a4b8..14595f83ce506 100644 --- a/src/test/run-pass/rtio-processes.rs +++ b/src/test/run-pass/rtio-processes.rs @@ -25,7 +25,6 @@ use std::rt::io::process::{Process, ProcessConfig, CreatePipe, Ignored}; use std::rt::io::{Reader, Writer}; -use std::rt::io::pipe::PipeStream; use std::str; #[test] @@ -105,8 +104,7 @@ fn run_output(args: ProcessConfig) -> ~str { #[test] #[cfg(unix, not(target_os="android"))] fn stdout_works() { - let pipe = PipeStream::new().unwrap(); - let io = ~[Ignored, CreatePipe(pipe, false, true)]; + let io = ~[Ignored, CreatePipe(false, true)]; let args = ProcessConfig { program: "/bin/sh", args: [~"-c", ~"echo foobar"], @@ -120,8 +118,7 @@ fn stdout_works() { #[test] #[cfg(unix, not(target_os="android"))] fn set_cwd_works() { - let pipe = PipeStream::new().unwrap(); - let io = ~[Ignored, CreatePipe(pipe, false, true)]; + let io = ~[Ignored, CreatePipe(false, true)]; let cwd = Some("/"); let args = ProcessConfig { program: "/bin/sh", @@ -136,10 +133,8 @@ fn set_cwd_works() { #[test] #[cfg(unix, not(target_os="android"))] fn stdin_works() { - let input = PipeStream::new().unwrap(); - let output = PipeStream::new().unwrap(); - let io = ~[CreatePipe(input, true, false), - CreatePipe(output, false, true)]; + let io = ~[CreatePipe(true, false), + CreatePipe(false, true)]; let args = ProcessConfig { program: "/bin/sh", args: [~"-c", ~"read line; echo $line"], From 35756fbcf6572d588929fde64fb4027f47e9d0af Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 16 Oct 2013 11:47:12 -0700 Subject: [PATCH 05/23] 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) --- src/libstd/rt/io/stdio.rs | 102 +++++++++++++++++++++++++++++++----- src/libstd/rt/rtio.rs | 11 ++++ src/libstd/rt/uv/async.rs | 25 +-------- src/libstd/rt/uv/idle.rs | 25 +-------- src/libstd/rt/uv/mod.rs | 28 ++++++++++ src/libstd/rt/uv/net.rs | 39 +------------- src/libstd/rt/uv/pipe.rs | 17 ------ src/libstd/rt/uv/process.rs | 19 ------- src/libstd/rt/uv/timer.rs | 29 +--------- src/libstd/rt/uv/tty.rs | 89 +++++++++++++++++++++++++++++++ src/libstd/rt/uv/uvio.rs | 74 ++++++++++++++++++++++++++ src/libstd/rt/uv/uvll.rs | 7 +++ src/rt/rustrt.def.in | 4 ++ 13 files changed, 307 insertions(+), 162 deletions(-) create mode 100644 src/libstd/rt/uv/tty.rs diff --git a/src/libstd/rt/io/stdio.rs b/src/libstd/rt/io/stdio.rs index e6dd9a480998e..0bc87c77a9c7b 100644 --- a/src/libstd/rt/io/stdio.rs +++ b/src/libstd/rt/io/stdio.rs @@ -13,7 +13,7 @@ use libc; use option::{Option, Some, None}; use result::{Ok, Err}; use rt::local::Local; -use rt::rtio::{RtioFileStream, IoFactoryObject, IoFactory}; +use rt::rtio::{IoFactoryObject, IoFactory, RtioTTYObject, RtioTTY}; use super::{Reader, Writer, io_error}; /// Creates a new non-blocking handle to the stdin of the current process. @@ -22,8 +22,8 @@ use super::{Reader, Writer, io_error}; pub fn stdin() -> StdReader { let stream = unsafe { let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).fs_from_raw_fd(libc::STDIN_FILENO, false) - }; + (*io).tty_open(libc::STDIN_FILENO, true, false) + }.unwrap(); StdReader { inner: stream } } @@ -36,8 +36,8 @@ pub fn stdin() -> StdReader { pub fn stdout() -> StdWriter { let stream = unsafe { let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).fs_from_raw_fd(libc::STDOUT_FILENO, false) - }; + (*io).tty_open(libc::STDOUT_FILENO, false, false) + }.unwrap(); StdWriter { inner: stream } } @@ -47,8 +47,8 @@ pub fn stdout() -> StdWriter { pub fn stderr() -> StdWriter { let stream = unsafe { let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).fs_from_raw_fd(libc::STDERR_FILENO, false) - }; + (*io).tty_open(libc::STDERR_FILENO, false, false) + }.unwrap(); StdWriter { inner: stream } } @@ -87,7 +87,30 @@ pub fn println_args(fmt: &fmt::Arguments) { /// Representation of a reader of a standard input stream pub struct StdReader { - priv inner: ~RtioFileStream + priv inner: ~RtioTTYObject +} + +impl StdReader { + /// Controls whether this output stream is a "raw stream" or simply a normal + /// stream. + /// + /// # Failure + /// + /// This function will raise on the `io_error` condition if an error + /// happens. + pub fn set_raw(&mut self, raw: bool) { + match self.inner.set_raw(raw) { + Ok(()) => {}, + Err(e) => io_error::cond.raise(e), + } + } + + /// Resets the mode of this stream back to its original state. + /// + /// # Failure + /// + /// This function cannot fail. + pub fn reset_mode(&mut self) { self.inner.reset_mode(); } } impl Reader for StdReader { @@ -106,7 +129,50 @@ impl Reader for StdReader { /// Representation of a writer to a standard output stream pub struct StdWriter { - priv inner: ~RtioFileStream + priv inner: ~RtioTTYObject +} + +impl StdWriter { + /// Gets the size of this output window, if possible. This is typically used + /// when the writer is attached to something like a terminal, this is used + /// to fetch the dimensions of the terminal. + /// + /// If successful, returns Some((width, height)). + /// + /// # Failure + /// + /// This function will raise on the `io_error` condition if an error + /// happens. + pub fn winsize(&mut self) -> Option<(int, int)> { + match self.inner.get_winsize() { + Ok(p) => Some(p), + Err(e) => { + io_error::cond.raise(e); + None + } + } + } + + /// Controls whether this output stream is a "raw stream" or simply a normal + /// stream. + /// + /// # Failure + /// + /// This function will raise on the `io_error` condition if an error + /// happens. + pub fn set_raw(&mut self, raw: bool) { + match self.inner.set_raw(raw) { + Ok(()) => {}, + Err(e) => io_error::cond.raise(e), + } + } + + /// Resets the mode of this stream back to its original state. + /// + /// # Failure + /// + /// This function cannot fail. + pub fn reset_mode(&mut self) { self.inner.reset_mode(); } } impl Writer for StdWriter { @@ -117,10 +183,18 @@ impl Writer for StdWriter { } } - fn flush(&mut self) { - match self.inner.flush() { - Ok(()) => {} - Err(e) => io_error::cond.raise(e) - } + fn flush(&mut self) { /* nothing to do */ } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn smoke() { + // Just make sure we can acquire handles + stdin(); + stdout(); + stderr(); } } diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index c37d9bf913b7b..3c513e263f167 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -38,6 +38,7 @@ pub type RtioPipeObject = uvio::UvPipeStream; pub type RtioProcessObject = uvio::UvProcess; pub type RtioUnixListenerObject = uvio::UvUnixListener; pub type RtioUnixAcceptorObject = uvio::UvUnixAcceptor; +pub type RtioTTYObject = uvio::UvTTY; pub trait EventLoop { fn run(&mut self); @@ -94,6 +95,8 @@ pub trait IoFactory { Result<~RtioUnixListenerObject, IoError>; fn unix_connect(&mut self, path: &P) -> Result<~RtioPipeObject, IoError>; + fn tty_open(&mut self, fd: c_int, readable: bool, close_on_drop: bool) + -> Result<~RtioTTYObject, IoError>; } pub trait RtioTcpListener : RtioSocket { @@ -171,3 +174,11 @@ pub trait RtioUnixAcceptor { fn accept_simultaneously(&mut self) -> Result<(), IoError>; fn dont_accept_simultaneously(&mut self) -> Result<(), IoError>; } + +pub trait RtioTTY { + fn read(&mut self, buf: &mut [u8]) -> Result; + fn write(&mut self, buf: &[u8]) -> Result<(), IoError>; + fn set_raw(&mut self, raw: bool) -> Result<(), IoError>; + fn reset_mode(&mut self); + fn get_winsize(&mut self) -> Result<(int, int), IoError>; +} diff --git a/src/libstd/rt/uv/async.rs b/src/libstd/rt/uv/async.rs index ff7bb9dd03abc..108aef43c3c9a 100644 --- a/src/libstd/rt/uv/async.rs +++ b/src/libstd/rt/uv/async.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use libc::{c_int, c_void}; +use libc::c_int; use option::Some; use rt::uv::uvll; use rt::uv::uvll::UV_ASYNC; -use rt::uv::{Watcher, Loop, NativeHandle, AsyncCallback, NullCallback}; +use rt::uv::{Watcher, Loop, NativeHandle, AsyncCallback}; use rt::uv::WatcherInterop; use rt::uv::status_to_maybe_uv_error; @@ -47,27 +47,6 @@ impl AsyncWatcher { uvll::async_send(handle); } } - - pub fn close(self, cb: NullCallback) { - let mut this = self; - let data = this.get_watcher_data(); - assert!(data.close_cb.is_none()); - data.close_cb = Some(cb); - - unsafe { - uvll::close(self.native_handle(), close_cb); - } - - extern fn close_cb(handle: *uvll::uv_stream_t) { - let mut watcher: AsyncWatcher = NativeHandle::from_native_handle(handle); - { - let data = watcher.get_watcher_data(); - data.close_cb.take_unwrap()(); - } - watcher.drop_watcher_data(); - unsafe { uvll::free_handle(handle as *c_void); } - } - } } impl NativeHandle<*uvll::uv_async_t> for AsyncWatcher { diff --git a/src/libstd/rt/uv/idle.rs b/src/libstd/rt/uv/idle.rs index 8cbcd7b77c082..9d392583b9e12 100644 --- a/src/libstd/rt/uv/idle.rs +++ b/src/libstd/rt/uv/idle.rs @@ -11,7 +11,7 @@ use libc::c_int; use option::Some; use rt::uv::uvll; -use rt::uv::{Watcher, Loop, NativeHandle, IdleCallback, NullCallback}; +use rt::uv::{Watcher, Loop, NativeHandle, IdleCallback}; use rt::uv::status_to_maybe_uv_error; pub struct IdleWatcher(*uvll::uv_idle_t); @@ -71,29 +71,6 @@ impl IdleWatcher { assert!(0 == uvll::idle_stop(self.native_handle())); } } - - pub fn close(self, cb: NullCallback) { - { - let mut this = self; - let data = this.get_watcher_data(); - assert!(data.close_cb.is_none()); - data.close_cb = Some(cb); - } - - unsafe { uvll::close(self.native_handle(), close_cb) }; - - extern fn close_cb(handle: *uvll::uv_idle_t) { - unsafe { - let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle); - { - let data = idle_watcher.get_watcher_data(); - data.close_cb.take_unwrap()(); - } - idle_watcher.drop_watcher_data(); - uvll::idle_delete(handle); - } - } - } } impl NativeHandle<*uvll::uv_idle_t> for IdleWatcher { diff --git a/src/libstd/rt/uv/mod.rs b/src/libstd/rt/uv/mod.rs index 3a6a3acbc5342..a03264af7e1e9 100644 --- a/src/libstd/rt/uv/mod.rs +++ b/src/libstd/rt/uv/mod.rs @@ -75,6 +75,7 @@ pub mod async; pub mod addrinfo; pub mod process; pub mod pipe; +pub mod tty; /// XXX: Loop(*handle) is buggy with destructors. Normal structs /// with dtors may not be destructured, but tuple structs can, @@ -83,6 +84,14 @@ pub struct Loop { priv handle: *uvll::uv_loop_t } +pub struct Handle(*uvll::uv_handle_t); + +impl Watcher for Handle {} +impl NativeHandle<*uvll::uv_handle_t> for Handle { + fn from_native_handle(h: *uvll::uv_handle_t) -> Handle { Handle(h) } + fn native_handle(&self) -> *uvll::uv_handle_t { **self } +} + /// The trait implemented by uv 'watchers' (handles). Watchers are /// non-owning wrappers around the uv handles and are not completely /// safe - there may be multiple instances for a single underlying @@ -160,6 +169,7 @@ pub trait WatcherInterop { fn install_watcher_data(&mut self); fn get_watcher_data<'r>(&'r mut self) -> &'r mut WatcherData; fn drop_watcher_data(&mut self); + fn close(self, cb: NullCallback); } impl> WatcherInterop for W { @@ -207,6 +217,24 @@ impl> WatcherInterop for W { uvll::set_data_for_uv_handle(self.native_handle(), null::<()>()); } } + + fn close(self, cb: NullCallback) { + let mut this = self; + { + let data = this.get_watcher_data(); + assert!(data.close_cb.is_none()); + data.close_cb = Some(cb); + } + + unsafe { uvll::close(this.native_handle(), close_cb); } + + extern fn close_cb(handle: *uvll::uv_handle_t) { + let mut h: Handle = NativeHandle::from_native_handle(handle); + h.get_watcher_data().close_cb.take_unwrap()(); + h.drop_watcher_data(); + unsafe { uvll::free_handle(handle as *c_void) } + } + } } // XXX: Need to define the error constants like EOF so they can be diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs index e2f2510c48781..3ab0655071acb 100644 --- a/src/libstd/rt/uv/net.rs +++ b/src/libstd/rt/uv/net.rs @@ -13,7 +13,7 @@ use libc::{size_t, ssize_t, c_int, c_void, c_uint}; use rt::uv::uvll; use rt::uv::uvll::*; use rt::uv::{AllocCallback, ConnectionCallback, ReadCallback, UdpReceiveCallback, UdpSendCallback}; -use rt::uv::{Loop, Watcher, Request, UvError, Buf, NativeHandle, NullCallback, +use rt::uv::{Loop, Watcher, Request, UvError, Buf, NativeHandle, status_to_maybe_uv_error, vec_to_uv_buf}; use rt::io::net::ip::{SocketAddr, Ipv4Addr, Ipv6Addr}; use vec; @@ -184,24 +184,6 @@ impl StreamWatcher { } } - pub fn close(self, cb: NullCallback) { - { - let mut this = self; - let data = this.get_watcher_data(); - assert!(data.close_cb.is_none()); - data.close_cb = Some(cb); - } - - unsafe { uvll::close(self.native_handle(), close_cb); } - - extern fn close_cb(handle: *uvll::uv_stream_t) { - let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(handle); - let cb = stream_watcher.get_watcher_data().close_cb.take_unwrap(); - stream_watcher.drop_watcher_data(); - unsafe { free_handle(handle as *c_void) } - cb(); - } - } pub fn listen(&mut self, cb: ConnectionCallback) -> Result<(), UvError> { { @@ -413,25 +395,6 @@ impl UdpWatcher { cb(udp_watcher, status); } } - - pub fn close(self, cb: NullCallback) { - { - let mut this = self; - let data = this.get_watcher_data(); - assert!(data.close_cb.is_none()); - data.close_cb = Some(cb); - } - - unsafe { uvll::close(self.native_handle(), close_cb); } - - extern fn close_cb(handle: *uvll::uv_udp_t) { - let mut udp_watcher: UdpWatcher = NativeHandle::from_native_handle(handle); - let cb = udp_watcher.get_watcher_data().close_cb.take_unwrap(); - udp_watcher.drop_watcher_data(); - unsafe { free_handle(handle as *c_void) } - cb(); - } - } } impl NativeHandle<*uvll::uv_udp_t> for UdpWatcher { diff --git a/src/libstd/rt/uv/pipe.rs b/src/libstd/rt/uv/pipe.rs index 1cb86d4df2ca2..2ad5079e5d546 100644 --- a/src/libstd/rt/uv/pipe.rs +++ b/src/libstd/rt/uv/pipe.rs @@ -86,23 +86,6 @@ impl Pipe { } } - pub fn close(self, cb: uv::NullCallback) { - { - let mut this = self; - let data = this.get_watcher_data(); - assert!(data.close_cb.is_none()); - data.close_cb = Some(cb); - } - - unsafe { uvll::close(self.native_handle(), close_cb); } - - extern "C" fn close_cb(handle: *uvll::uv_pipe_t) { - let mut process: Pipe = uv::NativeHandle::from_native_handle(handle); - process.get_watcher_data().close_cb.take_unwrap()(); - process.drop_watcher_data(); - unsafe { uvll::free_handle(handle as *libc::c_void) } - } - } } impl uv::NativeHandle<*uvll::uv_pipe_t> for Pipe { diff --git a/src/libstd/rt/uv/process.rs b/src/libstd/rt/uv/process.rs index 25c516b600872..c3417109645d4 100644 --- a/src/libstd/rt/uv/process.rs +++ b/src/libstd/rt/uv/process.rs @@ -123,25 +123,6 @@ impl Process { pub fn pid(&self) -> libc::pid_t { unsafe { uvll::process_pid(**self) as libc::pid_t } } - - /// Closes this handle, invoking the specified callback once closed - pub fn close(self, cb: uv::NullCallback) { - { - let mut this = self; - let data = this.get_watcher_data(); - assert!(data.close_cb.is_none()); - data.close_cb = Some(cb); - } - - unsafe { uvll::close(self.native_handle(), close_cb); } - - extern fn close_cb(handle: *uvll::uv_process_t) { - let mut process: Process = uv::NativeHandle::from_native_handle(handle); - process.get_watcher_data().close_cb.take_unwrap()(); - process.drop_watcher_data(); - unsafe { uvll::free_handle(handle as *libc::c_void) } - } - } } unsafe fn set_stdio(dst: *uvll::uv_stdio_container_t, diff --git a/src/libstd/rt/uv/timer.rs b/src/libstd/rt/uv/timer.rs index 7b09cf2eb0e3a..fb3c84df39f9b 100644 --- a/src/libstd/rt/uv/timer.rs +++ b/src/libstd/rt/uv/timer.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use libc::{c_void, c_int}; +use libc::c_int; use option::Some; use rt::uv::uvll; -use rt::uv::{Watcher, Loop, NativeHandle, TimerCallback, NullCallback}; +use rt::uv::{Watcher, Loop, NativeHandle, TimerCallback}; use rt::uv::status_to_maybe_uv_error; pub struct TimerWatcher(*uvll::uv_timer_t); @@ -53,31 +53,6 @@ impl TimerWatcher { uvll::timer_stop(self.native_handle()); } } - - pub fn close(self, cb: NullCallback) { - let mut watcher = self; - { - let data = watcher.get_watcher_data(); - assert!(data.close_cb.is_none()); - data.close_cb = Some(cb); - } - - unsafe { - uvll::close(watcher.native_handle(), close_cb); - } - - extern fn close_cb(handle: *uvll::uv_timer_t) { - let mut watcher: TimerWatcher = NativeHandle::from_native_handle(handle); - { - let data = watcher.get_watcher_data(); - data.close_cb.take_unwrap()(); - } - watcher.drop_watcher_data(); - unsafe { - uvll::free_handle(handle as *c_void); - } - } - } } impl NativeHandle<*uvll::uv_timer_t> for TimerWatcher { diff --git a/src/libstd/rt/uv/tty.rs b/src/libstd/rt/uv/tty.rs new file mode 100644 index 0000000000000..4c9a08f95bf84 --- /dev/null +++ b/src/libstd/rt/uv/tty.rs @@ -0,0 +1,89 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use prelude::*; +use libc; + +use rt::uv; +use rt::uv::net; +use rt::uv::uvll; + +/// A process wraps the handle of the underlying uv_process_t. +pub struct TTY(*uvll::uv_tty_t); + +impl uv::Watcher for TTY {} + +impl TTY { + #[fixed_stack_segment] #[inline(never)] + pub fn new(loop_: &uv::Loop, fd: libc::c_int, readable: bool) -> + Result + { + let handle = unsafe { uvll::malloc_handle(uvll::UV_TTY) }; + assert!(handle.is_not_null()); + + let ret = unsafe { + uvll::uv_tty_init(loop_.native_handle(), handle, fd as libc::c_int, + readable as libc::c_int) + }; + match ret { + 0 => { + let mut ret: TTY = uv::NativeHandle::from_native_handle(handle); + ret.install_watcher_data(); + Ok(ret) + } + n => { + unsafe { uvll::free_handle(handle); } + Err(uv::UvError(n)) + } + } + } + + pub fn as_stream(&self) -> net::StreamWatcher { + net::StreamWatcher(**self as *uvll::uv_stream_t) + } + + #[fixed_stack_segment] #[inline(never)] + pub fn set_mode(&self, raw: bool) -> Result<(), uv::UvError> { + let raw = raw as libc::c_int; + match unsafe { uvll::uv_tty_set_mode(self.native_handle(), raw) } { + 0 => Ok(()), + n => Err(uv::UvError(n)) + } + } + + #[fixed_stack_segment] #[inline(never)] + pub fn reset_mode(&self) { + unsafe { uvll::uv_tty_reset_mode(self.native_handle()) } + } + + #[fixed_stack_segment] #[inline(never)] #[allow(unused_mut)] + pub fn get_winsize(&self) -> Result<(int, int), uv::UvError> { + let mut width: libc::c_int = 0; + let mut height: libc::c_int = 0; + let widthptr: *libc::c_int = &width; + let heightptr: *libc::c_int = &width; + + match unsafe { uvll::uv_tty_get_winsize(self.native_handle(), + widthptr, heightptr) } { + 0 => Ok((width as int, height as int)), + n => Err(uv::UvError(n)) + } + } +} + +impl uv::NativeHandle<*uvll::uv_tty_t> for TTY { + fn from_native_handle(handle: *uvll::uv_tty_t) -> TTY { + TTY(handle) + } + fn native_handle(&self) -> *uvll::uv_tty_t { + match self { &TTY(ptr) => ptr } + } +} + diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index db19bc7463a9c..f1a5916ee1389 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>, @@ -1769,6 +1809,40 @@ impl RtioUnixAcceptor for UvUnixAcceptor { } } +impl RtioTTY for UvTTY { + fn read(&mut self, buf: &mut [u8]) -> Result { + 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 { diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index eb770d0807074..8ef1d1768b8c4 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -131,6 +131,7 @@ pub type uv_udp_send_t = c_void; pub type uv_getaddrinfo_t = c_void; pub type uv_process_t = c_void; pub type uv_pipe_t = c_void; +pub type uv_tty_t = c_void; pub struct uv_timespec_t { tv_sec: libc::c_long, @@ -1107,6 +1108,12 @@ extern { pub fn uv_pipe_bind(pipe: *uv_pipe_t, name: *c_char) -> c_int; pub fn uv_pipe_connect(req: *uv_connect_t, handle: *uv_pipe_t, name: *c_char, cb: uv_connect_cb); + pub fn uv_tty_init(loop_ptr: *uv_loop_t, tty: *uv_tty_t, fd: c_int, + readable: c_int) -> c_int; + pub fn uv_tty_set_mode(tty: *uv_tty_t, mode: c_int) -> c_int; + pub fn uv_tty_reset_mode(tty: *uv_tty_t); + pub fn uv_tty_get_winsize(tty: *uv_tty_t, width: *c_int, + height: *c_int) -> c_int; // These should all really be constants... #[rust_stack] pub fn rust_SOCK_STREAM() -> c_int; diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index b144820c44246..5945fdc3e59b1 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -214,3 +214,7 @@ rust_AI_V4MAPPED uv_pipe_open uv_pipe_bind uv_pipe_connect +uv_tty_init +uv_tty_set_mode +uv_tty_reset_mode +uv_tty_get_winsize From 0cad9847652088b35ee4c13c04539ca3a67611f7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 16 Oct 2013 14:48:05 -0700 Subject: [PATCH 06/23] Migrate Rtio objects to true trait objects This moves as many as I could over to ~Trait instead of ~Typedef. The only remaining one is the IoFactoryObject which should be coming soon... --- src/libstd/rt/io/net/tcp.rs | 13 +++---- src/libstd/rt/io/net/udp.rs | 4 +- src/libstd/rt/io/net/unix.rs | 9 ++--- src/libstd/rt/io/pipe.rs | 6 +-- src/libstd/rt/io/process.rs | 4 +- src/libstd/rt/io/stdio.rs | 6 +-- src/libstd/rt/io/timer.rs | 5 +-- src/libstd/rt/mod.rs | 4 +- src/libstd/rt/rtio.rs | 46 ++++++++++------------- src/libstd/rt/sched.rs | 12 +++--- src/libstd/rt/test.rs | 5 ++- src/libstd/rt/uv/uvio.rs | 73 +++++++++++++++++++----------------- src/libstd/task/spawn.rs | 4 +- 13 files changed, 92 insertions(+), 99 deletions(-) diff --git a/src/libstd/rt/io/net/tcp.rs b/src/libstd/rt/io/net/tcp.rs index f29e17cfc2f3d..946ecbea6f778 100644 --- a/src/libstd/rt/io/net/tcp.rs +++ b/src/libstd/rt/io/net/tcp.rs @@ -13,19 +13,16 @@ use result::{Ok, Err}; use rt::io::net::ip::SocketAddr; use rt::io::{Reader, Writer, Listener, Acceptor}; use rt::io::{io_error, read_error, EndOfFile}; -use rt::rtio::{IoFactory, IoFactoryObject, - RtioSocket, - RtioTcpListener, RtioTcpListenerObject, - RtioTcpAcceptor, RtioTcpAcceptorObject, - RtioTcpStream, RtioTcpStreamObject}; +use rt::rtio::{IoFactory, IoFactoryObject, RtioTcpListenerObject, + RtioSocket, RtioTcpListener, RtioTcpAcceptor, RtioTcpStream}; use rt::local::Local; pub struct TcpStream { - priv obj: ~RtioTcpStreamObject + priv obj: ~RtioTcpStream } impl TcpStream { - fn new(s: ~RtioTcpStreamObject) -> TcpStream { + fn new(s: ~RtioTcpStream) -> TcpStream { TcpStream { obj: s } } @@ -142,7 +139,7 @@ impl Listener for TcpListener { } pub struct TcpAcceptor { - priv obj: ~RtioTcpAcceptorObject + priv obj: ~RtioTcpAcceptor } impl Acceptor for TcpAcceptor { diff --git a/src/libstd/rt/io/net/udp.rs b/src/libstd/rt/io/net/udp.rs index 27faae0838b15..ed01dc9dcdaa5 100644 --- a/src/libstd/rt/io/net/udp.rs +++ b/src/libstd/rt/io/net/udp.rs @@ -13,11 +13,11 @@ use result::{Ok, Err}; use rt::io::net::ip::SocketAddr; use rt::io::{Reader, Writer}; use rt::io::{io_error, read_error, EndOfFile}; -use rt::rtio::{RtioSocket, RtioUdpSocketObject, RtioUdpSocket, IoFactory, IoFactoryObject}; +use rt::rtio::{RtioSocket, RtioUdpSocket, IoFactory, IoFactoryObject}; use rt::local::Local; pub struct UdpSocket { - priv obj: ~RtioUdpSocketObject + priv obj: ~RtioUdpSocket } impl UdpSocket { diff --git a/src/libstd/rt/io/net/unix.rs b/src/libstd/rt/io/net/unix.rs index 9428c1f800d15..1394cdb04a87c 100644 --- a/src/libstd/rt/io/net/unix.rs +++ b/src/libstd/rt/io/net/unix.rs @@ -25,9 +25,8 @@ instances as clients. use prelude::*; use super::super::support::PathLike; -use rt::rtio::{IoFactory, IoFactoryObject, RtioUnixListenerObject}; -use rt::rtio::{RtioUnixAcceptorObject, RtioPipeObject, RtioUnixListener}; -use rt::rtio::RtioUnixAcceptor; +use rt::rtio::{IoFactory, IoFactoryObject, RtioUnixListener}; +use rt::rtio::{RtioUnixAcceptor, RtioPipe, RtioUnixListenerObject}; use rt::io::pipe::PipeStream; use rt::io::{io_error, Listener, Acceptor, Reader, Writer}; use rt::local::Local; @@ -38,7 +37,7 @@ pub struct UnixStream { } impl UnixStream { - fn new(obj: ~RtioPipeObject) -> UnixStream { + fn new(obj: ~RtioPipe) -> UnixStream { UnixStream { obj: PipeStream::new_bound(obj) } } @@ -141,7 +140,7 @@ impl Listener for UnixListener { } pub struct UnixAcceptor { - priv obj: ~RtioUnixAcceptorObject, + priv obj: ~RtioUnixAcceptor, } impl Acceptor for UnixAcceptor { diff --git a/src/libstd/rt/io/pipe.rs b/src/libstd/rt/io/pipe.rs index 67e04f57f4f2f..c15fbc79da9f6 100644 --- a/src/libstd/rt/io/pipe.rs +++ b/src/libstd/rt/io/pipe.rs @@ -16,14 +16,14 @@ use prelude::*; use super::{Reader, Writer}; use rt::io::{io_error, read_error, EndOfFile}; -use rt::rtio::{RtioPipe, RtioPipeObject}; +use rt::rtio::RtioPipe; pub struct PipeStream { - priv obj: ~RtioPipeObject + priv obj: ~RtioPipe, } impl PipeStream { - pub fn new_bound(inner: ~RtioPipeObject) -> PipeStream { + pub fn new_bound(inner: ~RtioPipe) -> PipeStream { PipeStream { obj: inner } } } diff --git a/src/libstd/rt/io/process.rs b/src/libstd/rt/io/process.rs index f6e8b87344f98..c13b275ae52bf 100644 --- a/src/libstd/rt/io/process.rs +++ b/src/libstd/rt/io/process.rs @@ -16,7 +16,7 @@ use libc; use rt::io; use rt::io::io_error; use rt::local::Local; -use rt::rtio::{RtioProcess, RtioProcessObject, IoFactoryObject, IoFactory}; +use rt::rtio::{RtioProcess, IoFactoryObject, IoFactory}; // windows values don't matter as long as they're at least one of unix's // TERM/KILL/INT signals @@ -26,7 +26,7 @@ use rt::rtio::{RtioProcess, RtioProcessObject, IoFactoryObject, IoFactory}; #[cfg(not(windows))] pub static MustDieSignal: int = libc::SIGKILL as int; pub struct Process { - priv handle: ~RtioProcessObject, + priv handle: ~RtioProcess, io: ~[Option], } diff --git a/src/libstd/rt/io/stdio.rs b/src/libstd/rt/io/stdio.rs index 0bc87c77a9c7b..77ac87830e253 100644 --- a/src/libstd/rt/io/stdio.rs +++ b/src/libstd/rt/io/stdio.rs @@ -13,7 +13,7 @@ use libc; use option::{Option, Some, None}; use result::{Ok, Err}; use rt::local::Local; -use rt::rtio::{IoFactoryObject, IoFactory, RtioTTYObject, RtioTTY}; +use rt::rtio::{IoFactoryObject, IoFactory, RtioTTY}; use super::{Reader, Writer, io_error}; /// Creates a new non-blocking handle to the stdin of the current process. @@ -87,7 +87,7 @@ pub fn println_args(fmt: &fmt::Arguments) { /// Representation of a reader of a standard input stream pub struct StdReader { - priv inner: ~RtioTTYObject + priv inner: ~RtioTTY } impl StdReader { @@ -129,7 +129,7 @@ impl Reader for StdReader { /// Representation of a writer to a standard output stream pub struct StdWriter { - priv inner: ~RtioTTYObject + priv inner: ~RtioTTY } impl StdWriter { diff --git a/src/libstd/rt/io/timer.rs b/src/libstd/rt/io/timer.rs index b41d7541a6074..7d13e034dc1be 100644 --- a/src/libstd/rt/io/timer.rs +++ b/src/libstd/rt/io/timer.rs @@ -11,12 +11,11 @@ use option::{Option, Some, None}; use result::{Ok, Err}; use rt::io::{io_error}; -use rt::rtio::{IoFactory, IoFactoryObject, - RtioTimer, RtioTimerObject}; +use rt::rtio::{IoFactory, IoFactoryObject, RtioTimer}; use rt::local::Local; pub struct Timer { - priv obj: ~RtioTimerObject + priv obj: ~RtioTimer } /// Sleep the current task for `msecs` milliseconds. diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 9ea7b734d248c..66d7a6bf48823 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -279,7 +279,7 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int { rtdebug!("inserting a regular scheduler"); // Every scheduler is driven by an I/O event loop. - let loop_ = ~UvEventLoop::new(); + let loop_ = ~UvEventLoop::new() as ~rtio::EventLoop; let mut sched = ~Scheduler::new(loop_, work_queue.clone(), work_queues.clone(), @@ -303,7 +303,7 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int { // set. let work_queue = WorkQueue::new(); - let main_loop = ~UvEventLoop::new(); + let main_loop = ~UvEventLoop::new() as ~rtio::EventLoop; let mut main_sched = ~Scheduler::new_special(main_loop, work_queue, work_queues.clone(), diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index 3c513e263f167..ef695130e22ca 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -23,31 +23,18 @@ use super::io::support::PathLike; use super::io::{SeekStyle}; use super::io::{FileMode, FileAccess, FileStat}; -// XXX: ~object doesn't work currently so these are some placeholder -// types to use instead -pub type EventLoopObject = uvio::UvEventLoop; -pub type RemoteCallbackObject = uvio::UvRemoteCallback; -pub type IoFactoryObject = uvio::UvIoFactory; -pub type RtioTcpStreamObject = uvio::UvTcpStream; -pub type RtioTcpAcceptorObject = uvio::UvTcpAcceptor; +// FIXME(#9893) cannot call by-value self method on a trait object pub type RtioTcpListenerObject = uvio::UvTcpListener; -pub type RtioUdpSocketObject = uvio::UvUdpSocket; -pub type RtioTimerObject = uvio::UvTimer; -pub type PausibleIdleCallback = uvio::UvPausibleIdleCallback; -pub type RtioPipeObject = uvio::UvPipeStream; -pub type RtioProcessObject = uvio::UvProcess; pub type RtioUnixListenerObject = uvio::UvUnixListener; -pub type RtioUnixAcceptorObject = uvio::UvUnixAcceptor; -pub type RtioTTYObject = uvio::UvTTY; pub trait EventLoop { fn run(&mut self); fn callback(&mut self, ~fn()); fn pausible_idle_callback(&mut self) -> ~PausibleIdleCallback; fn callback_ms(&mut self, ms: u64, ~fn()); - fn remote_callback(&mut self, ~fn()) -> ~RemoteCallbackObject; + fn remote_callback(&mut self, ~fn()) -> ~RemoteCallback; /// The asynchronous I/O services. Not all event loops may provide one - fn io<'a>(&'a mut self) -> Option<&'a mut IoFactoryObject>; + fn io<'a>(&'a mut self) -> Option<&'a mut IoFactory>; } pub trait RemoteCallback { @@ -73,10 +60,10 @@ pub struct FileOpenConfig { } pub trait IoFactory { - fn tcp_connect(&mut self, addr: SocketAddr) -> Result<~RtioTcpStreamObject, IoError>; + fn tcp_connect(&mut self, addr: SocketAddr) -> Result<~RtioTcpStream, IoError>; fn tcp_bind(&mut self, addr: SocketAddr) -> Result<~RtioTcpListenerObject, IoError>; - fn udp_bind(&mut self, addr: SocketAddr) -> Result<~RtioUdpSocketObject, IoError>; - fn timer_init(&mut self) -> Result<~RtioTimerObject, IoError>; + fn udp_bind(&mut self, addr: SocketAddr) -> Result<~RtioUdpSocket, IoError>; + fn timer_init(&mut self) -> Result<~RtioTimer, IoError>; fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileStream; fn fs_open(&mut self, path: &P, fm: FileMode, fa: FileAccess) -> Result<~RtioFileStream, IoError>; @@ -89,22 +76,22 @@ pub trait IoFactory { fn fs_readdir(&mut self, path: &P, flags: c_int) -> Result<~[Path], IoError>; fn spawn(&mut self, config: ProcessConfig) - -> Result<(~RtioProcessObject, ~[Option<~RtioPipeObject>]), IoError>; + -> Result<(~RtioProcess, ~[Option<~RtioPipe>]), IoError>; fn unix_bind(&mut self, path: &P) -> Result<~RtioUnixListenerObject, IoError>; fn unix_connect(&mut self, path: &P) -> - Result<~RtioPipeObject, IoError>; + Result<~RtioPipe, IoError>; fn tty_open(&mut self, fd: c_int, readable: bool, close_on_drop: bool) - -> Result<~RtioTTYObject, IoError>; + -> Result<~RtioTTY, IoError>; } pub trait RtioTcpListener : RtioSocket { - fn listen(self) -> Result<~RtioTcpAcceptorObject, IoError>; + fn listen(self) -> Result<~RtioTcpAcceptor, IoError>; } pub trait RtioTcpAcceptor : RtioSocket { - fn accept(&mut self) -> Result<~RtioTcpStreamObject, IoError>; + fn accept(&mut self) -> Result<~RtioTcpStream, IoError>; fn accept_simultaneously(&mut self) -> Result<(), IoError>; fn dont_accept_simultaneously(&mut self) -> Result<(), IoError>; } @@ -166,11 +153,11 @@ pub trait RtioPipe { } pub trait RtioUnixListener { - fn listen(self) -> Result<~RtioUnixAcceptorObject, IoError>; + fn listen(self) -> Result<~RtioUnixAcceptor, IoError>; } pub trait RtioUnixAcceptor { - fn accept(&mut self) -> Result<~RtioPipeObject, IoError>; + fn accept(&mut self) -> Result<~RtioPipe, IoError>; fn accept_simultaneously(&mut self) -> Result<(), IoError>; fn dont_accept_simultaneously(&mut self) -> Result<(), IoError>; } @@ -182,3 +169,10 @@ pub trait RtioTTY { fn reset_mode(&mut self); fn get_winsize(&mut self) -> Result<(int, int), IoError>; } + +pub trait PausibleIdleCallback { + fn start(&mut self, f: ~fn()); + fn pause(&mut self); + fn resume(&mut self); + fn close(&mut self); +} diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs index ee163bab3c062..464e2b2c4c254 100644 --- a/src/libstd/rt/sched.rs +++ b/src/libstd/rt/sched.rs @@ -16,7 +16,7 @@ use unstable::raw; use super::sleeper_list::SleeperList; use super::work_queue::WorkQueue; use super::stack::{StackPool}; -use super::rtio::{EventLoop, EventLoopObject, RemoteCallbackObject}; +use super::rtio::EventLoop; use super::context::Context; use super::task::{Task, AnySched, Sched}; use super::message_queue::MessageQueue; @@ -63,7 +63,7 @@ pub struct Scheduler { no_sleep: bool, stack_pool: StackPool, /// The event loop used to drive the scheduler and perform I/O - event_loop: ~EventLoopObject, + event_loop: ~EventLoop, /// The scheduler runs on a special task. When it is not running /// it is stored here instead of the work queue. priv sched_task: Option<~Task>, @@ -107,7 +107,7 @@ impl Scheduler { // * Initialization Functions - pub fn new(event_loop: ~EventLoopObject, + pub fn new(event_loop: ~EventLoop, work_queue: WorkQueue<~Task>, work_queues: ~[WorkQueue<~Task>], sleeper_list: SleeperList) @@ -119,7 +119,7 @@ impl Scheduler { } - pub fn new_special(event_loop: ~EventLoopObject, + pub fn new_special(event_loop: ~EventLoop, work_queue: WorkQueue<~Task>, work_queues: ~[WorkQueue<~Task>], sleeper_list: SleeperList, @@ -227,7 +227,7 @@ impl Scheduler { // mutable reference to the event_loop to give it the "run" // command. unsafe { - let event_loop: *mut ~EventLoopObject = &mut self_sched.event_loop; + let event_loop: *mut ~EventLoop = &mut self_sched.event_loop; // Our scheduler must be in the task before the event loop // is started. @@ -793,7 +793,7 @@ pub enum SchedMessage { } pub struct SchedHandle { - priv remote: ~RemoteCallbackObject, + priv remote: ~RemoteCallback, priv queue: MessageQueue, sched_id: uint } diff --git a/src/libstd/rt/test.rs b/src/libstd/rt/test.rs index 759550e5cbd03..66d3f3de6ec23 100644 --- a/src/libstd/rt/test.rs +++ b/src/libstd/rt/test.rs @@ -22,6 +22,7 @@ use super::io::net::ip::{SocketAddr, Ipv4Addr, Ipv6Addr}; use vec::{OwnedVector, MutableVector, ImmutableVector}; use path::GenericPath; use rt::sched::Scheduler; +use rt::rtio::EventLoop; use unstable::{run_in_bare_thread}; use rt::thread::Thread; use rt::task::Task; @@ -36,7 +37,7 @@ pub fn new_test_uv_sched() -> Scheduler { let queue = WorkQueue::new(); let queues = ~[queue.clone()]; - let mut sched = Scheduler::new(~UvEventLoop::new(), + let mut sched = Scheduler::new(~UvEventLoop::new() as ~EventLoop, queue, queues, SleeperList::new()); @@ -195,7 +196,7 @@ pub fn run_in_mt_newsched_task(f: ~fn()) { } for i in range(0u, nthreads) { - let loop_ = ~UvEventLoop::new(); + let loop_ = ~UvEventLoop::new() as ~EventLoop; let mut sched = ~Scheduler::new(loop_, work_queues[i].clone(), work_queues.clone(), diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index f1a5916ee1389..00572d66573d2 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -215,11 +215,11 @@ impl EventLoop for UvEventLoop { fn pausible_idle_callback(&mut self) -> ~PausibleIdleCallback { let idle_watcher = IdleWatcher::new(self.uvio.uv_loop()); - return ~UvPausibleIdleCallback { + ~UvPausibleIdleCallback { watcher: idle_watcher, idle_flag: false, closed: false - }; + } as ~PausibleIdleCallback } fn callback_ms(&mut self, ms: u64, f: ~fn()) { @@ -231,12 +231,12 @@ impl EventLoop for UvEventLoop { } } - fn remote_callback(&mut self, f: ~fn()) -> ~RemoteCallbackObject { - ~UvRemoteCallback::new(self.uvio.uv_loop(), f) + fn remote_callback(&mut self, f: ~fn()) -> ~RemoteCallback{ + ~UvRemoteCallback::new(self.uvio.uv_loop(), f) as ~RemoteCallback } - fn io<'a>(&'a mut self) -> Option<&'a mut IoFactoryObject> { - Some(&mut self.uvio) + fn io<'a>(&'a mut self) -> Option<&'a mut IoFactory> { + Some(&mut self.uvio as &mut IoFactory) } } @@ -246,30 +246,30 @@ pub struct UvPausibleIdleCallback { priv closed: bool } -impl UvPausibleIdleCallback { +impl RtioPausibleIdleCallback for UvPausibleIdleCallback { #[inline] - pub fn start(&mut self, f: ~fn()) { + fn start(&mut self, f: ~fn()) { do self.watcher.start |_idle_watcher, _status| { f(); }; self.idle_flag = true; } #[inline] - pub fn pause(&mut self) { + fn pause(&mut self) { if self.idle_flag == true { self.watcher.stop(); self.idle_flag = false; } } #[inline] - pub fn resume(&mut self) { + fn resume(&mut self) { if self.idle_flag == false { self.watcher.restart(); self.idle_flag = true; } } #[inline] - pub fn close(&mut self) { + fn close(&mut self) { self.pause(); if !self.closed { self.closed = true; @@ -447,11 +447,11 @@ impl IoFactory for UvIoFactory { // Connect to an address and return a new stream // NB: This blocks the task waiting on the connection. // It would probably be better to return a future - fn tcp_connect(&mut self, addr: SocketAddr) -> Result<~RtioTcpStreamObject, IoError> { + fn tcp_connect(&mut self, addr: SocketAddr) -> Result<~RtioTcpStream, IoError> { // Create a cell in the task to hold the result. We will fill // the cell before resuming the task. let result_cell = Cell::new_empty(); - let result_cell_ptr: *Cell> = &result_cell; + let result_cell_ptr: *Cell> = &result_cell; // Block this task and take ownership, switch to scheduler context do task::unkillable { // FIXME(#8674) @@ -467,7 +467,8 @@ impl IoFactory for UvIoFactory { None => { let tcp = NativeHandle::from_native_handle(stream.native_handle()); let home = get_handle_to_current_scheduler!(); - let res = Ok(~UvTcpStream { watcher: tcp, home: home }); + let res = Ok(~UvTcpStream { watcher: tcp, home: home } + as ~RtioTcpStream); // Store the stream in the task's stack unsafe { (*result_cell_ptr).put_back(res); } @@ -517,12 +518,12 @@ impl IoFactory for UvIoFactory { } } - fn udp_bind(&mut self, addr: SocketAddr) -> Result<~RtioUdpSocketObject, IoError> { + fn udp_bind(&mut self, addr: SocketAddr) -> Result<~RtioUdpSocket, IoError> { let mut watcher = UdpWatcher::new(self.uv_loop()); match watcher.bind(addr) { Ok(_) => { let home = get_handle_to_current_scheduler!(); - Ok(~UvUdpSocket { watcher: watcher, home: home }) + Ok(~UvUdpSocket { watcher: watcher, home: home } as ~RtioUdpSocket) } Err(uverr) => { do task::unkillable { // FIXME(#8674) @@ -540,10 +541,10 @@ impl IoFactory for UvIoFactory { } } - fn timer_init(&mut self) -> Result<~RtioTimerObject, IoError> { + fn timer_init(&mut self) -> Result<~RtioTimer, IoError> { let watcher = TimerWatcher::new(self.uv_loop()); let home = get_handle_to_current_scheduler!(); - Ok(~UvTimer::new(watcher, home)) + Ok(~UvTimer::new(watcher, home) as ~RtioTimer) } fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileStream { @@ -750,7 +751,7 @@ impl IoFactory for UvIoFactory { } fn spawn(&mut self, config: ProcessConfig) - -> Result<(~RtioProcessObject, ~[Option<~RtioPipeObject>]), IoError> + -> Result<(~RtioProcess, ~[Option<~RtioPipe>]), IoError> { // Sadly, we must create the UvProcess before we actually call uv_spawn // so that the exit_cb can close over it and notify it when the process @@ -792,7 +793,8 @@ impl IoFactory for UvIoFactory { Ok(io) => { // Only now do we actually get a handle to this scheduler. ret.home = Some(get_handle_to_current_scheduler!()); - Ok((ret, io)) + Ok((ret as ~RtioProcess, + io.move_iter().map(|p| p.map(|p| p as ~RtioPipe)).collect())) } Err(uverr) => { // We still need to close the process handle we created, but @@ -827,12 +829,12 @@ impl IoFactory for UvIoFactory { } fn unix_connect(&mut self, path: &P) -> - Result<~RtioPipeObject, IoError> + Result<~RtioPipe, IoError> { let scheduler: ~Scheduler = Local::take(); let mut pipe = Pipe::new(self.uv_loop(), false); let result_cell = Cell::new_empty(); - let result_cell_ptr: *Cell> = &result_cell; + let result_cell_ptr: *Cell> = &result_cell; do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); @@ -845,7 +847,7 @@ impl IoFactory for UvIoFactory { handle as *uvll::uv_pipe_t); let home = get_handle_to_current_scheduler!(); let pipe = UvUnboundPipe::new(pipe, home); - Ok(~UvPipeStream::new(pipe)) + Ok(~UvPipeStream::new(pipe) as ~RtioPipe) } Some(e) => { Err(uv_error_to_io_error(e)) } }; @@ -871,13 +873,13 @@ impl IoFactory for UvIoFactory { } fn tty_open(&mut self, fd: c_int, readable: bool, close_on_drop: bool) - -> Result<~RtioTTYObject, IoError> { + -> Result<~RtioTTY, 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, - }), + } as ~RtioTTY), Err(e) => Err(uv_error_to_io_error(e)) } } @@ -921,7 +923,7 @@ impl RtioSocket for UvTcpListener { } impl RtioTcpListener for UvTcpListener { - fn listen(self) -> Result<~RtioTcpAcceptorObject, IoError> { + fn listen(self) -> Result<~RtioTcpAcceptor, IoError> { do self.home_for_io_consume |self_| { let acceptor = ~UvTcpAcceptor::new(self_); let incoming = Cell::new(acceptor.incoming.clone()); @@ -935,14 +937,15 @@ impl RtioTcpListener for UvTcpListener { // first accept call in the callback guarenteed to succeed server.accept(inc.as_stream()); let home = get_handle_to_current_scheduler!(); - Ok(~UvTcpStream { watcher: inc, home: home }) + Ok(~UvTcpStream { watcher: inc, home: home } + as ~RtioTcpStream) } }; incoming.send(inc); } }; match res { - Ok(()) => Ok(acceptor), + Ok(()) => Ok(acceptor as ~RtioTcpAcceptor), Err(e) => Err(uv_error_to_io_error(e)), } } @@ -951,7 +954,7 @@ impl RtioTcpListener for UvTcpListener { pub struct UvTcpAcceptor { priv listener: UvTcpListener, - priv incoming: Tube>, + priv incoming: Tube>, } impl HomingIO for UvTcpAcceptor { @@ -984,7 +987,7 @@ fn accept_simultaneously(stream: StreamWatcher, a: int) -> Result<(), IoError> { } impl RtioTcpAcceptor for UvTcpAcceptor { - fn accept(&mut self) -> Result<~RtioTcpStreamObject, IoError> { + fn accept(&mut self) -> Result<~RtioTcpStream, IoError> { do self.home_for_io |self_| { self_.incoming.recv() } @@ -1718,7 +1721,7 @@ impl UvUnixListener { } impl RtioUnixListener for UvUnixListener { - fn listen(self) -> Result<~RtioUnixAcceptorObject, IoError> { + fn listen(self) -> Result<~RtioUnixAcceptor, IoError> { do self.home_for_io_consume |self_| { let acceptor = ~UvUnixAcceptor::new(self_); let incoming = Cell::new(acceptor.incoming.clone()); @@ -1732,14 +1735,14 @@ impl RtioUnixListener for UvUnixListener { server.accept(inc.as_stream()); let home = get_handle_to_current_scheduler!(); let pipe = UvUnboundPipe::new(inc, home); - Ok(~UvPipeStream::new(pipe)) + Ok(~UvPipeStream::new(pipe) as ~RtioPipe) } }; incoming.send(inc); } }; match res { - Ok(()) => Ok(acceptor), + Ok(()) => Ok(acceptor as ~RtioUnixAcceptor), Err(e) => Err(uv_error_to_io_error(e)), } } @@ -1776,7 +1779,7 @@ impl Drop for UvTTY { pub struct UvUnixAcceptor { listener: UvUnixListener, - incoming: Tube>, + incoming: Tube>, } impl HomingIO for UvUnixAcceptor { @@ -1790,7 +1793,7 @@ impl UvUnixAcceptor { } impl RtioUnixAcceptor for UvUnixAcceptor { - fn accept(&mut self) -> Result<~RtioPipeObject, IoError> { + fn accept(&mut self) -> Result<~RtioPipe, IoError> { do self.home_for_io |self_| { self_.incoming.recv() } diff --git a/src/libstd/task/spawn.rs b/src/libstd/task/spawn.rs index dec13eded3983..fbe2988f77c71 100644 --- a/src/libstd/task/spawn.rs +++ b/src/libstd/task/spawn.rs @@ -89,7 +89,7 @@ use unstable::sync::Exclusive; use rt::in_green_task_context; use rt::local::Local; use rt::task::{Task, Sched}; -use rt::shouldnt_be_public::{Scheduler, KillHandle, WorkQueue, Thread}; +use rt::shouldnt_be_public::{Scheduler, KillHandle, WorkQueue, Thread, EventLoop}; use rt::uv::uvio::UvEventLoop; #[cfg(test)] use task::default_task_opts; @@ -607,7 +607,7 @@ pub fn spawn_raw(mut opts: TaskOpts, f: ~fn()) { let work_queue = WorkQueue::new(); // Create a new scheduler to hold the new task - let new_loop = ~UvEventLoop::new(); + let new_loop = ~UvEventLoop::new() as ~EventLoop; let mut new_sched = ~Scheduler::new_special(new_loop, work_queue, (*sched).work_queues.clone(), From 9110a38cbfd801983a838775c690c83e9189b4c3 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 16 Oct 2013 16:48:30 -0700 Subject: [PATCH 07/23] Remove rt::io::support This removes the PathLike trait associated with this "support module". This is yet another "container of bytes" trait, so I didn't want to duplicate what already exists throughout libstd. In actuality, we're going to pass of C strings to the libuv APIs, so instead the arguments are now bound with the 'ToCStr' trait instead. Additionally, a layer of complexity was removed by immediately converting these type-generic parameters into CStrings to get handed off to libuv apis. --- src/libstd/c_str.rs | 43 ++++++++++++++++++ src/libstd/os.rs | 7 ++- src/libstd/rt/io/file.rs | 45 +++++++++---------- src/libstd/rt/io/mod.rs | 4 -- src/libstd/rt/io/net/unix.rs | 6 +-- src/libstd/rt/io/support.rs | 42 ------------------ src/libstd/rt/rtio.rs | 13 +++--- src/libstd/rt/uv/file.rs | 84 ++++++++++++++---------------------- src/libstd/rt/uv/uvio.rs | 47 +++++++++----------- src/libstd/str.rs | 48 --------------------- 10 files changed, 131 insertions(+), 208 deletions(-) delete mode 100644 src/libstd/rt/io/support.rs diff --git a/src/libstd/c_str.rs b/src/libstd/c_str.rs index acfa02a4defd5..ba64a71553f6e 100644 --- a/src/libstd/c_str.rs +++ b/src/libstd/c_str.rs @@ -348,6 +348,34 @@ impl<'self> Iterator for CStringIterator<'self> { } } +/// Parses a C "multistring", eg windows env values or +/// the req->ptr result in a uv_fs_readdir() call. +/// +/// Optionally, a `count` can be passed in, limiting the +/// parsing to only being done `count`-times. +/// +/// The specified closure is invoked with each string that +/// is found, and the number of strings found is returned. +pub unsafe fn from_c_multistring(buf: *libc::c_char, + count: Option, + f: &fn(&CString)) -> uint { + + let mut curr_ptr: uint = buf as uint; + let mut ctr = 0; + let (limited_count, limit) = match count { + Some(limit) => (true, limit), + None => (false, 0) + }; + while ((limited_count && ctr < limit) || !limited_count) + && *(curr_ptr as *libc::c_char) != 0 as libc::c_char { + let cstr = CString::new(curr_ptr as *libc::c_char, false); + f(&cstr); + curr_ptr += cstr.len() + 1; + ctr += 1; + } + return ctr; +} + #[cfg(test)] mod tests { use super::*; @@ -355,6 +383,21 @@ mod tests { use ptr; use option::{Some, None}; + #[test] + fn test_str_multistring_parsing() { + unsafe { + let input = bytes!("zero", "\x00", "one", "\x00", "\x00"); + let ptr = vec::raw::to_ptr(input); + let expected = ["zero", "one"]; + let mut it = expected.iter(); + let result = do from_c_multistring(ptr as *libc::c_char, None) |c| { + assert_eq!(c.as_str(), expected.next().unwrap()); + }; + assert_eq!(result, 2); + assert!(it.next().is_none()); + } + } + #[test] fn test_str_to_c_str() { do "".to_c_str().with_ref |buf| { diff --git a/src/libstd/os.rs b/src/libstd/os.rs index ba2b42c9b9c8b..65190c5d8d623 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -62,7 +62,7 @@ pub fn close(fd: c_int) -> c_int { // which are for Windows and for non-Windows, if necessary. // See https://github.com/mozilla/rust/issues/9822 for more information. -pub mod rustrt { +mod rustrt { use libc::{c_char, c_int}; use libc; @@ -200,7 +200,10 @@ pub fn env() -> ~[(~str,~str)] { fail!("os::env() failure getting env string from OS: {}", os::last_os_error()); } - let result = str::raw::from_c_multistring(ch as *libc::c_char, None); + let mut result = ~[]; + do c_str::from_c_multistring(ch as *libc::c_char, None) |cstr| { + result.push(cstr.as_str().to_owned()); + }; FreeEnvironmentStringsA(ch); result } diff --git a/src/libstd/rt/io/file.rs b/src/libstd/rt/io/file.rs index a43bcd8142e18..cc39db4443153 100644 --- a/src/libstd/rt/io/file.rs +++ b/src/libstd/rt/io/file.rs @@ -15,7 +15,8 @@ with regular files & directories on a filesystem. At the top-level of the module are a set of freestanding functions, associated with various filesystem operations. They all operate -on a `PathLike` object. +on a `ToCStr` object. This trait is already defined for common +objects such as strings and `Path` instances. All operations in this module, including those as part of `FileStream` et al block the task during execution. Most will raise `std::rt::io::{io_error,read_error}` @@ -30,7 +31,7 @@ free function counterparts. */ use prelude::*; -use super::support::PathLike; +use c_str::ToCStr; use super::{Reader, Writer, Seek}; use super::{SeekStyle, Read, Write}; use rt::rtio::{RtioFileStream, IoFactory, IoFactoryObject}; @@ -48,7 +49,6 @@ use path::Path; /// /// use std; /// use std::path::Path; -/// use std::rt::io::support::PathLike; /// use std::rt::io::file::open; /// use std::rt::io::{FileMode, FileAccess}; /// @@ -87,13 +87,13 @@ use path::Path; /// * Attempting to open a file with a `FileAccess` that the user lacks permissions /// for /// * Filesystem-level errors (full disk, etc) -pub fn open(path: &P, - mode: FileMode, - access: FileAccess - ) -> Option { +pub fn open(path: &P, + mode: FileMode, + access: FileAccess + ) -> Option { let open_result = unsafe { let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).fs_open(path, mode, access) + (*io).fs_open(&path.to_c_str(), mode, access) }; match open_result { Ok(fd) => Some(FileStream { @@ -113,7 +113,6 @@ pub fn open(path: &P, /// /// use std; /// use std::path::Path; -/// use std::rt::io::support::PathLike; /// use std::rt::io::file::unlink; /// /// let p = &Path("/some/file/path.txt"); @@ -129,10 +128,10 @@ pub fn open(path: &P, /// /// This function will raise an `io_error` condition if the user lacks permissions to /// remove the file or if some other filesystem-level error occurs -pub fn unlink(path: &P) { +pub fn unlink(path: &P) { let unlink_result = unsafe { let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).fs_unlink(path) + (*io).fs_unlink(&path.to_c_str()) }; match unlink_result { Ok(_) => (), @@ -148,7 +147,6 @@ pub fn unlink(path: &P) { /// /// use std; /// use std::path::Path; -/// use std::rt::io::support::PathLike; /// use std::rt::io::file::mkdir; /// /// let p = &Path("/some/dir"); @@ -159,10 +157,10 @@ pub fn unlink(path: &P) { /// /// This call will raise an `io_error` condition if the user lacks permissions to make a /// new directory at the provided path, or if the directory already exists -pub fn mkdir(path: &P) { +pub fn mkdir(path: &P) { let mkdir_result = unsafe { let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).fs_mkdir(path) + (*io).fs_mkdir(&path.to_c_str()) }; match mkdir_result { Ok(_) => (), @@ -178,7 +176,6 @@ pub fn mkdir(path: &P) { /// /// use std; /// use std::path::Path; -/// use std::rt::io::support::PathLike; /// use std::rt::io::file::rmdir; /// /// let p = &Path("/some/dir"); @@ -189,10 +186,10 @@ pub fn mkdir(path: &P) { /// /// This call will raise an `io_error` condition if the user lacks permissions to remove the /// directory at the provided path, or if the directory isn't empty -pub fn rmdir(path: &P) { +pub fn rmdir(path: &P) { let rmdir_result = unsafe { let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).fs_rmdir(path) + (*io).fs_rmdir(&path.to_c_str()) }; match rmdir_result { Ok(_) => (), @@ -204,8 +201,8 @@ pub fn rmdir(path: &P) { /// Get information on the file, directory, etc at the provided path /// -/// Given a `rt::io::support::PathLike`, query the file system to get -/// information about a file, directory, etc. +/// Given a path, query the file system to get information about a file, +/// directory, etc. /// /// Returns a `Some(std::rt::io::PathInfo)` on success /// @@ -213,7 +210,6 @@ pub fn rmdir(path: &P) { /// /// use std; /// use std::path::Path; -/// use std::rt::io::support::PathLike; /// use std::rt::io::file::stat; /// /// let p = &Path("/some/file/path.txt"); @@ -238,10 +234,10 @@ pub fn rmdir(path: &P) { /// This call will raise an `io_error` condition if the user lacks the requisite /// permissions to perform a `stat` call on the given path or if there is no /// entry in the filesystem at the provided path. -pub fn stat(path: &P) -> Option { +pub fn stat(path: &P) -> Option { let open_result = unsafe { let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).fs_stat(path) + (*io).fs_stat(&path.to_c_str()) }; match open_result { Ok(p) => { @@ -260,7 +256,6 @@ pub fn stat(path: &P) -> Option { /// /// use std; /// use std::path::Path; -/// use std::rt::io::support::PathLike; /// use std::rt::io::file::readdir; /// /// fn visit_dirs(dir: &Path, cb: &fn(&Path)) { @@ -279,10 +274,10 @@ pub fn stat(path: &P) -> Option { /// Will raise an `io_error` condition if the provided `path` doesn't exist, /// the process lacks permissions to view the contents or if the `path` points /// at a non-directory file -pub fn readdir(path: &P) -> Option<~[Path]> { +pub fn readdir(path: &P) -> Option<~[Path]> { let readdir_result = unsafe { let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).fs_readdir(path, 0) + (*io).fs_readdir(&path.to_c_str(), 0) }; match readdir_result { Ok(p) => { diff --git a/src/libstd/rt/io/mod.rs b/src/libstd/rt/io/mod.rs index eaff43378f2ed..cb6361ff4e3c9 100644 --- a/src/libstd/rt/io/mod.rs +++ b/src/libstd/rt/io/mod.rs @@ -298,10 +298,6 @@ pub mod comm_adapters; /// Extension traits pub mod extensions; -/// Non-I/O things needed by the I/O module -// XXX: shouldn this really be pub? -pub mod support; - /// Basic Timer pub mod timer; diff --git a/src/libstd/rt/io/net/unix.rs b/src/libstd/rt/io/net/unix.rs index 1394cdb04a87c..fe045bff0507e 100644 --- a/src/libstd/rt/io/net/unix.rs +++ b/src/libstd/rt/io/net/unix.rs @@ -24,7 +24,7 @@ instances as clients. use prelude::*; -use super::super::support::PathLike; +use c_str::ToCStr; use rt::rtio::{IoFactory, IoFactoryObject, RtioUnixListener}; use rt::rtio::{RtioUnixAcceptor, RtioPipe, RtioUnixListenerObject}; use rt::io::pipe::PipeStream; @@ -59,7 +59,7 @@ impl UnixStream { /// let mut stream = UnixStream::connect(&server); /// stream.write([1, 2, 3]); /// - pub fn connect(path: &P) -> Option { + pub fn connect(path: &P) -> Option { let pipe = unsafe { let io: *mut IoFactoryObject = Local::unsafe_borrow(); (*io).unix_connect(path) @@ -112,7 +112,7 @@ impl UnixListener { /// client.write([1, 2, 3, 4]); /// } /// - pub fn bind(path: &P) -> Option { + pub fn bind(path: &P) -> Option { let listener = unsafe { let io: *mut IoFactoryObject = Local::unsafe_borrow(); (*io).unix_bind(path) diff --git a/src/libstd/rt/io/support.rs b/src/libstd/rt/io/support.rs deleted file mode 100644 index 31040bc51a135..0000000000000 --- a/src/libstd/rt/io/support.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use path::*; - -pub trait PathLike { - fn path_as_str(&self, f: &fn(&str) -> T) -> T; -} - -impl<'self> PathLike for &'self str { - fn path_as_str(&self, f: &fn(&str) -> T) -> T { - f(*self) - } -} - -impl PathLike for Path { - fn path_as_str(&self, f: &fn(&str) -> T) -> T { - let s = self.as_str().unwrap(); - f(s) - } -} - -#[cfg(test)] -mod test { - use path::*; - use super::PathLike; - - #[test] - fn path_like_smoke_test() { - let expected = if cfg!(unix) { "/home" } else { "C:\\" }; - let path = Path::new(expected); - path.path_as_str(|p| assert!(p == expected)); - path.path_as_str(|p| assert!(p == expected)); - } -} diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index ef695130e22ca..c889355f3531c 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -12,6 +12,7 @@ use libc; use option::*; use result::*; use libc::c_int; +use c_str::CString; use ai = rt::io::net::addrinfo; use rt::io::IoError; @@ -19,7 +20,6 @@ use super::io::process::ProcessConfig; use super::io::net::ip::{IpAddr, SocketAddr}; use rt::uv::uvio; use path::Path; -use super::io::support::PathLike; use super::io::{SeekStyle}; use super::io::{FileMode, FileAccess, FileStat}; @@ -65,15 +65,14 @@ pub trait IoFactory { fn udp_bind(&mut self, addr: SocketAddr) -> Result<~RtioUdpSocket, IoError>; fn timer_init(&mut self) -> Result<~RtioTimer, IoError>; fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileStream; - fn fs_open(&mut self, path: &P, fm: FileMode, fa: FileAccess) + fn fs_open(&mut self, path: &CString, fm: FileMode, fa: FileAccess) -> Result<~RtioFileStream, IoError>; - fn fs_unlink(&mut self, path: &P) -> Result<(), IoError>; fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>, hint: Option) -> Result<~[ai::Info], IoError>; - fn fs_stat(&mut self, path: &P) -> Result; - fn fs_mkdir(&mut self, path: &P) -> Result<(), IoError>; - fn fs_rmdir(&mut self, path: &P) -> Result<(), IoError>; - fn fs_readdir(&mut self, path: &P, flags: c_int) -> + fn fs_stat(&mut self, path: &CString) -> Result; + fn fs_mkdir(&mut self, path: &CString) -> Result<(), IoError>; + fn fs_rmdir(&mut self, path: &CString) -> Result<(), IoError>; + fn fs_readdir(&mut self, path: &CString, flags: c_int) -> Result<~[Path], IoError>; fn spawn(&mut self, config: ProcessConfig) -> Result<(~RtioProcess, ~[Option<~RtioPipe>]), IoError>; diff --git a/src/libstd/rt/uv/file.rs b/src/libstd/rt/uv/file.rs index 5d64ca4d755ce..07a22bc00e3a0 100644 --- a/src/libstd/rt/uv/file.rs +++ b/src/libstd/rt/uv/file.rs @@ -10,12 +10,13 @@ use prelude::*; use ptr::null; +use c_str; +use c_str::CString; use libc::c_void; use rt::uv::{Request, NativeHandle, Loop, FsCallback, Buf, status_to_maybe_uv_error, UvError}; use rt::uv::uvll; use rt::uv::uvll::*; -use super::super::io::support::PathLike; use cast::transmute; use libc; use libc::{c_int}; @@ -36,73 +37,63 @@ impl FsRequest { fs_req } - pub fn open(self, loop_: &Loop, path: &P, flags: int, mode: int, - cb: FsCallback) { + pub fn open(self, loop_: &Loop, path: &CString, flags: int, mode: int, + cb: FsCallback) { let complete_cb_ptr = { let mut me = self; me.req_boilerplate(Some(cb)) }; - path.path_as_str(|p| { - p.with_c_str(|p| unsafe { + path.with_ref(|p| unsafe { uvll::fs_open(loop_.native_handle(), self.native_handle(), p, flags, mode, complete_cb_ptr) - }) }); } - pub fn open_sync(self, loop_: &Loop, path: &P, - flags: int, mode: int) -> Result { + pub fn open_sync(self, loop_: &Loop, path: &CString, + flags: int, mode: int) -> Result { let complete_cb_ptr = { let mut me = self; me.req_boilerplate(None) }; - let result = path.path_as_str(|p| { - p.with_c_str(|p| unsafe { + let result = path.with_ref(|p| unsafe { uvll::fs_open(loop_.native_handle(), self.native_handle(), p, flags, mode, complete_cb_ptr) - }) }); self.sync_cleanup(result) } - pub fn unlink(self, loop_: &Loop, path: &P, cb: FsCallback) { + pub fn unlink(self, loop_: &Loop, path: &CString, cb: FsCallback) { let complete_cb_ptr = { let mut me = self; me.req_boilerplate(Some(cb)) }; - path.path_as_str(|p| { - p.with_c_str(|p| unsafe { - uvll::fs_unlink(loop_.native_handle(), - self.native_handle(), p, complete_cb_ptr) - }) + path.with_ref(|p| unsafe { + uvll::fs_unlink(loop_.native_handle(), + self.native_handle(), p, complete_cb_ptr) }); } - pub fn unlink_sync(self, loop_: &Loop, path: &P) + pub fn unlink_sync(self, loop_: &Loop, path: &CString) -> Result { let complete_cb_ptr = { let mut me = self; me.req_boilerplate(None) }; - let result = path.path_as_str(|p| { - p.with_c_str(|p| unsafe { - uvll::fs_unlink(loop_.native_handle(), - self.native_handle(), p, complete_cb_ptr) - }) + let result = path.with_ref(|p| unsafe { + uvll::fs_unlink(loop_.native_handle(), + self.native_handle(), p, complete_cb_ptr) }); self.sync_cleanup(result) } - pub fn stat(self, loop_: &Loop, path: &P, cb: FsCallback) { + pub fn stat(self, loop_: &Loop, path: &CString, cb: FsCallback) { let complete_cb_ptr = { let mut me = self; me.req_boilerplate(Some(cb)) }; - path.path_as_str(|p| { - p.with_c_str(|p| unsafe { - uvll::fs_stat(loop_.native_handle(), - self.native_handle(), p, complete_cb_ptr) - }) + path.with_ref(|p| unsafe { + uvll::fs_stat(loop_.native_handle(), + self.native_handle(), p, complete_cb_ptr) }); } @@ -186,43 +177,37 @@ impl FsRequest { self.sync_cleanup(result) } - pub fn mkdir(self, loop_: &Loop, path: &P, mode: int, cb: FsCallback) { + pub fn mkdir(self, loop_: &Loop, path: &CString, mode: int, cb: FsCallback) { let complete_cb_ptr = { let mut me = self; me.req_boilerplate(Some(cb)) }; - path.path_as_str(|p| { - p.with_c_str(|p| unsafe { + path.with_ref(|p| unsafe { uvll::fs_mkdir(loop_.native_handle(), self.native_handle(), p, mode, complete_cb_ptr) - }) }); } - pub fn rmdir(self, loop_: &Loop, path: &P, cb: FsCallback) { + pub fn rmdir(self, loop_: &Loop, path: &CString, cb: FsCallback) { let complete_cb_ptr = { let mut me = self; me.req_boilerplate(Some(cb)) }; - path.path_as_str(|p| { - p.with_c_str(|p| unsafe { + path.with_ref(|p| unsafe { uvll::fs_rmdir(loop_.native_handle(), self.native_handle(), p, complete_cb_ptr) - }) }); } - pub fn readdir(self, loop_: &Loop, path: &P, - flags: c_int, cb: FsCallback) { + pub fn readdir(self, loop_: &Loop, path: &CString, + flags: c_int, cb: FsCallback) { let complete_cb_ptr = { let mut me = self; me.req_boilerplate(Some(cb)) }; - path.path_as_str(|p| { - p.with_c_str(|p| unsafe { + path.with_ref(|p| unsafe { uvll::fs_readdir(loop_.native_handle(), self.native_handle(), p, flags, complete_cb_ptr) - }) }); } @@ -286,13 +271,11 @@ impl FsRequest { } } - pub fn get_paths(&mut self) -> ~[~str] { + pub fn each_path(&mut self, f: &fn(&CString)) { use str; let ptr = self.get_ptr(); match self.get_result() { - n if (n <= 0) => { - ~[] - }, + n if (n <= 0) => {} n => { let n_len = n as uint; // we pass in the len that uv tells us is there @@ -301,11 +284,10 @@ impl FsRequest { // correctly delimited and we stray into garbage memory? // in any case, passing Some(n_len) fixes it and ensures // good results - let raw_path_strs = unsafe { - str::raw::from_c_multistring(ptr as *libc::c_char, Some(n_len)) }; - let raw_len = raw_path_strs.len(); - assert_eq!(raw_len, n_len); - raw_path_strs + unsafe { + c_str::from_c_multistring(ptr as *libc::c_char, + Some(n_len), f); + } } } } diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 00572d66573d2..b0cdce7dd935d 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use c_str::ToCStr; +use c_str::{ToCStr, CString}; use cast::transmute; use cast; use cell::Cell; @@ -36,7 +36,6 @@ use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr}; use rt::uv::addrinfo::{GetAddrInfoRequest, accum_addrinfo}; use unstable::sync::Exclusive; use path::{GenericPath, Path}; -use super::super::io::support::PathLike; use libc::{lseek, off_t, O_CREAT, O_APPEND, O_TRUNC, O_RDWR, O_RDONLY, O_WRONLY, S_IRUSR, S_IWUSR, S_IRWXU}; use rt::io::{FileMode, FileAccess, OpenOrCreate, Open, Create, @@ -415,9 +414,9 @@ impl UvIoFactory { /// Helper for a variety of simple uv_fs_* functions that /// have no ret val -fn uv_fs_helper(loop_: &mut Loop, path: &P, - cb: ~fn(&mut FsRequest, &mut Loop, &P, - ~fn(&FsRequest, Option))) +fn uv_fs_helper(loop_: &mut Loop, path: &CString, + cb: ~fn(&mut FsRequest, &mut Loop, &CString, + ~fn(&FsRequest, Option))) -> Result<(), IoError> { let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell> = &result_cell; @@ -553,7 +552,7 @@ impl IoFactory for UvIoFactory { ~UvFileStream::new(loop_, fd, close_on_drop, home) as ~RtioFileStream } - fn fs_open(&mut self, path: &P, fm: FileMode, fa: FileAccess) + fn fs_open(&mut self, path: &CString, fm: FileMode, fa: FileAccess) -> Result<~RtioFileStream, IoError> { let mut flags = match fm { Open => 0, @@ -608,14 +607,14 @@ impl IoFactory for UvIoFactory { return result_cell.take(); } - fn fs_unlink(&mut self, path: &P) -> Result<(), IoError> { + fn fs_unlink(&mut self, path: &CString) -> Result<(), IoError> { do uv_fs_helper(self.uv_loop(), path) |unlink_req, l, p, cb| { do unlink_req.unlink(l, p) |req, err| { cb(req, err) }; } } - fn fs_stat(&mut self, path: &P) -> Result { + fn fs_stat(&mut self, path: &CString) -> Result { use str::StrSlice; let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell { let stat = req.get_stat(); Ok(FileStat { - path: Path::new(path_str.as_slice()), + path: path_instance.take(), is_file: stat.is_file(), is_dir: stat.is_dir(), device: stat.st_dev, @@ -694,7 +692,7 @@ impl IoFactory for UvIoFactory { assert!(!result_cell.is_empty()); return result_cell.take(); } - fn fs_mkdir(&mut self, path: &P) -> Result<(), IoError> { + fn fs_mkdir(&mut self, path: &CString) -> Result<(), IoError> { let mode = S_IRWXU as int; do uv_fs_helper(self.uv_loop(), path) |mkdir_req, l, p, cb| { do mkdir_req.mkdir(l, p, mode as int) |req, err| { @@ -702,14 +700,14 @@ impl IoFactory for UvIoFactory { }; } } - fn fs_rmdir(&mut self, path: &P) -> Result<(), IoError> { + fn fs_rmdir(&mut self, path: &CString) -> Result<(), IoError> { do uv_fs_helper(self.uv_loop(), path) |rmdir_req, l, p, cb| { do rmdir_req.rmdir(l, p) |req, err| { cb(req, err) }; } } - fn fs_readdir(&mut self, path: &P, flags: c_int) -> + fn fs_readdir(&mut self, path: &CString, flags: c_int) -> Result<~[Path], IoError> { use str::StrSlice; let result_cell = Cell::new_empty(); @@ -722,17 +720,14 @@ impl IoFactory for UvIoFactory { do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); let path = path_cell.take(); - let path_str = path.path_as_str(|p| p.to_owned()); - do stat_req.readdir(self.uv_loop(), path, flags) - |req,err| { + let path_parent = Cell::new(Path::new(path.as_bytes())); + do stat_req.readdir(self.uv_loop(), path, flags) |req,err| { + let parent = path_parent.take(); let res = match err { None => { - let rel_paths = req.get_paths(); let mut paths = ~[]; - for r in rel_paths.iter() { - let mut p = Path::new(path_str.as_slice()); - p.push(r.as_slice()); - paths.push(p); + do req.each_path |rel_path| { + paths.push(parent.join(rel_path.as_bytes())); } Ok(paths) }, @@ -2417,20 +2412,20 @@ fn file_test_uvio_full_simple_impl() { { let create_fm = Create; let create_fa = ReadWrite; - let mut fd = (*io).fs_open(&Path::new(path), create_fm, create_fa).unwrap(); + let mut fd = (*io).fs_open(&path.to_c_str(), create_fm, create_fa).unwrap(); let write_buf = write_val.as_bytes(); fd.write(write_buf); } { let ro_fm = Open; let ro_fa = Read; - let mut fd = (*io).fs_open(&Path::new(path), ro_fm, ro_fa).unwrap(); + let mut fd = (*io).fs_open(&path.to_c_str(), ro_fm, ro_fa).unwrap(); let mut read_vec = [0, .. 1028]; let nread = fd.read(read_vec).unwrap(); let read_val = str::from_utf8(read_vec.slice(0, nread as uint)); assert!(read_val == write_val.to_owned()); } - (*io).fs_unlink(&Path::new(path)); + (*io).fs_unlink(&path.to_c_str()); } } diff --git a/src/libstd/str.rs b/src/libstd/str.rs index f134788942cdb..3c89c12dbfa18 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -1172,34 +1172,6 @@ pub mod raw { vec::raw::set_len(as_owned_vec(s), new_len) } - /// Parses a C "multistring", eg windows env values or - /// the req->ptr result in a uv_fs_readdir() call. - /// Optionally, a `count` can be passed in, limiting the - /// parsing to only being done `count`-times. - #[inline] - pub unsafe fn from_c_multistring(buf: *libc::c_char, count: Option) -> ~[~str] { - #[fixed_stack_segment]; #[inline(never)]; - - let mut curr_ptr: uint = buf as uint; - let mut result = ~[]; - let mut ctr = 0; - let (limited_count, limit) = match count { - Some(limit) => (true, limit), - None => (false, 0) - }; - while(((limited_count && ctr < limit) || !limited_count) - && *(curr_ptr as *libc::c_char) != 0 as libc::c_char) { - let env_pair = from_c_str( - curr_ptr as *libc::c_char); - result.push(env_pair); - curr_ptr += - libc::strlen(curr_ptr as *libc::c_char) as uint - + 1; - ctr += 1; - } - result - } - /// Sets the length of a string /// /// This will explicitly set the size of the string, without actually @@ -1214,26 +1186,6 @@ pub mod raw { assert_eq!(c, ~"AAA"); } } - - #[test] - fn test_str_multistring_parsing() { - use option::None; - unsafe { - let input = bytes!("zero", "\x00", "one", "\x00", "\x00"); - let ptr = vec::raw::to_ptr(input); - let result = from_c_multistring(ptr as *libc::c_char, None); - assert!(result.len() == 2); - let mut ctr = 0; - for x in result.iter() { - match ctr { - 0 => assert_eq!(x, &~"zero"), - 1 => assert_eq!(x, &~"one"), - _ => fail!("shouldn't happen!") - } - ctr += 1; - } - } - } } /* From b46f60a72968bd62560c0230b2e5dc63f107f468 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 16 Oct 2013 17:05:28 -0700 Subject: [PATCH 08/23] Remove IoFactoryObject for ~IoFactory This involved changing a fair amount of code, rooted in how we access the local IoFactory instance. I added a helper method to the rtio module to access the optional local IoFactory. This is different than before in which it was assumed that a local IoFactory was *always* present. Now, a separate io_error is raised when an IoFactory is not present, yet I/O is requested. --- src/libstd/c_str.rs | 4 +- src/libstd/rt/io/file.rs | 114 ++++++++++------------ src/libstd/rt/io/mod.rs | 6 +- src/libstd/rt/io/net/addrinfo.rs | 22 ++--- src/libstd/rt/io/net/tcp.rs | 39 +++----- src/libstd/rt/io/net/udp.rs | 19 ++-- src/libstd/rt/io/net/unix.rs | 36 +++---- src/libstd/rt/io/process.rs | 31 +++--- src/libstd/rt/io/stdio.rs | 45 +++++---- src/libstd/rt/io/timer.rs | 28 +++--- src/libstd/rt/local.rs | 20 ---- src/libstd/rt/rtio.rs | 33 +++++-- src/libstd/rt/sched.rs | 7 +- src/libstd/rt/test.rs | 4 +- src/libstd/rt/uv/file.rs | 52 +++++----- src/libstd/rt/uv/uvio.rs | 157 ++++++++++++++++--------------- src/libstd/str.rs | 1 - 17 files changed, 303 insertions(+), 315 deletions(-) diff --git a/src/libstd/c_str.rs b/src/libstd/c_str.rs index ba64a71553f6e..b2e68c8d20fa7 100644 --- a/src/libstd/c_str.rs +++ b/src/libstd/c_str.rs @@ -382,6 +382,7 @@ mod tests { use libc; use ptr; use option::{Some, None}; + use vec; #[test] fn test_str_multistring_parsing() { @@ -391,7 +392,8 @@ mod tests { let expected = ["zero", "one"]; let mut it = expected.iter(); let result = do from_c_multistring(ptr as *libc::c_char, None) |c| { - assert_eq!(c.as_str(), expected.next().unwrap()); + let cbytes = c.as_bytes().slice_to(c.len()); + assert_eq!(cbytes, it.next().unwrap().as_bytes()); }; assert_eq!(result, 2); assert!(it.next().is_none()); diff --git a/src/libstd/rt/io/file.rs b/src/libstd/rt/io/file.rs index cc39db4443153..0bd0213b5b06e 100644 --- a/src/libstd/rt/io/file.rs +++ b/src/libstd/rt/io/file.rs @@ -34,12 +34,11 @@ use prelude::*; use c_str::ToCStr; use super::{Reader, Writer, Seek}; use super::{SeekStyle, Read, Write}; -use rt::rtio::{RtioFileStream, IoFactory, IoFactoryObject}; +use rt::rtio::{RtioFileStream, IoFactory, with_local_io}; use rt::io::{io_error, read_error, EndOfFile, FileMode, FileAccess, FileStat, IoError, PathAlreadyExists, PathDoesntExist, MismatchedFileTypeForOperation, ignore_io_error}; -use rt::local::Local; use option::{Some, None}; use path::Path; @@ -90,19 +89,17 @@ use path::Path; pub fn open(path: &P, mode: FileMode, access: FileAccess - ) -> Option { - let open_result = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).fs_open(&path.to_c_str(), mode, access) - }; - match open_result { - Ok(fd) => Some(FileStream { - fd: fd, - last_nread: -1 - }), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None + ) -> Option { + do with_local_io |io| { + match io.fs_open(&path.to_c_str(), mode, access) { + Ok(fd) => Some(FileStream { + fd: fd, + last_nread: -1 + }), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } } } } @@ -129,16 +126,15 @@ pub fn open(path: &P, /// This function will raise an `io_error` condition if the user lacks permissions to /// remove the file or if some other filesystem-level error occurs pub fn unlink(path: &P) { - let unlink_result = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).fs_unlink(&path.to_c_str()) - }; - match unlink_result { - Ok(_) => (), - Err(ioerr) => { - io_error::cond.raise(ioerr); + do with_local_io |io| { + match io.fs_unlink(&path.to_c_str()) { + Ok(_) => Some(()), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } } - } + }; } /// Create a new, empty directory at the provided path @@ -158,16 +154,15 @@ pub fn unlink(path: &P) { /// This call will raise an `io_error` condition if the user lacks permissions to make a /// new directory at the provided path, or if the directory already exists pub fn mkdir(path: &P) { - let mkdir_result = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).fs_mkdir(&path.to_c_str()) - }; - match mkdir_result { - Ok(_) => (), - Err(ioerr) => { - io_error::cond.raise(ioerr); + do with_local_io |io| { + match io.fs_mkdir(&path.to_c_str()) { + Ok(_) => Some(()), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } } - } + }; } /// Remove an existing, empty directory @@ -187,16 +182,15 @@ pub fn mkdir(path: &P) { /// This call will raise an `io_error` condition if the user lacks permissions to remove the /// directory at the provided path, or if the directory isn't empty pub fn rmdir(path: &P) { - let rmdir_result = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).fs_rmdir(&path.to_c_str()) - }; - match rmdir_result { - Ok(_) => (), - Err(ioerr) => { - io_error::cond.raise(ioerr); + do with_local_io |io| { + match io.fs_rmdir(&path.to_c_str()) { + Ok(_) => Some(()), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } } - } + }; } /// Get information on the file, directory, etc at the provided path @@ -235,17 +229,13 @@ pub fn rmdir(path: &P) { /// permissions to perform a `stat` call on the given path or if there is no /// entry in the filesystem at the provided path. pub fn stat(path: &P) -> Option { - let open_result = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).fs_stat(&path.to_c_str()) - }; - match open_result { - Ok(p) => { - Some(p) - }, - Err(ioerr) => { - io_error::cond.raise(ioerr); - None + do with_local_io |io| { + match io.fs_stat(&path.to_c_str()) { + Ok(p) => Some(p), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } } } } @@ -275,17 +265,13 @@ pub fn stat(path: &P) -> Option { /// the process lacks permissions to view the contents or if the `path` points /// at a non-directory file pub fn readdir(path: &P) -> Option<~[Path]> { - let readdir_result = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).fs_readdir(&path.to_c_str(), 0) - }; - match readdir_result { - Ok(p) => { - Some(p) - }, - Err(ioerr) => { - io_error::cond.raise(ioerr); - None + do with_local_io |io| { + match io.fs_readdir(&path.to_c_str(), 0) { + Ok(p) => Some(p), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } } } } diff --git a/src/libstd/rt/io/mod.rs b/src/libstd/rt/io/mod.rs index cb6361ff4e3c9..1a5c197fd5271 100644 --- a/src/libstd/rt/io/mod.rs +++ b/src/libstd/rt/io/mod.rs @@ -369,7 +369,8 @@ pub enum IoErrorKind { BrokenPipe, PathAlreadyExists, PathDoesntExist, - MismatchedFileTypeForOperation + MismatchedFileTypeForOperation, + IoUnavailable, } // FIXME: #8242 implementing manually because deriving doesn't work for some reason @@ -389,7 +390,8 @@ impl ToStr for IoErrorKind { BrokenPipe => ~"BrokenPipe", PathAlreadyExists => ~"PathAlreadyExists", PathDoesntExist => ~"PathDoesntExist", - MismatchedFileTypeForOperation => ~"MismatchedFileTypeForOperation" + MismatchedFileTypeForOperation => ~"MismatchedFileTypeForOperation", + IoUnavailable => ~"IoUnavailable", } } } diff --git a/src/libstd/rt/io/net/addrinfo.rs b/src/libstd/rt/io/net/addrinfo.rs index ae0d542acbe47..e0c92730cd905 100644 --- a/src/libstd/rt/io/net/addrinfo.rs +++ b/src/libstd/rt/io/net/addrinfo.rs @@ -19,10 +19,9 @@ getaddrinfo() use option::{Option, Some, None}; use result::{Ok, Err}; -use rt::io::io_error; +use rt::io::{io_error}; use rt::io::net::ip::{SocketAddr, IpAddr}; -use rt::rtio::{IoFactory, IoFactoryObject}; -use rt::local::Local; +use rt::rtio::{IoFactory, with_local_io}; /// Hints to the types of sockets that are desired when looking up hosts pub enum SocketType { @@ -94,16 +93,13 @@ pub fn get_host_addresses(host: &str) -> Option<~[IpAddr]> { /// On failure, this will raise on the `io_error` condition. pub fn lookup(hostname: Option<&str>, servname: Option<&str>, hint: Option) -> Option<~[Info]> { - let ipaddrs = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).get_host_addresses(hostname, servname, hint) - }; - - match ipaddrs { - Ok(i) => Some(i), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None + do with_local_io |io| { + match io.get_host_addresses(hostname, servname, hint) { + Ok(i) => Some(i), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } } } } diff --git a/src/libstd/rt/io/net/tcp.rs b/src/libstd/rt/io/net/tcp.rs index 946ecbea6f778..bafde180d5c9e 100644 --- a/src/libstd/rt/io/net/tcp.rs +++ b/src/libstd/rt/io/net/tcp.rs @@ -13,9 +13,8 @@ use result::{Ok, Err}; use rt::io::net::ip::SocketAddr; use rt::io::{Reader, Writer, Listener, Acceptor}; use rt::io::{io_error, read_error, EndOfFile}; -use rt::rtio::{IoFactory, IoFactoryObject, RtioTcpListenerObject, +use rt::rtio::{IoFactory, RtioTcpListenerObject, with_local_io, RtioSocket, RtioTcpListener, RtioTcpAcceptor, RtioTcpStream}; -use rt::local::Local; pub struct TcpStream { priv obj: ~RtioTcpStream @@ -27,19 +26,13 @@ impl TcpStream { } pub fn connect(addr: SocketAddr) -> Option { - let stream = unsafe { - rtdebug!("borrowing io to connect"); - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - rtdebug!("about to connect"); - (*io).tcp_connect(addr) - }; - - match stream { - Ok(s) => Some(TcpStream::new(s)), - Err(ioerr) => { - rtdebug!("failed to connect: {:?}", ioerr); - io_error::cond.raise(ioerr); - None + do with_local_io |io| { + match io.tcp_connect(addr) { + Ok(s) => Some(TcpStream::new(s)), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } } } } @@ -101,15 +94,13 @@ pub struct TcpListener { impl TcpListener { pub fn bind(addr: SocketAddr) -> Option { - let listener = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).tcp_bind(addr) - }; - match listener { - Ok(l) => Some(TcpListener { obj: l }), - Err(ioerr) => { - io_error::cond.raise(ioerr); - return None; + do with_local_io |io| { + match io.tcp_bind(addr) { + Ok(l) => Some(TcpListener { obj: l }), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } } } } diff --git a/src/libstd/rt/io/net/udp.rs b/src/libstd/rt/io/net/udp.rs index ed01dc9dcdaa5..eee5dce7b6c68 100644 --- a/src/libstd/rt/io/net/udp.rs +++ b/src/libstd/rt/io/net/udp.rs @@ -13,8 +13,7 @@ use result::{Ok, Err}; use rt::io::net::ip::SocketAddr; use rt::io::{Reader, Writer}; use rt::io::{io_error, read_error, EndOfFile}; -use rt::rtio::{RtioSocket, RtioUdpSocket, IoFactory, IoFactoryObject}; -use rt::local::Local; +use rt::rtio::{RtioSocket, RtioUdpSocket, IoFactory, with_local_io}; pub struct UdpSocket { priv obj: ~RtioUdpSocket @@ -22,15 +21,13 @@ pub struct UdpSocket { impl UdpSocket { pub fn bind(addr: SocketAddr) -> Option { - let socket = unsafe { - let factory: *mut IoFactoryObject = Local::unsafe_borrow(); - (*factory).udp_bind(addr) - }; - match socket { - Ok(s) => Some(UdpSocket { obj: s }), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None + do with_local_io |io| { + match io.udp_bind(addr) { + Ok(s) => Some(UdpSocket { obj: s }), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } } } } diff --git a/src/libstd/rt/io/net/unix.rs b/src/libstd/rt/io/net/unix.rs index fe045bff0507e..b98d5b52cb2bf 100644 --- a/src/libstd/rt/io/net/unix.rs +++ b/src/libstd/rt/io/net/unix.rs @@ -25,11 +25,10 @@ instances as clients. use prelude::*; use c_str::ToCStr; -use rt::rtio::{IoFactory, IoFactoryObject, RtioUnixListener}; +use rt::rtio::{IoFactory, RtioUnixListener, with_local_io}; use rt::rtio::{RtioUnixAcceptor, RtioPipe, RtioUnixListenerObject}; use rt::io::pipe::PipeStream; use rt::io::{io_error, Listener, Acceptor, Reader, Writer}; -use rt::local::Local; /// A stream which communicates over a named pipe. pub struct UnixStream { @@ -60,16 +59,13 @@ impl UnixStream { /// stream.write([1, 2, 3]); /// pub fn connect(path: &P) -> Option { - let pipe = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).unix_connect(path) - }; - - match pipe { - Ok(s) => Some(UnixStream::new(s)), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None + do with_local_io |io| { + match io.unix_connect(&path.to_c_str()) { + Ok(s) => Some(UnixStream::new(s)), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } } } } @@ -113,15 +109,13 @@ impl UnixListener { /// } /// pub fn bind(path: &P) -> Option { - let listener = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).unix_bind(path) - }; - match listener { - Ok(s) => Some(UnixListener{ obj: s }), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None + do with_local_io |io| { + match io.unix_bind(&path.to_c_str()) { + Ok(s) => Some(UnixListener{ obj: s }), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } } } } diff --git a/src/libstd/rt/io/process.rs b/src/libstd/rt/io/process.rs index c13b275ae52bf..c45429ca2e6cd 100644 --- a/src/libstd/rt/io/process.rs +++ b/src/libstd/rt/io/process.rs @@ -11,12 +11,12 @@ //! Bindings for executing child processes use prelude::*; +use cell::Cell; use libc; use rt::io; use rt::io::io_error; -use rt::local::Local; -use rt::rtio::{RtioProcess, IoFactoryObject, IoFactory}; +use rt::rtio::{RtioProcess, IoFactory, with_local_io}; // windows values don't matter as long as they're at least one of unix's // TERM/KILL/INT signals @@ -83,20 +83,19 @@ impl Process { /// Creates a new pipe initialized, but not bound to any particular /// source/destination pub fn new(config: ProcessConfig) -> Option { - let process = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).spawn(config) - }; - match process { - Ok((p, io)) => Some(Process{ - handle: p, - io: io.move_iter().map(|p| - p.map(|p| io::PipeStream::new_bound(p)) - ).collect() - }), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None + let config = Cell::new(config); + do with_local_io |io| { + match io.spawn(config.take()) { + Ok((p, io)) => Some(Process{ + handle: p, + io: io.move_iter().map(|p| + p.map(|p| io::PipeStream::new_bound(p)) + ).collect() + }), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } } } } diff --git a/src/libstd/rt/io/stdio.rs b/src/libstd/rt/io/stdio.rs index 77ac87830e253..a3cbe87431de0 100644 --- a/src/libstd/rt/io/stdio.rs +++ b/src/libstd/rt/io/stdio.rs @@ -12,19 +12,22 @@ use fmt; use libc; use option::{Option, Some, None}; use result::{Ok, Err}; -use rt::local::Local; -use rt::rtio::{IoFactoryObject, IoFactory, RtioTTY}; +use rt::rtio::{IoFactory, RtioTTY, with_local_io}; use super::{Reader, Writer, io_error}; /// Creates a new non-blocking handle to the stdin of the current process. /// /// See `stdout()` for notes about this function. pub fn stdin() -> StdReader { - let stream = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).tty_open(libc::STDIN_FILENO, true, false) - }.unwrap(); - StdReader { inner: stream } + do with_local_io |io| { + match io.tty_open(libc::STDIN_FILENO, true, false) { + Ok(tty) => Some(StdReader { inner: tty }), + Err(e) => { + io_error::cond.raise(e); + None + } + } + }.unwrap() } /// Creates a new non-blocking handle to the stdout of the current process. @@ -34,22 +37,30 @@ pub fn stdin() -> StdReader { /// task context because the stream returned will be a non-blocking object using /// the local scheduler to perform the I/O. pub fn stdout() -> StdWriter { - let stream = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).tty_open(libc::STDOUT_FILENO, false, false) - }.unwrap(); - StdWriter { inner: stream } + do with_local_io |io| { + match io.tty_open(libc::STDOUT_FILENO, false, false) { + Ok(tty) => Some(StdWriter { inner: tty }), + Err(e) => { + io_error::cond.raise(e); + None + } + } + }.unwrap() } /// Creates a new non-blocking handle to the stderr of the current process. /// /// See `stdout()` for notes about this function. pub fn stderr() -> StdWriter { - let stream = unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - (*io).tty_open(libc::STDERR_FILENO, false, false) - }.unwrap(); - StdWriter { inner: stream } + do with_local_io |io| { + match io.tty_open(libc::STDERR_FILENO, false, false) { + Ok(tty) => Some(StdWriter { inner: tty }), + Err(e) => { + io_error::cond.raise(e); + None + } + } + }.unwrap() } /// Prints a string to the stdout of the current process. No newline is emitted diff --git a/src/libstd/rt/io/timer.rs b/src/libstd/rt/io/timer.rs index 7d13e034dc1be..fab0062ee0054 100644 --- a/src/libstd/rt/io/timer.rs +++ b/src/libstd/rt/io/timer.rs @@ -10,9 +10,8 @@ use option::{Option, Some, None}; use result::{Ok, Err}; -use rt::io::{io_error}; -use rt::rtio::{IoFactory, IoFactoryObject, RtioTimer}; -use rt::local::Local; +use rt::io::io_error; +use rt::rtio::{IoFactory, RtioTimer, with_local_io}; pub struct Timer { priv obj: ~RtioTimer @@ -27,20 +26,19 @@ pub fn sleep(msecs: u64) { impl Timer { + /// Creates a new timer which can be used to put the current task to sleep + /// for a number of milliseconds. pub fn new() -> Option { - let timer = unsafe { - rtdebug!("Timer::init: borrowing io to init timer"); - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - rtdebug!("about to init timer"); - (*io).timer_init() - }; - match timer { - Ok(t) => Some(Timer { obj: t }), - Err(ioerr) => { - rtdebug!("Timer::init: failed to init: {:?}", ioerr); - io_error::cond.raise(ioerr); - None + do with_local_io |io| { + match io.timer_init() { + Ok(t) => Some(Timer { obj: t }), + Err(ioerr) => { + rtdebug!("Timer::init: failed to init: {:?}", ioerr); + io_error::cond.raise(ioerr); + None + } } + } } diff --git a/src/libstd/rt/local.rs b/src/libstd/rt/local.rs index d4f31879c003a..1ddc2f86f4bc4 100644 --- a/src/libstd/rt/local.rs +++ b/src/libstd/rt/local.rs @@ -12,8 +12,6 @@ use option::{Option, Some, None}; use rt::sched::Scheduler; use rt::task::Task; use rt::local_ptr; -use rt::rtio::{EventLoop, IoFactoryObject}; -//use borrow::to_uint; use cell::Cell; pub trait Local { @@ -122,24 +120,6 @@ impl Local for Scheduler { } } -// XXX: This formulation won't work once ~IoFactoryObject is a real trait pointer -impl Local for IoFactoryObject { - fn put(_value: ~IoFactoryObject) { rtabort!("unimpl") } - fn take() -> ~IoFactoryObject { rtabort!("unimpl") } - fn exists(_: Option) -> bool { rtabort!("unimpl") } - fn borrow(_f: &fn(&mut IoFactoryObject) -> T) -> T { rtabort!("unimpl") } - unsafe fn unsafe_take() -> ~IoFactoryObject { rtabort!("unimpl") } - unsafe fn unsafe_borrow() -> *mut IoFactoryObject { - let sched: *mut Scheduler = Local::unsafe_borrow(); - let io: *mut IoFactoryObject = (*sched).event_loop.io().unwrap(); - return io; - } - unsafe fn try_unsafe_borrow() -> Option<*mut IoFactoryObject> { - rtabort!("unimpl") - } -} - - #[cfg(test)] mod test { use option::None; diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index c889355f3531c..897bf328f2367 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -33,8 +33,10 @@ pub trait EventLoop { fn pausible_idle_callback(&mut self) -> ~PausibleIdleCallback; fn callback_ms(&mut self, ms: u64, ~fn()); fn remote_callback(&mut self, ~fn()) -> ~RemoteCallback; + /// The asynchronous I/O services. Not all event loops may provide one - fn io<'a>(&'a mut self) -> Option<&'a mut IoFactory>; + // FIXME(#9382) this is an awful interface + fn io<'a>(&'a mut self, f: &fn(&'a mut IoFactory)); } pub trait RemoteCallback { @@ -59,16 +61,36 @@ pub struct FileOpenConfig { priv mode: int } +pub fn with_local_io(f: &fn(&mut IoFactory) -> Option) -> Option { + use rt::sched::Scheduler; + use rt::local::Local; + use rt::io::{io_error, standard_error, IoUnavailable}; + + unsafe { + let sched: *mut Scheduler = Local::unsafe_borrow(); + let mut io = None; + (*sched).event_loop.io(|i| io = Some(i)); + match io { + Some(io) => f(io), + None => { + io_error::cond.raise(standard_error(IoUnavailable)); + None + } + } + } +} + pub trait IoFactory { fn tcp_connect(&mut self, addr: SocketAddr) -> Result<~RtioTcpStream, IoError>; fn tcp_bind(&mut self, addr: SocketAddr) -> Result<~RtioTcpListenerObject, IoError>; fn udp_bind(&mut self, addr: SocketAddr) -> Result<~RtioUdpSocket, IoError>; + fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>, + hint: Option) -> Result<~[ai::Info], IoError>; fn timer_init(&mut self) -> Result<~RtioTimer, IoError>; fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileStream; fn fs_open(&mut self, path: &CString, fm: FileMode, fa: FileAccess) -> Result<~RtioFileStream, IoError>; - fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>, - hint: Option) -> Result<~[ai::Info], IoError>; + fn fs_unlink(&mut self, path: &CString) -> Result<(), IoError>; fn fs_stat(&mut self, path: &CString) -> Result; fn fs_mkdir(&mut self, path: &CString) -> Result<(), IoError>; fn fs_rmdir(&mut self, path: &CString) -> Result<(), IoError>; @@ -77,10 +99,9 @@ pub trait IoFactory { fn spawn(&mut self, config: ProcessConfig) -> Result<(~RtioProcess, ~[Option<~RtioPipe>]), IoError>; - fn unix_bind(&mut self, path: &P) -> + fn unix_bind(&mut self, path: &CString) -> Result<~RtioUnixListenerObject, IoError>; - fn unix_connect(&mut self, path: &P) -> - Result<~RtioPipe, IoError>; + fn unix_connect(&mut self, path: &CString) -> Result<~RtioPipe, IoError>; fn tty_open(&mut self, fd: c_int, readable: bool, close_on_drop: bool) -> Result<~RtioTTY, IoError>; } diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs index 464e2b2c4c254..6e66188461617 100644 --- a/src/libstd/rt/sched.rs +++ b/src/libstd/rt/sched.rs @@ -905,6 +905,7 @@ mod test { use cell::Cell; use rt::thread::Thread; use rt::task::{Task, Sched}; + use rt::rtio::EventLoop; use rt::util; use option::{Some}; @@ -1020,7 +1021,7 @@ mod test { // Our normal scheduler let mut normal_sched = ~Scheduler::new( - ~UvEventLoop::new(), + ~UvEventLoop::new() as ~EventLoop, normal_queue, queues.clone(), sleepers.clone()); @@ -1031,7 +1032,7 @@ mod test { // Our special scheduler let mut special_sched = ~Scheduler::new_special( - ~UvEventLoop::new(), + ~UvEventLoop::new() as ~EventLoop, special_queue.clone(), queues.clone(), sleepers.clone(), @@ -1202,7 +1203,7 @@ mod test { let queues = ~[queue.clone()]; let mut sched = ~Scheduler::new( - ~UvEventLoop::new(), + ~UvEventLoop::new() as ~EventLoop, queue, queues.clone(), sleepers.clone()); diff --git a/src/libstd/rt/test.rs b/src/libstd/rt/test.rs index 66d3f3de6ec23..c238b1dfba16a 100644 --- a/src/libstd/rt/test.rs +++ b/src/libstd/rt/test.rs @@ -13,7 +13,7 @@ use rand::Rng; use os; use libc; use option::{Some, None}; -use path::{Path, GenericPath}; +use path::Path; use cell::Cell; use clone::Clone; use container::Container; @@ -335,7 +335,7 @@ pub fn next_test_port() -> u16 { /// Get a temporary path which could be the location of a unix socket #[fixed_stack_segment] #[inline(never)] pub fn next_test_unix() -> Path { - os::tmpdir().push(rand::task_rng().gen_ascii_str(20)) + os::tmpdir().join(rand::task_rng().gen_ascii_str(20)) } /// Get a unique IPv4 localhost:port pair starting at 9600 diff --git a/src/libstd/rt/uv/file.rs b/src/libstd/rt/uv/file.rs index 07a22bc00e3a0..78b3a88f5f1ba 100644 --- a/src/libstd/rt/uv/file.rs +++ b/src/libstd/rt/uv/file.rs @@ -272,7 +272,6 @@ impl FsRequest { } pub fn each_path(&mut self, f: &fn(&CString)) { - use str; let ptr = self.get_ptr(); match self.get_result() { n if (n <= 0) => {} @@ -350,7 +349,6 @@ mod test { use vec; use str; use unstable::run_in_bare_thread; - use path::Path; use rt::uv::{Loop, Buf, slice_to_uv_buf}; use libc::{O_CREAT, O_RDWR, O_RDONLY, S_IWUSR, S_IRUSR}; @@ -373,10 +371,9 @@ mod test { let read_mem = vec::from_elem(read_buf_len, 0u8); let read_buf = slice_to_uv_buf(read_mem); let read_buf_ptr: *Buf = &read_buf; - let p = Path::new(path_str); let open_req = FsRequest::new(); - do open_req.open(&loop_, &p, create_flags as int, mode as int) - |req, uverr| { + do open_req.open(&loop_, &path_str.to_c_str(), create_flags as int, + mode as int) |req, uverr| { assert!(uverr.is_none()); let fd = req.get_result(); let buf = unsafe { *write_buf_ptr }; @@ -387,8 +384,8 @@ mod test { assert!(uverr.is_none()); let loop_ = req.get_loop(); let open_req = FsRequest::new(); - do open_req.open(&loop_, &Path::new(path_str), read_flags as int,0) - |req, uverr| { + do open_req.open(&loop_, &path_str.to_c_str(), + read_flags as int,0) |req, uverr| { assert!(uverr.is_none()); let loop_ = req.get_loop(); let fd = req.get_result(); @@ -413,7 +410,8 @@ mod test { assert!(uverr.is_none()); let loop_ = &req.get_loop(); let unlink_req = FsRequest::new(); - do unlink_req.unlink(loop_, &Path::new(path_str)) + do unlink_req.unlink(loop_, + &path_str.to_c_str()) |_,uverr| { assert!(uverr.is_none()); }; @@ -447,8 +445,8 @@ mod test { let write_buf = slice_to_uv_buf(write_val); // open/create let open_req = FsRequest::new(); - let result = open_req.open_sync(&loop_, &Path::new(path_str), - create_flags as int, mode as int); + let result = open_req.open_sync(&loop_, &path_str.to_c_str(), + create_flags as int, mode as int); assert!(result.is_ok()); let fd = result.unwrap(); // write @@ -461,7 +459,7 @@ mod test { assert!(result.is_ok()); // re-open let open_req = FsRequest::new(); - let result = open_req.open_sync(&loop_, &Path::new(path_str), + let result = open_req.open_sync(&loop_, &path_str.to_c_str(), read_flags as int,0); assert!(result.is_ok()); let len = 1028; @@ -485,7 +483,7 @@ mod test { assert!(result.is_ok()); // unlink let unlink_req = FsRequest::new(); - let result = unlink_req.unlink_sync(&loop_, &Path::new(path_str)); + let result = unlink_req.unlink_sync(&loop_, &path_str.to_c_str()); assert!(result.is_ok()); } else { fail!("nread was 0.. wudn't expectin' that."); } loop_.close(); @@ -521,8 +519,8 @@ mod test { let write_buf = slice_to_uv_buf(write_val); let write_buf_ptr: *Buf = &write_buf; let open_req = FsRequest::new(); - do open_req.open(&loop_, &path, create_flags as int, mode as int) - |req, uverr| { + do open_req.open(&loop_, &path.to_c_str(), create_flags as int, + mode as int) |req, uverr| { assert!(uverr.is_none()); let fd = req.get_result(); let buf = unsafe { *write_buf_ptr }; @@ -531,7 +529,7 @@ mod test { assert!(uverr.is_none()); let loop_ = req.get_loop(); let stat_req = FsRequest::new(); - do stat_req.stat(&loop_, &path) |req, uverr| { + do stat_req.stat(&loop_, &path.to_c_str()) |req, uverr| { assert!(uverr.is_none()); let loop_ = req.get_loop(); let stat = req.get_stat(); @@ -542,11 +540,13 @@ mod test { assert!(uverr.is_none()); let loop_ = req.get_loop(); let unlink_req = FsRequest::new(); - do unlink_req.unlink(&loop_, &path) |req,uverr| { + do unlink_req.unlink(&loop_, + &path.to_c_str()) |req,uverr| { assert!(uverr.is_none()); let loop_ = req.get_loop(); let stat_req = FsRequest::new(); - do stat_req.stat(&loop_, &path) |_, uverr| { + do stat_req.stat(&loop_, + &path.to_c_str()) |_, uverr| { // should cause an error because the // file doesn't exist anymore assert!(uverr.is_some()); @@ -569,22 +569,23 @@ mod test { let mode = S_IWUSR | S_IRUSR; let mkdir_req = FsRequest::new(); - do mkdir_req.mkdir(&loop_, &path, mode as int) |req,uverr| { + do mkdir_req.mkdir(&loop_, &path.to_c_str(), + mode as int) |req,uverr| { assert!(uverr.is_none()); let loop_ = req.get_loop(); let stat_req = FsRequest::new(); - do stat_req.stat(&loop_, &path) |req, uverr| { + do stat_req.stat(&loop_, &path.to_c_str()) |req, uverr| { assert!(uverr.is_none()); let loop_ = req.get_loop(); let stat = req.get_stat(); naive_print(&loop_, format!("{:?}", stat)); assert!(stat.is_dir()); let rmdir_req = FsRequest::new(); - do rmdir_req.rmdir(&loop_, &path) |req,uverr| { + do rmdir_req.rmdir(&loop_, &path.to_c_str()) |req,uverr| { assert!(uverr.is_none()); let loop_ = req.get_loop(); let stat_req = FsRequest::new(); - do stat_req.stat(&loop_, &path) |_req, uverr| { + do stat_req.stat(&loop_, &path.to_c_str()) |_req, uverr| { assert!(uverr.is_some()); } } @@ -602,16 +603,17 @@ mod test { let mode = S_IWUSR | S_IRUSR; let mkdir_req = FsRequest::new(); - do mkdir_req.mkdir(&loop_, &path, mode as int) |req,uverr| { + do mkdir_req.mkdir(&loop_, &path.to_c_str(), mode as int) |req,uverr| { assert!(uverr.is_none()); let loop_ = req.get_loop(); let mkdir_req = FsRequest::new(); - do mkdir_req.mkdir(&loop_, &path, mode as int) |req,uverr| { + do mkdir_req.mkdir(&loop_, &path.to_c_str(), + mode as int) |req,uverr| { assert!(uverr.is_some()); let loop_ = req.get_loop(); let _stat = req.get_stat(); let rmdir_req = FsRequest::new(); - do rmdir_req.rmdir(&loop_, &path) |req,uverr| { + do rmdir_req.rmdir(&loop_, &path.to_c_str()) |req,uverr| { assert!(uverr.is_none()); let _loop = req.get_loop(); } @@ -627,7 +629,7 @@ mod test { let mut loop_ = Loop::new(); let path = "./tmp/never_existed_dir"; let rmdir_req = FsRequest::new(); - do rmdir_req.rmdir(&loop_, &path) |_req, uverr| { + do rmdir_req.rmdir(&loop_, &path.to_c_str()) |_req, uverr| { assert!(uverr.is_some()); } loop_.run(); diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index b0cdce7dd935d..96719e989721b 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -18,7 +18,6 @@ use ops::Drop; use option::*; use ptr; use str; -use str::Str; use result::*; use rt::io::IoError; use rt::io::net::ip::{SocketAddr, IpAddr}; @@ -234,8 +233,8 @@ impl EventLoop for UvEventLoop { ~UvRemoteCallback::new(self.uvio.uv_loop(), f) as ~RemoteCallback } - fn io<'a>(&'a mut self) -> Option<&'a mut IoFactory> { - Some(&mut self.uvio as &mut IoFactory) + fn io<'a>(&'a mut self, f: &fn(&'a mut IoFactory)) { + f(&mut self.uvio as &mut IoFactory) } } @@ -245,7 +244,7 @@ pub struct UvPausibleIdleCallback { priv closed: bool } -impl RtioPausibleIdleCallback for UvPausibleIdleCallback { +impl PausibleIdleCallback for UvPausibleIdleCallback { #[inline] fn start(&mut self, f: ~fn()) { do self.watcher.start |_idle_watcher, _status| { @@ -626,7 +625,9 @@ impl IoFactory for UvIoFactory { do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); let path = path_cell.take(); - let path_instance = Cell::new(Path::new(path.as_bytes())); + // Don't pick up the null byte + let slice = path.as_bytes().slice(0, path.len()); + let path_instance = Cell::new(Path::new(slice)); do stat_req.stat(self.uv_loop(), path) |req,err| { let res = match err { None => { @@ -720,14 +721,17 @@ impl IoFactory for UvIoFactory { do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); let path = path_cell.take(); - let path_parent = Cell::new(Path::new(path.as_bytes())); + // Don't pick up the null byte + let slice = path.as_bytes().slice(0, path.len()); + let path_parent = Cell::new(Path::new(slice)); do stat_req.readdir(self.uv_loop(), path, flags) |req,err| { let parent = path_parent.take(); let res = match err { None => { let mut paths = ~[]; do req.each_path |rel_path| { - paths.push(parent.join(rel_path.as_bytes())); + let p = rel_path.as_bytes(); + paths.push(parent.join(p.slice_to(rel_path.len()))); } Ok(paths) }, @@ -799,10 +803,10 @@ impl IoFactory for UvIoFactory { } } - fn unix_bind(&mut self, path: &P) -> + fn unix_bind(&mut self, path: &CString) -> Result<~RtioUnixListenerObject, IoError> { let mut pipe = Pipe::new(self.uv_loop(), false); - match pipe.bind(&path.path_as_str(|s| s.to_c_str())) { + match pipe.bind(path) { Ok(()) => { let handle = get_handle_to_current_scheduler!(); let pipe = UvUnboundPipe::new(pipe, handle); @@ -823,9 +827,7 @@ impl IoFactory for UvIoFactory { } } - fn unix_connect(&mut self, path: &P) -> - Result<~RtioPipe, IoError> - { + fn unix_connect(&mut self, path: &CString) -> Result<~RtioPipe, IoError> { let scheduler: ~Scheduler = Local::take(); let mut pipe = Pipe::new(self.uv_loop(), false); let result_cell = Cell::new_empty(); @@ -833,8 +835,7 @@ impl IoFactory for UvIoFactory { do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); - let cstr = do path.path_as_str |s| { s.to_c_str() }; - do pipe.connect(&cstr) |stream, err| { + do pipe.connect(path) |stream, err| { let res = match err { None => { let handle = stream.native_handle(); @@ -1841,13 +1842,22 @@ impl RtioTTY for UvTTY { } } +// this function is full of lies +unsafe fn local_io() -> &'static mut IoFactory { + do Local::borrow |sched: &mut Scheduler| { + let mut io = None; + sched.event_loop.io(|i| io = Some(i)); + cast::transmute(io.unwrap()) + } +} + #[test] fn test_simple_io_no_connect() { do run_in_mt_newsched_task { unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); + let io = local_io(); let addr = next_test_ip4(); - let maybe_chan = (*io).tcp_connect(addr); + let maybe_chan = io.tcp_connect(addr); assert!(maybe_chan.is_err()); } } @@ -1857,9 +1867,9 @@ fn test_simple_io_no_connect() { fn test_simple_udp_io_bind_only() { do run_in_mt_newsched_task { unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); + let io = local_io(); let addr = next_test_ip4(); - let maybe_socket = (*io).udp_bind(addr); + let maybe_socket = io.udp_bind(addr); assert!(maybe_socket.is_ok()); } } @@ -1878,9 +1888,11 @@ fn test_simple_homed_udp_io_bind_then_move_task_then_home_and_close() { let work_queue2 = WorkQueue::new(); let queues = ~[work_queue1.clone(), work_queue2.clone()]; - let mut sched1 = ~Scheduler::new(~UvEventLoop::new(), work_queue1, queues.clone(), + let loop1 = ~UvEventLoop::new() as ~EventLoop; + let mut sched1 = ~Scheduler::new(loop1, work_queue1, queues.clone(), sleepers.clone()); - let mut sched2 = ~Scheduler::new(~UvEventLoop::new(), work_queue2, queues.clone(), + let loop2 = ~UvEventLoop::new() as ~EventLoop; + let mut sched2 = ~Scheduler::new(loop2, work_queue2, queues.clone(), sleepers.clone()); let handle1 = Cell::new(sched1.make_handle()); @@ -1894,11 +1906,9 @@ fn test_simple_homed_udp_io_bind_then_move_task_then_home_and_close() { }; let test_function: ~fn() = || { - let io: *mut IoFactoryObject = unsafe { - Local::unsafe_borrow() - }; + let io = unsafe { local_io() }; let addr = next_test_ip4(); - let maybe_socket = unsafe { (*io).udp_bind(addr) }; + let maybe_socket = io.udp_bind(addr); // this socket is bound to this event loop assert!(maybe_socket.is_ok()); @@ -1957,9 +1967,11 @@ fn test_simple_homed_udp_io_bind_then_move_handle_then_home_and_close() { let work_queue2 = WorkQueue::new(); let queues = ~[work_queue1.clone(), work_queue2.clone()]; - let mut sched1 = ~Scheduler::new(~UvEventLoop::new(), work_queue1, queues.clone(), + let loop1 = ~UvEventLoop::new() as ~EventLoop; + let mut sched1 = ~Scheduler::new(loop1, work_queue1, queues.clone(), sleepers.clone()); - let mut sched2 = ~Scheduler::new(~UvEventLoop::new(), work_queue2, queues.clone(), + let loop2 = ~UvEventLoop::new() as ~EventLoop; + let mut sched2 = ~Scheduler::new(loop2, work_queue2, queues.clone(), sleepers.clone()); let handle1 = Cell::new(sched1.make_handle()); @@ -1970,11 +1982,9 @@ fn test_simple_homed_udp_io_bind_then_move_handle_then_home_and_close() { let chan = Cell::new(chan); let body1: ~fn() = || { - let io: *mut IoFactoryObject = unsafe { - Local::unsafe_borrow() - }; + let io = unsafe { local_io() }; let addr = next_test_ip4(); - let socket = unsafe { (*io).udp_bind(addr) }; + let socket = io.udp_bind(addr); assert!(socket.is_ok()); chan.take().send(socket); }; @@ -2028,8 +2038,8 @@ fn test_simple_tcp_server_and_client() { // Start the server first so it's listening when we connect do spawntask { unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - let listener = (*io).tcp_bind(addr).unwrap(); + let io = local_io(); + let listener = io.tcp_bind(addr).unwrap(); let mut acceptor = listener.listen().unwrap(); chan.take().send(()); let mut stream = acceptor.accept().unwrap(); @@ -2046,8 +2056,8 @@ fn test_simple_tcp_server_and_client() { do spawntask { unsafe { port.take().recv(); - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - let mut stream = (*io).tcp_connect(addr).unwrap(); + let io = local_io(); + let mut stream = io.tcp_connect(addr).unwrap(); stream.write([0, 1, 2, 3, 4, 5, 6, 7]); } } @@ -2071,9 +2081,11 @@ fn test_simple_tcp_server_and_client_on_diff_threads() { let client_work_queue = WorkQueue::new(); let queues = ~[server_work_queue.clone(), client_work_queue.clone()]; - let mut server_sched = ~Scheduler::new(~UvEventLoop::new(), server_work_queue, + let sloop = ~UvEventLoop::new() as ~EventLoop; + let mut server_sched = ~Scheduler::new(sloop, server_work_queue, queues.clone(), sleepers.clone()); - let mut client_sched = ~Scheduler::new(~UvEventLoop::new(), client_work_queue, + let cloop = ~UvEventLoop::new() as ~EventLoop; + let mut client_sched = ~Scheduler::new(cloop, client_work_queue, queues.clone(), sleepers.clone()); let server_handle = Cell::new(server_sched.make_handle()); @@ -2090,8 +2102,8 @@ fn test_simple_tcp_server_and_client_on_diff_threads() { }; let server_fn: ~fn() = || { - let io: *mut IoFactoryObject = unsafe { Local::unsafe_borrow() }; - let listener = unsafe { (*io).tcp_bind(server_addr).unwrap() }; + let io = unsafe { local_io() }; + let listener = io.tcp_bind(server_addr).unwrap(); let mut acceptor = listener.listen().unwrap(); let mut stream = acceptor.accept().unwrap(); let mut buf = [0, .. 2048]; @@ -2103,12 +2115,10 @@ fn test_simple_tcp_server_and_client_on_diff_threads() { }; let client_fn: ~fn() = || { - let io: *mut IoFactoryObject = unsafe { - Local::unsafe_borrow() - }; - let mut stream = unsafe { (*io).tcp_connect(client_addr) }; + let io = unsafe { local_io() }; + let mut stream = io.tcp_connect(client_addr); while stream.is_err() { - stream = unsafe { (*io).tcp_connect(client_addr) }; + stream = io.tcp_connect(client_addr); } stream.unwrap().write([0, 1, 2, 3, 4, 5, 6, 7]); }; @@ -2147,8 +2157,8 @@ fn test_simple_udp_server_and_client() { do spawntask { unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - let mut server_socket = (*io).udp_bind(server_addr).unwrap(); + let io = local_io(); + let mut server_socket = io.udp_bind(server_addr).unwrap(); chan.take().send(()); let mut buf = [0, .. 2048]; let (nread,src) = server_socket.recvfrom(buf).unwrap(); @@ -2163,8 +2173,8 @@ fn test_simple_udp_server_and_client() { do spawntask { unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - let mut client_socket = (*io).udp_bind(client_addr).unwrap(); + let io = local_io(); + let mut client_socket = io.udp_bind(client_addr).unwrap(); port.take().recv(); client_socket.sendto([0, 1, 2, 3, 4, 5, 6, 7], server_addr); } @@ -2181,8 +2191,8 @@ fn test_read_and_block() { let chan = Cell::new(chan); do spawntask { - let io: *mut IoFactoryObject = unsafe { Local::unsafe_borrow() }; - let listener = unsafe { (*io).tcp_bind(addr).unwrap() }; + let io = unsafe { local_io() }; + let listener = io.tcp_bind(addr).unwrap(); let mut acceptor = listener.listen().unwrap(); chan.take().send(()); let mut stream = acceptor.accept().unwrap(); @@ -2220,8 +2230,8 @@ fn test_read_and_block() { do spawntask { unsafe { port.take().recv(); - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - let mut stream = (*io).tcp_connect(addr).unwrap(); + let io = local_io(); + let mut stream = io.tcp_connect(addr).unwrap(); stream.write([0, 1, 2, 3, 4, 5, 6, 7]); stream.write([0, 1, 2, 3, 4, 5, 6, 7]); stream.write([0, 1, 2, 3, 4, 5, 6, 7]); @@ -2243,8 +2253,8 @@ fn test_read_read_read() { do spawntask { unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - let listener = (*io).tcp_bind(addr).unwrap(); + let io = local_io(); + let listener = io.tcp_bind(addr).unwrap(); let mut acceptor = listener.listen().unwrap(); chan.take().send(()); let mut stream = acceptor.accept().unwrap(); @@ -2260,8 +2270,8 @@ fn test_read_read_read() { do spawntask { unsafe { port.take().recv(); - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - let mut stream = (*io).tcp_connect(addr).unwrap(); + let io = local_io(); + let mut stream = io.tcp_connect(addr).unwrap(); let mut buf = [0, .. 2048]; let mut total_bytes_read = 0; while total_bytes_read < MAX { @@ -2289,8 +2299,8 @@ fn test_udp_twice() { do spawntask { unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - let mut client = (*io).udp_bind(client_addr).unwrap(); + let io = local_io(); + let mut client = io.udp_bind(client_addr).unwrap(); port.take().recv(); assert!(client.sendto([1], server_addr).is_ok()); assert!(client.sendto([2], server_addr).is_ok()); @@ -2299,8 +2309,8 @@ fn test_udp_twice() { do spawntask { unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - let mut server = (*io).udp_bind(server_addr).unwrap(); + let io = local_io(); + let mut server = io.udp_bind(server_addr).unwrap(); chan.take().send(()); let mut buf1 = [0]; let mut buf2 = [0]; @@ -2334,9 +2344,9 @@ fn test_udp_many_read() { do spawntask { unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - let mut server_out = (*io).udp_bind(server_out_addr).unwrap(); - let mut server_in = (*io).udp_bind(server_in_addr).unwrap(); + let io = local_io(); + let mut server_out = io.udp_bind(server_out_addr).unwrap(); + let mut server_in = io.udp_bind(server_in_addr).unwrap(); let (port, chan) = first.take(); chan.send(()); port.recv(); @@ -2360,9 +2370,9 @@ fn test_udp_many_read() { do spawntask { unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - let mut client_out = (*io).udp_bind(client_out_addr).unwrap(); - let mut client_in = (*io).udp_bind(client_in_addr).unwrap(); + let io = local_io(); + let mut client_out = io.udp_bind(client_out_addr).unwrap(); + let mut client_in = io.udp_bind(client_in_addr).unwrap(); let (port, chan) = second.take(); port.recv(); chan.send(()); @@ -2392,8 +2402,8 @@ fn test_udp_many_read() { fn test_timer_sleep_simple() { do run_in_mt_newsched_task { unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); - let timer = (*io).timer_init(); + let io = local_io(); + let timer = io.timer_init(); do timer.map_move |mut t| { t.sleep(1) }; } } @@ -2403,29 +2413,28 @@ fn file_test_uvio_full_simple_impl() { use str::StrSlice; // why does this have to be explicitly imported to work? // compiler was complaining about no trait for str that // does .as_bytes() .. - use path::Path; use rt::io::{Open, Create, ReadWrite, Read}; unsafe { - let io: *mut IoFactoryObject = Local::unsafe_borrow(); + let io = local_io(); let write_val = "hello uvio!"; let path = "./tmp/file_test_uvio_full.txt"; { let create_fm = Create; let create_fa = ReadWrite; - let mut fd = (*io).fs_open(&path.to_c_str(), create_fm, create_fa).unwrap(); + let mut fd = io.fs_open(&path.to_c_str(), create_fm, create_fa).unwrap(); let write_buf = write_val.as_bytes(); fd.write(write_buf); } { let ro_fm = Open; let ro_fa = Read; - let mut fd = (*io).fs_open(&path.to_c_str(), ro_fm, ro_fa).unwrap(); + let mut fd = io.fs_open(&path.to_c_str(), ro_fm, ro_fa).unwrap(); let mut read_vec = [0, .. 1028]; let nread = fd.read(read_vec).unwrap(); let read_val = str::from_utf8(read_vec.slice(0, nread as uint)); assert!(read_val == write_val.to_owned()); } - (*io).fs_unlink(&path.to_c_str()); + io.fs_unlink(&path.to_c_str()); } } @@ -2440,9 +2449,9 @@ fn uvio_naive_print(input: &str) { use str::StrSlice; unsafe { use libc::{STDOUT_FILENO}; - let io: *mut IoFactoryObject = Local::unsafe_borrow(); + let io = local_io(); { - let mut fd = (*io).fs_from_raw_fd(STDOUT_FILENO, false); + let mut fd = io.fs_from_raw_fd(STDOUT_FILENO, false); let write_buf = input.as_bytes(); fd.write(write_buf); } diff --git a/src/libstd/str.rs b/src/libstd/str.rs index 3c89c12dbfa18..053076c5d89ec 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -1018,7 +1018,6 @@ static TAG_CONT_U8: u8 = 128u8; /// Unsafe operations pub mod raw { - use option::{Option, Some}; use cast; use libc; use ptr; From 59d45b8fe793d369ddf600cce0f212f9b6165a30 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 17 Oct 2013 11:28:05 -0700 Subject: [PATCH 09/23] Don't attempt to export uv functions directly --- src/libstd/rt/io/stdio.rs | 14 ------------ src/libstd/rt/rtio.rs | 1 - src/libstd/rt/uv/pipe.rs | 12 +++++----- src/libstd/rt/uv/tty.rs | 15 +++++-------- src/libstd/rt/uv/uvio.rs | 4 ---- src/libstd/rt/uv/uvll.rs | 46 ++++++++++++++++++++++++++++++--------- src/rt/rust_uv.cpp | 31 ++++++++++++++++++++++++++ src/rt/rustrt.def.in | 13 +++++------ 8 files changed, 84 insertions(+), 52 deletions(-) diff --git a/src/libstd/rt/io/stdio.rs b/src/libstd/rt/io/stdio.rs index a3cbe87431de0..52838425422ca 100644 --- a/src/libstd/rt/io/stdio.rs +++ b/src/libstd/rt/io/stdio.rs @@ -115,13 +115,6 @@ impl StdReader { Err(e) => io_error::cond.raise(e), } } - - /// Resets the mode of this stream back to its original state. - /// - /// # Failure - /// - /// This function cannot fail. - pub fn reset_mode(&mut self) { self.inner.reset_mode(); } } impl Reader for StdReader { @@ -177,13 +170,6 @@ impl StdWriter { Err(e) => io_error::cond.raise(e), } } - - /// Resets the mode of this stream back to its original state. - /// - /// # Failure - /// - /// This function cannot fail. - pub fn reset_mode(&mut self) { self.inner.reset_mode(); } } impl Writer for StdWriter { diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index 897bf328f2367..924d9c4bff199 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -186,7 +186,6 @@ pub trait RtioTTY { fn read(&mut self, buf: &mut [u8]) -> Result; fn write(&mut self, buf: &[u8]) -> Result<(), IoError>; fn set_raw(&mut self, raw: bool) -> Result<(), IoError>; - fn reset_mode(&mut self); fn get_winsize(&mut self) -> Result<(int, int), IoError>; } diff --git a/src/libstd/rt/uv/pipe.rs b/src/libstd/rt/uv/pipe.rs index 2ad5079e5d546..74b9312954c83 100644 --- a/src/libstd/rt/uv/pipe.rs +++ b/src/libstd/rt/uv/pipe.rs @@ -40,7 +40,7 @@ impl Pipe { #[fixed_stack_segment] #[inline(never)] pub fn open(&mut self, file: libc::c_int) -> Result<(), uv::UvError> { - match unsafe { uvll::uv_pipe_open(self.native_handle(), file) } { + match unsafe { uvll::pipe_open(self.native_handle(), file) } { 0 => Ok(()), n => Err(uv::UvError(n)) } @@ -49,7 +49,7 @@ impl Pipe { #[fixed_stack_segment] #[inline(never)] pub fn bind(&mut self, name: &CString) -> Result<(), uv::UvError> { do name.with_ref |name| { - match unsafe { uvll::uv_pipe_bind(self.native_handle(), name) } { + match unsafe { uvll::pipe_bind(self.native_handle(), name) } { 0 => Ok(()), n => Err(uv::UvError(n)) } @@ -68,10 +68,10 @@ impl Pipe { let name = do name.with_ref |p| { p }; unsafe { - uvll::uv_pipe_connect(connect.native_handle(), - self.native_handle(), - name, - connect_cb) + uvll::pipe_connect(connect.native_handle(), + self.native_handle(), + name, + connect_cb) } extern "C" fn connect_cb(req: *uvll::uv_connect_t, status: libc::c_int) { diff --git a/src/libstd/rt/uv/tty.rs b/src/libstd/rt/uv/tty.rs index 4c9a08f95bf84..f44c5ae8eff61 100644 --- a/src/libstd/rt/uv/tty.rs +++ b/src/libstd/rt/uv/tty.rs @@ -29,8 +29,8 @@ impl TTY { assert!(handle.is_not_null()); let ret = unsafe { - uvll::uv_tty_init(loop_.native_handle(), handle, fd as libc::c_int, - readable as libc::c_int) + uvll::tty_init(loop_.native_handle(), handle, fd as libc::c_int, + readable as libc::c_int) }; match ret { 0 => { @@ -52,17 +52,12 @@ impl TTY { #[fixed_stack_segment] #[inline(never)] pub fn set_mode(&self, raw: bool) -> Result<(), uv::UvError> { let raw = raw as libc::c_int; - match unsafe { uvll::uv_tty_set_mode(self.native_handle(), raw) } { + match unsafe { uvll::tty_set_mode(self.native_handle(), raw) } { 0 => Ok(()), n => Err(uv::UvError(n)) } } - #[fixed_stack_segment] #[inline(never)] - pub fn reset_mode(&self) { - unsafe { uvll::uv_tty_reset_mode(self.native_handle()) } - } - #[fixed_stack_segment] #[inline(never)] #[allow(unused_mut)] pub fn get_winsize(&self) -> Result<(int, int), uv::UvError> { let mut width: libc::c_int = 0; @@ -70,8 +65,8 @@ impl TTY { let widthptr: *libc::c_int = &width; let heightptr: *libc::c_int = &width; - match unsafe { uvll::uv_tty_get_winsize(self.native_handle(), - widthptr, heightptr) } { + match unsafe { uvll::tty_get_winsize(self.native_handle(), + widthptr, heightptr) } { 0 => Ok((width as int, height as int)), n => Err(uv::UvError(n)) } diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 96719e989721b..3858b64915ac3 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -1829,10 +1829,6 @@ impl RtioTTY for UvTTY { } } - 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() { diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index 8ef1d1768b8c4..e78b2579779f9 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -959,6 +959,33 @@ pub unsafe fn freeaddrinfo(ai: *addrinfo) { #[fixed_stack_segment]; #[inline(never)]; rust_uv_freeaddrinfo(ai); } +pub unsafe fn pipe_open(pipe: *uv_pipe_t, file: c_int) -> c_int { + #[fixed_stack_segment]; #[inline(never)]; + rust_uv_pipe_open(pipe, file) +} +pub unsafe fn pipe_bind(pipe: *uv_pipe_t, name: *c_char) -> c_int { + #[fixed_stack_segment]; #[inline(never)]; + rust_uv_pipe_bind(pipe, name) +} +pub unsafe fn pipe_connect(req: *uv_connect_t, handle: *uv_pipe_t, + name: *c_char, cb: uv_connect_cb) { + #[fixed_stack_segment]; #[inline(never)]; + rust_uv_pipe_connect(req, handle, name, cb) +} +pub unsafe fn tty_init(loop_ptr: *uv_loop_t, tty: *uv_tty_t, fd: c_int, + readable: c_int) -> c_int { + #[fixed_stack_segment]; #[inline(never)]; + rust_uv_tty_init(loop_ptr, tty, fd, readable) +} +pub unsafe fn tty_set_mode(tty: *uv_tty_t, mode: c_int) -> c_int { + #[fixed_stack_segment]; #[inline(never)]; + rust_uv_tty_set_mode(tty, mode) +} +pub unsafe fn tty_get_winsize(tty: *uv_tty_t, width: *c_int, + height: *c_int) -> c_int { + #[fixed_stack_segment]; #[inline(never)]; + rust_uv_tty_get_winsize(tty, width, height) +} pub struct uv_err_data { priv err_name: ~str, @@ -1104,16 +1131,15 @@ extern { stream: *uv_stream_t); fn rust_uv_pipe_init(loop_ptr: *c_void, p: *uv_pipe_t, ipc: c_int) -> c_int; - pub fn uv_pipe_open(pipe: *uv_pipe_t, file: c_int) -> c_int; - pub fn uv_pipe_bind(pipe: *uv_pipe_t, name: *c_char) -> c_int; - pub fn uv_pipe_connect(req: *uv_connect_t, handle: *uv_pipe_t, - name: *c_char, cb: uv_connect_cb); - pub fn uv_tty_init(loop_ptr: *uv_loop_t, tty: *uv_tty_t, fd: c_int, - readable: c_int) -> c_int; - pub fn uv_tty_set_mode(tty: *uv_tty_t, mode: c_int) -> c_int; - pub fn uv_tty_reset_mode(tty: *uv_tty_t); - pub fn uv_tty_get_winsize(tty: *uv_tty_t, width: *c_int, - height: *c_int) -> c_int; + fn rust_uv_pipe_open(pipe: *uv_pipe_t, file: c_int) -> c_int; + fn rust_uv_pipe_bind(pipe: *uv_pipe_t, name: *c_char) -> c_int; + fn rust_uv_pipe_connect(req: *uv_connect_t, handle: *uv_pipe_t, + name: *c_char, cb: uv_connect_cb); + fn rust_uv_tty_init(loop_ptr: *uv_loop_t, tty: *uv_tty_t, fd: c_int, + readable: c_int) -> c_int; + fn rust_uv_tty_set_mode(tty: *uv_tty_t, mode: c_int) -> c_int; + fn rust_uv_tty_get_winsize(tty: *uv_tty_t, width: *c_int, + height: *c_int) -> c_int; // These should all really be constants... #[rust_stack] pub fn rust_SOCK_STREAM() -> c_int; diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index 29d0800237b6b..a47b3446d3442 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -650,3 +650,34 @@ extern "C" int rust_AI_NUMERICHOST() { return AI_NUMERICHOST; } extern "C" int rust_AI_NUMERICSERV() { return AI_NUMERICSERV; } extern "C" int rust_AI_PASSIVE() { return AI_PASSIVE; } extern "C" int rust_AI_V4MAPPED() { return AI_V4MAPPED; } + +extern "C" int +rust_uv_pipe_open(uv_pipe_t *pipe, int file) { + return uv_pipe_open(pipe, file); +} + +extern "C" int +rust_uv_pipe_bind(uv_pipe_t *pipe, char *name) { + return uv_pipe_bind(pipe, name); +} + +extern "C" void +rust_uv_pipe_connect(uv_connect_t *req, uv_pipe_t *handle, + char *name, uv_connect_cb cb) { + uv_pipe_connect(req, handle, name, cb); +} + +extern "C" int +rust_uv_tty_init(uv_loop_t *loop, uv_tty_t *tty, int fd, int readable) { + return uv_tty_init(loop, tty, fd, readable); +} + +extern "C" int +rust_uv_tty_set_mode(uv_tty_t *tty, int mode) { + return uv_tty_set_mode(tty, mode); +} + +extern "C" int +rust_uv_tty_get_winsize(uv_tty_t *tty, int *width, int *height) { + return uv_tty_get_winsize(tty, width, height); +} diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 5945fdc3e59b1..58862da31db5c 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -211,10 +211,9 @@ rust_AI_NUMERICHOST rust_AI_NUMERICSERV rust_AI_PASSIVE rust_AI_V4MAPPED -uv_pipe_open -uv_pipe_bind -uv_pipe_connect -uv_tty_init -uv_tty_set_mode -uv_tty_reset_mode -uv_tty_get_winsize +rust_uv_pipe_open +rust_uv_pipe_bind +rust_uv_pipe_connect +rust_uv_tty_init +rust_uv_tty_set_mode +rust_uv_tty_get_winsize From 4ce71eaca34526d0e3ee1ebf0658d2a20d388ef2 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 17 Oct 2013 12:13:29 -0700 Subject: [PATCH 10/23] Migrate the last typedefs to ~Trait in rtio There are no longer any remnants of typedefs, and everything is now built on true trait objects. --- src/libstd/rt/io/net/tcp.rs | 4 ++-- src/libstd/rt/io/net/unix.rs | 4 ++-- src/libstd/rt/rtio.rs | 13 ++++--------- src/libstd/rt/uv/uvio.rs | 12 ++++++------ 4 files changed, 14 insertions(+), 19 deletions(-) diff --git a/src/libstd/rt/io/net/tcp.rs b/src/libstd/rt/io/net/tcp.rs index bafde180d5c9e..21f98c272968f 100644 --- a/src/libstd/rt/io/net/tcp.rs +++ b/src/libstd/rt/io/net/tcp.rs @@ -13,7 +13,7 @@ use result::{Ok, Err}; use rt::io::net::ip::SocketAddr; use rt::io::{Reader, Writer, Listener, Acceptor}; use rt::io::{io_error, read_error, EndOfFile}; -use rt::rtio::{IoFactory, RtioTcpListenerObject, with_local_io, +use rt::rtio::{IoFactory, with_local_io, RtioSocket, RtioTcpListener, RtioTcpAcceptor, RtioTcpStream}; pub struct TcpStream { @@ -89,7 +89,7 @@ impl Writer for TcpStream { } pub struct TcpListener { - priv obj: ~RtioTcpListenerObject + priv obj: ~RtioTcpListener } impl TcpListener { diff --git a/src/libstd/rt/io/net/unix.rs b/src/libstd/rt/io/net/unix.rs index b98d5b52cb2bf..fc7839d545fa9 100644 --- a/src/libstd/rt/io/net/unix.rs +++ b/src/libstd/rt/io/net/unix.rs @@ -26,7 +26,7 @@ use prelude::*; use c_str::ToCStr; use rt::rtio::{IoFactory, RtioUnixListener, with_local_io}; -use rt::rtio::{RtioUnixAcceptor, RtioPipe, RtioUnixListenerObject}; +use rt::rtio::{RtioUnixAcceptor, RtioPipe}; use rt::io::pipe::PipeStream; use rt::io::{io_error, Listener, Acceptor, Reader, Writer}; @@ -82,7 +82,7 @@ impl Writer for UnixStream { } pub struct UnixListener { - priv obj: ~RtioUnixListenerObject, + priv obj: ~RtioUnixListener, } impl UnixListener { diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index 924d9c4bff199..c779be0104662 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -18,15 +18,10 @@ use ai = rt::io::net::addrinfo; use rt::io::IoError; use super::io::process::ProcessConfig; use super::io::net::ip::{IpAddr, SocketAddr}; -use rt::uv::uvio; use path::Path; use super::io::{SeekStyle}; use super::io::{FileMode, FileAccess, FileStat}; -// FIXME(#9893) cannot call by-value self method on a trait object -pub type RtioTcpListenerObject = uvio::UvTcpListener; -pub type RtioUnixListenerObject = uvio::UvUnixListener; - pub trait EventLoop { fn run(&mut self); fn callback(&mut self, ~fn()); @@ -82,7 +77,7 @@ pub fn with_local_io(f: &fn(&mut IoFactory) -> Option) -> Option { pub trait IoFactory { fn tcp_connect(&mut self, addr: SocketAddr) -> Result<~RtioTcpStream, IoError>; - fn tcp_bind(&mut self, addr: SocketAddr) -> Result<~RtioTcpListenerObject, IoError>; + fn tcp_bind(&mut self, addr: SocketAddr) -> Result<~RtioTcpListener, IoError>; fn udp_bind(&mut self, addr: SocketAddr) -> Result<~RtioUdpSocket, IoError>; fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>, hint: Option) -> Result<~[ai::Info], IoError>; @@ -100,14 +95,14 @@ pub trait IoFactory { -> Result<(~RtioProcess, ~[Option<~RtioPipe>]), IoError>; fn unix_bind(&mut self, path: &CString) -> - Result<~RtioUnixListenerObject, IoError>; + Result<~RtioUnixListener, IoError>; fn unix_connect(&mut self, path: &CString) -> Result<~RtioPipe, IoError>; fn tty_open(&mut self, fd: c_int, readable: bool, close_on_drop: bool) -> Result<~RtioTTY, IoError>; } pub trait RtioTcpListener : RtioSocket { - fn listen(self) -> Result<~RtioTcpAcceptor, IoError>; + fn listen(~self) -> Result<~RtioTcpAcceptor, IoError>; } pub trait RtioTcpAcceptor : RtioSocket { @@ -173,7 +168,7 @@ pub trait RtioPipe { } pub trait RtioUnixListener { - fn listen(self) -> Result<~RtioUnixAcceptor, IoError>; + fn listen(~self) -> Result<~RtioUnixAcceptor, IoError>; } pub trait RtioUnixAcceptor { diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 3858b64915ac3..322588973ae77 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -493,12 +493,12 @@ impl IoFactory for UvIoFactory { return result_cell.take(); } - fn tcp_bind(&mut self, addr: SocketAddr) -> Result<~RtioTcpListenerObject, IoError> { + fn tcp_bind(&mut self, addr: SocketAddr) -> Result<~RtioTcpListener, IoError> { let mut watcher = TcpWatcher::new(self.uv_loop()); match watcher.bind(addr) { Ok(_) => { let home = get_handle_to_current_scheduler!(); - Ok(~UvTcpListener::new(watcher, home)) + Ok(~UvTcpListener::new(watcher, home) as ~RtioTcpListener) } Err(uverr) => { do task::unkillable { // FIXME(#8674) @@ -804,13 +804,13 @@ impl IoFactory for UvIoFactory { } fn unix_bind(&mut self, path: &CString) -> - Result<~RtioUnixListenerObject, IoError> { + Result<~RtioUnixListener, IoError> { let mut pipe = Pipe::new(self.uv_loop(), false); match pipe.bind(path) { Ok(()) => { let handle = get_handle_to_current_scheduler!(); let pipe = UvUnboundPipe::new(pipe, handle); - Ok(~UvUnixListener::new(pipe)) + Ok(~UvUnixListener::new(pipe) as ~RtioUnixListener) } Err(e) => { let scheduler: ~Scheduler = Local::take(); @@ -919,7 +919,7 @@ impl RtioSocket for UvTcpListener { } impl RtioTcpListener for UvTcpListener { - fn listen(self) -> Result<~RtioTcpAcceptor, IoError> { + fn listen(~self) -> Result<~RtioTcpAcceptor, IoError> { do self.home_for_io_consume |self_| { let acceptor = ~UvTcpAcceptor::new(self_); let incoming = Cell::new(acceptor.incoming.clone()); @@ -1717,7 +1717,7 @@ impl UvUnixListener { } impl RtioUnixListener for UvUnixListener { - fn listen(self) -> Result<~RtioUnixAcceptor, IoError> { + fn listen(~self) -> Result<~RtioUnixAcceptor, IoError> { do self.home_for_io_consume |self_| { let acceptor = ~UvUnixAcceptor::new(self_); let incoming = Cell::new(acceptor.incoming.clone()); From 4eb53360541baf3e6df36dc0f0766bc7c1c9f8be Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 17 Oct 2013 17:04:51 -0700 Subject: [PATCH 11/23] Move as much I/O as possible off of native::io When uv's TTY I/O is used for the stdio streams, the file descriptors are put into a non-blocking mode. This means that other concurrent writes to the same stream can fail with EAGAIN or EWOULDBLOCK. By all I/O to event-loop I/O, we avoid this error. There is one location which cannot move, which is the runtime's dumb_println function. This was implemented to handle the EAGAIN and EWOULDBLOCK errors and simply retry again and again. --- src/libstd/logging.rs | 2 +- src/libstd/rt/io/mod.rs | 2 + src/libstd/rt/io/native/file.rs | 6 +++ src/libstd/rt/io/stdio.rs | 68 +++++++++++++++++--------- src/libstd/rt/logging.rs | 20 ++++++-- src/libstd/rt/rtio.rs | 3 +- src/libstd/rt/task.rs | 44 ++++++++--------- src/libstd/rt/util.rs | 13 ++++- src/libstd/rt/uv/mod.rs | 11 +++++ src/libstd/rt/uv/uvio.rs | 86 ++++++++++++++++----------------- src/libstd/rt/uv/uvll.rs | 5 ++ src/rt/rust_uv.cpp | 5 ++ src/rt/rustrt.def.in | 1 + 13 files changed, 166 insertions(+), 100 deletions(-) diff --git a/src/libstd/logging.rs b/src/libstd/logging.rs index 5e1ef3658b3f5..35a3ca3cff05d 100644 --- a/src/libstd/logging.rs +++ b/src/libstd/logging.rs @@ -112,7 +112,7 @@ pub fn log(_level: u32, args: &fmt::Arguments) { } None => { // There is no logger anywhere, just write to stderr - let mut logger = StdErrLogger; + let mut logger = StdErrLogger::new(); logger.log(args); } } diff --git a/src/libstd/rt/io/mod.rs b/src/libstd/rt/io/mod.rs index 1a5c197fd5271..240210880bfab 100644 --- a/src/libstd/rt/io/mod.rs +++ b/src/libstd/rt/io/mod.rs @@ -370,6 +370,7 @@ pub enum IoErrorKind { PathAlreadyExists, PathDoesntExist, MismatchedFileTypeForOperation, + ResourceUnavailable, IoUnavailable, } @@ -392,6 +393,7 @@ impl ToStr for IoErrorKind { PathDoesntExist => ~"PathDoesntExist", MismatchedFileTypeForOperation => ~"MismatchedFileTypeForOperation", IoUnavailable => ~"IoUnavailable", + ResourceUnavailable => ~"ResourceUnavailable", } } } diff --git a/src/libstd/rt/io/native/file.rs b/src/libstd/rt/io/native/file.rs index d682098118172..a2b2289679afc 100644 --- a/src/libstd/rt/io/native/file.rs +++ b/src/libstd/rt/io/native/file.rs @@ -21,6 +21,12 @@ fn raise_error() { // XXX: this should probably be a bit more descriptive... let (kind, desc) = match os::errno() as i32 { libc::EOF => (EndOfFile, "end of file"), + + // These two constants can have the same value on some systems, but + // different values on others, so we can't use a match clause + x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => + (ResourceUnavailable, "resource temporarily unavailable"), + _ => (OtherIoError, "unknown error"), }; diff --git a/src/libstd/rt/io/stdio.rs b/src/libstd/rt/io/stdio.rs index 52838425422ca..294df9a6442a1 100644 --- a/src/libstd/rt/io/stdio.rs +++ b/src/libstd/rt/io/stdio.rs @@ -8,6 +8,24 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +/*! + +This modules provides bindings to the local event loop's TTY interface, using it +to have synchronous, but non-blocking versions of stdio. These handles can be +inspected for information about terminal dimensions or related information +about the stream or terminal that it is attached to. + +# Example + +```rust +use std::rt::io; + +let mut out = io::stdout(); +out.write(bytes!("Hello, world!")); +``` + +*/ + use fmt; use libc; use option::{Option, Some, None}; @@ -15,13 +33,14 @@ use result::{Ok, Err}; use rt::rtio::{IoFactory, RtioTTY, with_local_io}; use super::{Reader, Writer, io_error}; -/// Creates a new non-blocking handle to the stdin of the current process. -/// -/// See `stdout()` for notes about this function. -pub fn stdin() -> StdReader { +#[fixed_stack_segment] #[inline(never)] +fn tty(fd: libc::c_int, f: &fn(~RtioTTY) -> T) -> T { do with_local_io |io| { - match io.tty_open(libc::STDIN_FILENO, true, false) { - Ok(tty) => Some(StdReader { inner: tty }), + // Always pass in readable as true, otherwise libuv turns our writes + // into blocking writes. We also need to dup the file descriptor because + // the tty will be closed when it's dropped. + match io.tty_open(unsafe { libc::dup(fd) }, true) { + Ok(tty) => Some(f(tty)), Err(e) => { io_error::cond.raise(e); None @@ -30,6 +49,13 @@ pub fn stdin() -> StdReader { }.unwrap() } +/// Creates a new non-blocking handle to the stdin of the current process. +/// +/// See `stdout()` for notes about this function. +pub fn stdin() -> StdReader { + do tty(libc::STDIN_FILENO) |tty| { StdReader { inner: tty } } +} + /// Creates a new non-blocking handle to the stdout of the current process. /// /// Note that this is a fairly expensive operation in that at least one memory @@ -37,30 +63,14 @@ pub fn stdin() -> StdReader { /// task context because the stream returned will be a non-blocking object using /// the local scheduler to perform the I/O. pub fn stdout() -> StdWriter { - do with_local_io |io| { - match io.tty_open(libc::STDOUT_FILENO, false, false) { - Ok(tty) => Some(StdWriter { inner: tty }), - Err(e) => { - io_error::cond.raise(e); - None - } - } - }.unwrap() + do tty(libc::STDOUT_FILENO) |tty| { StdWriter { inner: tty } } } /// Creates a new non-blocking handle to the stderr of the current process. /// /// See `stdout()` for notes about this function. pub fn stderr() -> StdWriter { - do with_local_io |io| { - match io.tty_open(libc::STDERR_FILENO, false, false) { - Ok(tty) => Some(StdWriter { inner: tty }), - Err(e) => { - io_error::cond.raise(e); - None - } - } - }.unwrap() + do tty(libc::STDERR_FILENO) |tty| { StdWriter { inner: tty } } } /// Prints a string to the stdout of the current process. No newline is emitted @@ -115,6 +125,11 @@ impl StdReader { Err(e) => io_error::cond.raise(e), } } + + /// Returns whether this tream is attached to a TTY instance or not. + /// + /// This is similar to libc's isatty() function + pub fn isatty(&self) -> bool { self.inner.isatty() } } impl Reader for StdReader { @@ -170,6 +185,11 @@ impl StdWriter { Err(e) => io_error::cond.raise(e), } } + + /// Returns whether this tream is attached to a TTY instance or not. + /// + /// This is similar to libc's isatty() function + pub fn isatty(&self) -> bool { self.inner.isatty() } } impl Writer for StdWriter { diff --git a/src/libstd/rt/logging.rs b/src/libstd/rt/logging.rs index 660d1cd43595f..31650ede7000d 100644 --- a/src/libstd/rt/logging.rs +++ b/src/libstd/rt/logging.rs @@ -12,6 +12,7 @@ use fmt; use from_str::from_str; use libc::exit; use option::{Some, None, Option}; +use rt::io; use rt::crate_map::{ModEntry, CrateMap, iter_crate_map, get_crate_map}; use str::StrSlice; use u32; @@ -166,14 +167,23 @@ pub trait Logger { fn log(&mut self, args: &fmt::Arguments); } -pub struct StdErrLogger; +/// This logger emits output to the stderr of the process, and contains a lazily +/// initialized event-loop driven handle to the stream. +pub struct StdErrLogger { + priv handle: Option, +} + +impl StdErrLogger { + pub fn new() -> StdErrLogger { StdErrLogger { handle: None } } +} impl Logger for StdErrLogger { fn log(&mut self, args: &fmt::Arguments) { - // FIXME(#6846): this should not call the blocking version of println, - // or at least the default loggers for tasks shouldn't do - // that - ::rt::util::dumb_println(args); + // First time logging? Get a handle to the stderr of this process. + if self.handle.is_none() { + self.handle = Some(io::stderr()); + } + fmt::writeln(self.handle.get_mut_ref() as &mut io::Writer, args); } } diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index c779be0104662..4a4ce4edcc2d6 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -97,7 +97,7 @@ pub trait IoFactory { fn unix_bind(&mut self, path: &CString) -> Result<~RtioUnixListener, IoError>; fn unix_connect(&mut self, path: &CString) -> Result<~RtioPipe, IoError>; - fn tty_open(&mut self, fd: c_int, readable: bool, close_on_drop: bool) + fn tty_open(&mut self, fd: c_int, readable: bool) -> Result<~RtioTTY, IoError>; } @@ -182,6 +182,7 @@ pub trait RtioTTY { fn write(&mut self, buf: &[u8]) -> Result<(), IoError>; fn set_raw(&mut self, raw: bool) -> Result<(), IoError>; fn get_winsize(&mut self) -> Result<(int, int), IoError>; + fn isatty(&self) -> bool; } pub trait PausibleIdleCallback { diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index c4f352501a08b..16ae28743c523 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -132,7 +132,7 @@ impl Task { heap: LocalHeap::new(), gc: GarbageCollector, storage: LocalStorage(None), - logger: StdErrLogger, + logger: StdErrLogger::new(), unwinder: Unwinder { unwinding: false }, taskgroup: None, death: Death::new(), @@ -166,7 +166,7 @@ impl Task { heap: LocalHeap::new(), gc: GarbageCollector, storage: LocalStorage(None), - logger: StdErrLogger, + logger: StdErrLogger::new(), unwinder: Unwinder { unwinding: false }, taskgroup: None, death: Death::new(), @@ -188,7 +188,7 @@ impl Task { heap: LocalHeap::new(), gc: GarbageCollector, storage: LocalStorage(None), - logger: StdErrLogger, + logger: StdErrLogger::new(), unwinder: Unwinder { unwinding: false }, taskgroup: None, // FIXME(#7544) make watching optional @@ -549,6 +549,7 @@ pub fn begin_unwind(msg: *c_char, file: *c_char, line: size_t) -> ! { use rt::logging::Logger; use str::Str; use c_str::CString; + use unstable::intrinsics; unsafe { let msg = CString::new(msg, false); @@ -557,35 +558,32 @@ pub fn begin_unwind(msg: *c_char, file: *c_char, line: size_t) -> ! { Some(s) => s, None => rtabort!("message wasn't utf8?") }; - if in_green_task_context() { - // Be careful not to allocate in this block, if we're failing we may - // have been failing due to a lack of memory in the first place... - do Local::borrow |task: &mut Task| { - let n = task.name.as_ref().map(|n| n.as_slice()).unwrap_or(""); - - match file.as_str() { - Some(file) => { - format_args!(|args| { task.logger.log(args) }, - "task '{}' failed at '{}', {}:{}", - n, msg, file, line); - } - None => { - format_args!(|args| { task.logger.log(args) }, - "task '{}' failed at '{}'", n, msg); - } - } - } - } else { + if !in_green_task_context() { match file.as_str() { Some(file) => { rterrln!("failed in non-task context at '{}', {}:{}", msg, file, line as int); } - None => rterrln!("failed in non-task context at '{}'", msg), + None => rterrln!("failed in non-task context at '{}'", msg) } + intrinsics::abort(); } + // Be careful not to allocate in this block, if we're failing we may + // have been failing due to a lack of memory in the first place... let task: *mut Task = Local::unsafe_borrow(); + let n = (*task).name.as_ref().map(|n| n.as_slice()).unwrap_or(""); + match file.as_str() { + Some(file) => { + format_args!(|args| { (*task).logger.log(args) }, + "task '{}' failed at '{}', {}:{}", + n, msg, file, line); + } + None => { + format_args!(|args| { (*task).logger.log(args) }, + "task '{}' failed at '{}'", n, msg); + } + } if (*task).unwinder.unwinding { rtabort!("unwinding again"); } diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs index 647d88c26f2f5..f15aa01db954d 100644 --- a/src/libstd/rt/util.rs +++ b/src/libstd/rt/util.rs @@ -71,9 +71,18 @@ pub fn default_sched_threads() -> uint { pub fn dumb_println(args: &fmt::Arguments) { use rt::io::native::stdio::stderr; - use rt::io::Writer; + use rt::io::{Writer, io_error, ResourceUnavailable}; let mut out = stderr(); - fmt::writeln(&mut out as &mut Writer, args); + + let mut again = true; + do io_error::cond.trap(|e| { + again = e.kind == ResourceUnavailable; + }).inside { + while again { + again = false; + fmt::writeln(&mut out as &mut Writer, args); + } + } } pub fn abort(msg: &str) -> ! { diff --git a/src/libstd/rt/uv/mod.rs b/src/libstd/rt/uv/mod.rs index a03264af7e1e9..18c9915770763 100644 --- a/src/libstd/rt/uv/mod.rs +++ b/src/libstd/rt/uv/mod.rs @@ -170,6 +170,7 @@ pub trait WatcherInterop { fn get_watcher_data<'r>(&'r mut self) -> &'r mut WatcherData; fn drop_watcher_data(&mut self); fn close(self, cb: NullCallback); + fn close_async(self); } impl> WatcherInterop for W { @@ -235,6 +236,16 @@ impl> WatcherInterop for W { unsafe { uvll::free_handle(handle as *c_void) } } } + + fn close_async(self) { + unsafe { uvll::close(self.native_handle(), close_cb); } + + extern fn close_cb(handle: *uvll::uv_handle_t) { + let mut h: Handle = NativeHandle::from_native_handle(handle); + h.drop_watcher_data(); + unsafe { uvll::free_handle(handle as *c_void) } + } + } } // XXX: Need to define the error constants like EOF so they can be diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 322588973ae77..915c7d0da528b 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -868,13 +868,13 @@ impl IoFactory for UvIoFactory { return ret; } - fn tty_open(&mut self, fd: c_int, readable: bool, close_on_drop: bool) + fn tty_open(&mut self, fd: c_int, readable: bool) -> Result<~RtioTTY, 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, + fd: fd, } as ~RtioTTY), Err(e) => Err(uv_error_to_io_error(e)) } @@ -1748,7 +1748,7 @@ impl RtioUnixListener for UvUnixListener { pub struct UvTTY { tty: tty::TTY, home: SchedHandle, - close_on_drop: bool, + fd: c_int, } impl HomingIO for UvTTY { @@ -1757,20 +1757,48 @@ impl HomingIO for UvTTY { 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()); - } + // TTY handles are used for the logger in a task, so this destructor is + // run when a task is destroyed. When a task is being destroyed, a local + // scheduler isn't available, so we can't do the normal "take the + // scheduler and resume once close is done". Instead close operations on + // a TTY are asynchronous. + + self.tty.close_async(); + } +} + +impl RtioTTY for UvTTY { + fn read(&mut self, buf: &mut [u8]) -> Result { + 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)) } - } else { - self.tty.drop_watcher_data(); - unsafe { uvll::free_handle(self.tty.native_handle()) } } } + + 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)) + } + } + } + + fn isatty(&self) -> bool { + unsafe { uvll::guess_handle(self.fd) == uvll::UV_TTY } + } } pub struct UvUnixAcceptor { @@ -1808,36 +1836,6 @@ impl RtioUnixAcceptor for UvUnixAcceptor { } } -impl RtioTTY for UvTTY { - fn read(&mut self, buf: &mut [u8]) -> Result { - 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 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)) - } - } - } -} - // this function is full of lies unsafe fn local_io() -> &'static mut IoFactory { do Local::borrow |sched: &mut Scheduler| { diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index e78b2579779f9..8f8aea9d12169 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -986,6 +986,10 @@ pub unsafe fn tty_get_winsize(tty: *uv_tty_t, width: *c_int, #[fixed_stack_segment]; #[inline(never)]; rust_uv_tty_get_winsize(tty, width, height) } +pub unsafe fn guess_handle(fd: c_int) -> uv_handle_type { + #[fixed_stack_segment]; #[inline(never)]; + rust_uv_guess_handle(fd) +} pub struct uv_err_data { priv err_name: ~str, @@ -1140,6 +1144,7 @@ extern { fn rust_uv_tty_set_mode(tty: *uv_tty_t, mode: c_int) -> c_int; fn rust_uv_tty_get_winsize(tty: *uv_tty_t, width: *c_int, height: *c_int) -> c_int; + fn rust_uv_guess_handle(fd: c_int) -> uv_handle_type; // These should all really be constants... #[rust_stack] pub fn rust_SOCK_STREAM() -> c_int; diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index a47b3446d3442..7ab57e6909aa7 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -681,3 +681,8 @@ extern "C" int rust_uv_tty_get_winsize(uv_tty_t *tty, int *width, int *height) { return uv_tty_get_winsize(tty, width, height); } + +extern "C" uv_handle_type +rust_uv_guess_handle(int fd) { + return uv_guess_handle(fd); +} diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 58862da31db5c..6c3988d6b0152 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -217,3 +217,4 @@ rust_uv_pipe_connect rust_uv_tty_init rust_uv_tty_set_mode rust_uv_tty_get_winsize +rust_uv_guess_handle From 61ed2cfb5516f76487509766b1054275f1340f70 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 13 Oct 2013 18:48:47 -0700 Subject: [PATCH 12/23] Remove even more of std::io Big fish fried here: extra::json most of the compiler extra::io_util removed extra::fileinput removed Fish left to fry extra::ebml --- src/compiletest/runtest.rs | 52 +- src/compiletest/util.rs | 3 +- src/etc/combine-tests.py | 8 +- src/libextra/extra.rs | 2 - src/libextra/fileinput.rs | 629 ------------------ src/libextra/io_util.rs | 70 -- src/libextra/json.rs | 192 +++--- src/libextra/semver.rs | 65 +- src/libextra/stats.rs | 57 +- src/libextra/term.rs | 10 +- src/libextra/test.rs | 145 ++-- src/libextra/time.rs | 133 ++-- src/libextra/url.rs | 294 ++++---- src/libextra/workcache.rs | 48 +- src/librustc/back/link.rs | 3 +- src/librustc/driver/driver.rs | 26 +- src/librustc/metadata/decoder.rs | 36 +- src/librustc/metadata/encoder.rs | 2 +- src/librustc/metadata/loader.rs | 6 +- src/librustc/middle/borrowck/mod.rs | 3 +- src/librustc/middle/dataflow.rs | 6 +- src/librustc/middle/liveness.rs | 26 +- src/librustc/middle/trans/base.rs | 5 +- src/librustc/rustc.rs | 9 +- src/librustdoc/rustdoc.rs | 17 +- src/librustpkg/context.rs | 18 +- src/librustpkg/messages.rs | 23 +- src/librustpkg/rustpkg.rs | 6 +- src/librustpkg/source_control.rs | 10 +- .../fail/src/no-inferred-crates/src/zzyzx.rs | 4 +- .../testsuite/pass/src/hello-world/main.rs | 4 +- src/librustpkg/usage.rs | 26 +- src/librustpkg/workcache_support.rs | 24 +- src/libstd/io.rs | 384 +---------- src/libstd/os.rs | 59 -- src/libsyntax/ast_util.rs | 3 +- src/libsyntax/diagnostic.rs | 38 +- src/libsyntax/ext/expand.rs | 33 +- src/libsyntax/ext/log_syntax.rs | 4 +- src/libsyntax/ext/source_util.rs | 51 +- src/libsyntax/parse/comments.rs | 7 +- src/libsyntax/parse/mod.rs | 52 +- src/libsyntax/print/pp.rs | 14 +- src/libsyntax/print/pprust.rs | 57 +- src/test/bench/core-map.rs | 17 +- src/test/bench/core-set.rs | 6 +- src/test/bench/msgsend-pipes-shared.rs | 7 +- src/test/bench/msgsend-pipes.rs | 7 +- src/test/bench/shootout-chameneos-redux.rs | 11 +- src/test/bench/shootout-fasta.rs | 24 +- src/test/bench/shootout-k-nucleotide-pipes.rs | 4 +- src/test/bench/shootout-pfib.rs | 7 +- src/test/bench/std-smallintmap.rs | 10 +- src/test/bench/sudoku.rs | 11 +- src/test/compile-fail/issue-5060-fail.rs | 12 +- src/test/compile-fail/issue-5883.rs | 6 +- src/test/compile-fail/issue-7573.rs | 4 +- src/test/compile-fail/lint-unused-imports.rs | 16 +- src/test/run-fail/issue-2156.rs | 24 - .../run-pass/auto-ref-bounded-ty-param.rs | 4 +- src/test/run-pass/expr-repeat-vstore.rs | 2 - src/test/run-pass/issue-2904.rs | 20 +- src/test/run-pass/issue-3556.rs | 6 +- src/test/run-pass/issue-3559.rs | 4 +- src/test/run-pass/issue-3563-3.rs | 4 +- src/test/run-pass/issue-4333.rs | 6 +- src/test/run-pass/issue-4541.rs | 4 +- src/test/run-pass/issue-5060.rs | 12 +- src/test/run-pass/issue-5741.rs | 4 +- src/test/run-pass/issue-8498.rs | 9 +- .../run-pass/match-drop-strs-issue-4541.rs | 3 +- ...nomorphized-callees-with-ty-params-3314.rs | 14 +- src/test/run-pass/new-import-syntax.rs | 2 - src/test/run-pass/new-style-constants.rs | 2 - src/test/run-pass/stat.rs | 14 +- .../trait-static-method-overwriting.rs | 4 +- 76 files changed, 916 insertions(+), 2028 deletions(-) delete mode 100644 src/libextra/fileinput.rs delete mode 100644 src/libextra/io_util.rs delete mode 100644 src/test/run-fail/issue-2156.rs diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index d02b88ae74e5f..4ae9ad81daff6 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -21,7 +21,10 @@ use util; use util::logv; use std::cell::Cell; -use std::io; +use std::rt::io; +use std::rt::io::Writer; +use std::rt::io::extensions::ReaderUtil; +use std::rt::io::file::FileInfo; use std::os; use std::str; use std::task::{spawn_sched, SingleThreaded}; @@ -60,7 +63,7 @@ pub fn run(config: config, testfile: ~str) { pub fn run_metrics(config: config, testfile: ~str, mm: &mut MetricMap) { if config.verbose { // We're going to be dumping a lot of info. Start on a new line. - io::stdout().write_str("\n\n"); + print!("\n\n"); } let testfile = Path::new(testfile); debug!("running {}", testfile.display()); @@ -170,7 +173,9 @@ fn run_pretty_test(config: &config, props: &TestProps, testfile: &Path) { let rounds = match props.pp_exact { Some(_) => 1, None => 2 }; - let mut srcs = ~[io::read_whole_file_str(testfile).unwrap()]; + let src = testfile.open_reader(io::Open).read_to_end(); + let src = str::from_utf8_owned(src); + let mut srcs = ~[src]; let mut round = 0; while round < rounds { @@ -190,7 +195,8 @@ fn run_pretty_test(config: &config, props: &TestProps, testfile: &Path) { let mut expected = match props.pp_exact { Some(ref file) => { let filepath = testfile.dir_path().join(file); - io::read_whole_file_str(&filepath).unwrap() + let s = filepath.open_reader(io::Open).read_to_end(); + str::from_utf8_owned(s) } None => { srcs[srcs.len() - 2u].clone() } }; @@ -228,8 +234,7 @@ fn run_pretty_test(config: &config, props: &TestProps, testfile: &Path) { fn compare_source(expected: &str, actual: &str) { if expected != actual { error(~"pretty-printed source does not match expected source"); - let msg = - format!("\n\ + println!("\n\ expected:\n\ ------------------------------------------\n\ {}\n\ @@ -240,7 +245,6 @@ actual:\n\ ------------------------------------------\n\ \n", expected, actual); - io::stdout().write_str(msg); fail!(); } } @@ -741,9 +745,7 @@ fn dump_output(config: &config, testfile: &Path, out: &str, err: &str) { fn dump_output_file(config: &config, testfile: &Path, out: &str, extension: &str) { let outfile = make_out_name(config, testfile, extension); - let writer = - io::file_writer(&outfile, [io::Create, io::Truncate]).unwrap(); - writer.write_str(out); + outfile.open_writer(io::CreateOrTruncate).write(out.as_bytes()); } fn make_out_name(config: &config, testfile: &Path, extension: &str) -> Path { @@ -771,24 +773,20 @@ fn output_base_name(config: &config, testfile: &Path) -> Path { fn maybe_dump_to_stdout(config: &config, out: &str, err: &str) { if config.verbose { - let sep1 = format!("------{}------------------------------", "stdout"); - let sep2 = format!("------{}------------------------------", "stderr"); - let sep3 = ~"------------------------------------------"; - io::stdout().write_line(sep1); - io::stdout().write_line(out); - io::stdout().write_line(sep2); - io::stdout().write_line(err); - io::stdout().write_line(sep3); + println!("------{}------------------------------", "stdout"); + println!("{}", out); + println!("------{}------------------------------", "stderr"); + println!("{}", err); + println!("------------------------------------------"); } } -fn error(err: ~str) { io::stdout().write_line(format!("\nerror: {}", err)); } +fn error(err: ~str) { println!("\nerror: {}", err); } fn fatal(err: ~str) -> ! { error(err); fail!(); } fn fatal_ProcRes(err: ~str, ProcRes: &ProcRes) -> ! { - let msg = - format!("\n\ + print!("\n\ error: {}\n\ command: {}\n\ stdout:\n\ @@ -801,7 +799,6 @@ stderr:\n\ ------------------------------------------\n\ \n", err, ProcRes.cmdline, ProcRes.stdout, ProcRes.stderr); - io::stdout().write_str(msg); fail!(); } @@ -821,9 +818,9 @@ fn _arm_exec_compiled_test(config: &config, props: &TestProps, ~[(~"",~"")], Some(~"")); if config.verbose { - io::stdout().write_str(format!("push ({}) {} {} {}", + println!("push ({}) {} {} {}", config.target, args.prog, - copy_result.out, copy_result.err)); + copy_result.out, copy_result.err); } logv(config, format!("executing ({}) {}", config.target, cmdline)); @@ -913,9 +910,9 @@ fn _arm_push_aux_shared_library(config: &config, testfile: &Path) { ~[(~"",~"")], Some(~"")); if config.verbose { - io::stdout().write_str(format!("push ({}) {} {} {}", + println!("push ({}) {} {} {}", config.target, file.display(), - copy_result.out, copy_result.err)); + copy_result.out, copy_result.err); } } } @@ -999,7 +996,8 @@ fn disassemble_extract(config: &config, _props: &TestProps, fn count_extracted_lines(p: &Path) -> uint { - let x = io::read_whole_file_str(&p.with_extension("ll")).unwrap(); + let x = p.with_extension("ll").open_reader(io::Open).read_to_end(); + let x = str::from_utf8_owned(x); x.line_iter().len() } diff --git a/src/compiletest/util.rs b/src/compiletest/util.rs index 04ef180299daf..ae4a25b80084c 100644 --- a/src/compiletest/util.rs +++ b/src/compiletest/util.rs @@ -10,7 +10,6 @@ use common::config; -use std::io; use std::os::getenv; /// Conversion table from triple OS name to Rust SYSNAME @@ -64,5 +63,5 @@ pub fn path_div() -> ~str { ~";" } pub fn logv(config: &config, s: ~str) { debug!("{}", s); - if config.verbose { io::println(s); } + if config.verbose { println(s); } } diff --git a/src/etc/combine-tests.py b/src/etc/combine-tests.py index 25976410c7c9c..dc5e11dabdf68 100755 --- a/src/etc/combine-tests.py +++ b/src/etc/combine-tests.py @@ -56,15 +56,15 @@ def scrub(b): d.write("extern mod extra;\n") d.write("extern mod run_pass_stage2;\n") d.write("use run_pass_stage2::*;\n") -d.write("use std::io::WriterUtil;\n"); -d.write("use std::io;\n"); +d.write("use std::rt::io;\n"); +d.write("use std::rt::io::Writer;\n"); d.write("fn main() {\n"); -d.write(" let out = io::stdout();\n"); +d.write(" let mut out = io::stdout();\n"); i = 0 for t in stage2_tests: p = os.path.join("test", "run-pass", t) p = p.replace("\\", "\\\\") - d.write(" out.write_str(\"run-pass [stage2]: %s\\n\");\n" % p) + d.write(" out.write(\"run-pass [stage2]: %s\\n\".as_bytes());\n" % p) d.write(" t_%d::main();\n" % i) i += 1 d.write("}\n") diff --git a/src/libextra/extra.rs b/src/libextra/extra.rs index 79a5b555c291f..3ea164fb456f8 100644 --- a/src/libextra/extra.rs +++ b/src/libextra/extra.rs @@ -45,7 +45,6 @@ pub use std::os; // Utility modules pub mod c_vec; -pub mod io_util; // Concurrency @@ -104,7 +103,6 @@ pub mod rational; pub mod complex; pub mod stats; pub mod semver; -pub mod fileinput; pub mod flate; pub mod hex; pub mod uuid; diff --git a/src/libextra/fileinput.rs b/src/libextra/fileinput.rs deleted file mode 100644 index 49072dab6d025..0000000000000 --- a/src/libextra/fileinput.rs +++ /dev/null @@ -1,629 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! -A library for iterating through the lines in a series of -files. Very similar to [the Python module of the same -name](http://docs.python.org/3.3/library/fileinput.html). - -It allows the programmer to automatically take filenames from the -command line arguments (via `input` and `input_state`), as well as -specify them as a vector directly (`input_vec` and -`input_vec_state`). The files are opened as necessary, so any files -that can't be opened only cause an error when reached in the -iteration. - -On the command line, `stdin` is represented by a filename of `-` (a -single hyphen) and in the functions that take a vector directly -(e.g. `input_vec`) it is represented by `None`. Note `stdin` is *not* -reset once it has been finished, so attempting to iterate on `[None, -None]` will only take input once unless `io::stdin().seek(0, SeekSet)` -is called between. - -The `make_path_option_vec` function handles converting a list of file paths as -strings to the appropriate format, including the (optional) conversion -of `"-"` to `stdin`. - -# Basic - -In many cases, one can use the `input_*` functions without having -to handle any `FileInput` structs. E.g. a simple `cat` program - - for input |line| { - io::println(line) - } - -or a program that numbers lines after concatenating two files - - for input_vec_state(make_path_option_vec([~"a.txt", ~"b.txt"])) |line, state| { - io::println(format!("{}: %s", state.line_num, - line)); - } - -The two `input_vec*` functions take a vec of file names (where empty -means read from `stdin`), the other two functions use the command line -arguments. - -# Advanced - -For more complicated uses (e.g. if one needs to pause iteration and -resume it later), a `FileInput` instance can be constructed via the -`from_vec`, `from_vec_raw` and `from_args` functions. - -Once created, the `each_line` (from the `std::io::ReaderUtil` trait) -and `each_line_state` methods allow one to iterate on the lines; the -latter provides more information about the position within the -iteration to the caller. - -It is possible (and safe) to skip lines and files using the -`read_line` and `next_file` methods. Also, `FileInput` implements -`std::io::Reader`, and the state will be updated correctly while -using any of those methods. - -E.g. the following program reads until an empty line, pauses for user -input, skips the current file and then numbers the remaining lines -(where the numbers are from the start of each file, rather than the -total line count). - - let input = FileInput::from_vec(pathify([~"a.txt", ~"b.txt", ~"c.txt"], - true)); - - for input.each_line |line| { - if line.is_empty() { - break - } - io::println(line); - } - - io::println("Continue?"); - - if io::stdin().read_line() == ~"yes" { - input.next_file(); // skip! - - for input.each_line_state |line, state| { - io::println(format!("{}: %s", state.line_num_file, - line)) - } - } -*/ - -#[allow(missing_doc)]; - - -use std::io::ReaderUtil; -use std::io; -use std::os; - -/** -A summary of the internal state of a `FileInput` object. `line_num` -and `line_num_file` represent the number of lines read in total and in -the current file respectively. `current_path` is `None` if the current -file is `stdin`. -*/ -#[deriving(Clone)] -pub struct FileInputState { - current_path: Option, - line_num: uint, - line_num_file: uint -} - -impl FileInputState { - fn is_stdin(&self) -> bool { - self.current_path.is_none() - } - - fn is_first_line(&self) -> bool { - self.line_num_file == 1 - } -} - -struct FileInput_ { - /** - `Some(path)` is the file represented by `path`, `None` is - `stdin`. Consumed as the files are read. - */ - files: ~[Option], - /** - The current file: `Some(r)` for an open file, `None` before - starting and after reading everything. - */ - current_reader: Option<@io::Reader>, - state: FileInputState, - - /** - Used to keep track of whether we need to insert the newline at the - end of a file that is missing it, which is needed to separate the - last and first lines. - */ - previous_was_newline: bool -} - - -// FIXME #5723: remove this when Reader has &mut self. -// Removing it would mean giving read_byte in the Reader impl for -// FileInput &mut self, which in turn means giving most of the -// io::Reader trait methods &mut self. That can't be done right now -// because of io::with_bytes_reader and #5723. -// Should be removable via -// "self.fi" -> "self." and renaming FileInput_. Documentation above -// will likely have to be updated to use `let mut in = ...`. -pub struct FileInput { - priv fi: @mut FileInput_ -} - -impl FileInput { - /** - Create a `FileInput` object from a vec of files. An empty - vec means lines are read from `stdin` (use `from_vec_raw` to stop - this behaviour). Any occurrence of `None` represents `stdin`. - */ - pub fn from_vec(files: ~[Option]) -> FileInput { - FileInput::from_vec_raw( - if files.is_empty() { - ~[None] - } else { - files - }) - } - - /** - Identical to `from_vec`, but an empty `files` vec stays - empty. (`None` is `stdin`.) - */ - pub fn from_vec_raw(files: ~[Option]) - -> FileInput { - FileInput{ - fi: @mut FileInput_ { - files: files, - current_reader: None, - state: FileInputState { - current_path: None, - line_num: 0, - line_num_file: 0 - }, - // there was no previous unended line - previous_was_newline: true - } - } - } - - /** - Create a `FileInput` object from the command line - arguments. `"-"` represents `stdin`. - */ - pub fn from_args() -> FileInput { - let args = os::args(); - let pathed = make_path_option_vec(args.tail(), true); - FileInput::from_vec(pathed) - } - - fn current_file_eof(&self) -> bool { - match self.fi.current_reader { - None => false, - Some(r) => r.eof() - } - } - - /** - Skip to the next file in the queue. Can `fail` when opening - a file. - - Returns `false` if there is no more files, and `true` when it - successfully opens the next file. - */ - - pub fn next_file(&self) -> bool { - // No more files - - if self.fi.files.is_empty() { - self.fi.current_reader = None; - return false; - } - - let path_option = self.fi.files.shift(); - let file = match path_option { - None => io::stdin(), - Some(ref path) => io::file_reader(path).unwrap() - }; - - self.fi.current_reader = Some(file); - self.fi.state.current_path = path_option; - self.fi.state.line_num_file = 0; - true - } - - /** - Attempt to open the next file if there is none currently open, - or if the current one is EOF'd. - - Returns `true` if it had to move to the next file and did - so successfully. - */ - fn next_file_if_eof(&self) -> bool { - match self.fi.current_reader { - None => self.next_file(), - Some(r) => { - if r.eof() { - self.next_file() - } else { - false - } - } - } - } - - /** - Apply `f` to each line successively, along with some state - (line numbers and file names, see documentation for - `FileInputState`). Otherwise identical to `lines_each`. - */ - pub fn each_line_state(&self, - f: &fn(&str, FileInputState) -> bool) -> bool { - self.each_line(|line| f(line, self.fi.state.clone())) - } - - - /** - Retrieve the current `FileInputState` information. - */ - pub fn state(&self) -> FileInputState { - self.fi.state.clone() - } -} - -impl io::Reader for FileInput { - fn read_byte(&self) -> int { - loop { - let stepped = self.next_file_if_eof(); - - // if we moved to the next file, and the previous - // character wasn't \n, then there is an unfinished line - // from the previous file. This library models - // line-by-line processing and the trailing line of the - // previous file and the leading of the current file - // should be considered different, so we need to insert a - // fake line separator - if stepped && !self.fi.previous_was_newline { - self.fi.state.line_num += 1; - self.fi.state.line_num_file += 1; - self.fi.previous_was_newline = true; - return '\n' as int; - } - - match self.fi.current_reader { - None => return -1, - Some(r) => { - let b = r.read_byte(); - - if b < 0 { - continue; - } - - if b == '\n' as int { - self.fi.state.line_num += 1; - self.fi.state.line_num_file += 1; - self.fi.previous_was_newline = true; - } else { - self.fi.previous_was_newline = false; - } - - return b; - } - } - } - } - fn read(&self, buf: &mut [u8], len: uint) -> uint { - let mut count = 0; - while count < len { - let b = self.read_byte(); - if b < 0 { break } - - buf[count] = b as u8; - count += 1; - } - - count - } - fn eof(&self) -> bool { - // we've run out of files, and current_reader is either None or eof. - - self.fi.files.is_empty() && - match self.fi.current_reader { None => true, Some(r) => r.eof() } - - } - fn seek(&self, offset: int, whence: io::SeekStyle) { - match self.fi.current_reader { - None => {}, - Some(r) => r.seek(offset, whence) - } - } - fn tell(&self) -> uint { - match self.fi.current_reader { - None => 0, - Some(r) => r.tell() - } - } -} - -/** -Convert a list of strings to an appropriate form for a `FileInput` -instance. `stdin_hyphen` controls whether `-` represents `stdin` or -a literal `-`. -*/ -pub fn make_path_option_vec(vec: &[~str], stdin_hyphen : bool) -> ~[Option] { - vec.iter().map(|s| { - if stdin_hyphen && "-" == *s { - None - } else { - Some(Path::new(s.as_slice())) - } - }).collect() -} - -/** -Iterate directly over the command line arguments (no arguments implies -reading from `stdin`). - -Fails when attempting to read from a file that can't be opened. -*/ -pub fn input(f: &fn(&str) -> bool) -> bool { - let i = FileInput::from_args(); - i.each_line(f) -} - -/** -Iterate directly over the command line arguments (no arguments -implies reading from `stdin`) with the current state of the iteration -provided at each call. - -Fails when attempting to read from a file that can't be opened. -*/ -pub fn input_state(f: &fn(&str, FileInputState) -> bool) -> bool { - let i = FileInput::from_args(); - i.each_line_state(f) -} - -/** -Iterate over a vector of files (an empty vector implies just `stdin`). - -Fails when attempting to read from a file that can't be opened. -*/ -pub fn input_vec(files: ~[Option], f: &fn(&str) -> bool) -> bool { - let i = FileInput::from_vec(files); - i.each_line(f) -} - -/** -Iterate over a vector of files (an empty vector implies just `stdin`) -with the current state of the iteration provided at each call. - -Fails when attempting to read from a file that can't be opened. -*/ -pub fn input_vec_state(files: ~[Option], - f: &fn(&str, FileInputState) -> bool) -> bool { - let i = FileInput::from_vec(files); - i.each_line_state(f) -} - -#[cfg(test)] -mod test { - - use super::{FileInput, make_path_option_vec, input_vec, input_vec_state}; - - use std::rt::io; - use std::rt::io::Writer; - use std::rt::io::file; - use std::vec; - - fn make_file(path : &Path, contents: &[~str]) { - let mut file = file::open(path, io::CreateOrTruncate, io::Write).unwrap(); - - for str in contents.iter() { - file.write(str.as_bytes()); - file.write(['\n' as u8]); - } - } - - #[test] - fn test_make_path_option_vec() { - let strs = [~"some/path", - ~"some/other/path"]; - let paths = ~[Some(Path::new("some/path")), - Some(Path::new("some/other/path"))]; - - assert_eq!(make_path_option_vec(strs, true), paths.clone()); - assert_eq!(make_path_option_vec(strs, false), paths); - - assert_eq!(make_path_option_vec([~"-"], true), ~[None]); - assert_eq!(make_path_option_vec([~"-"], false), ~[Some(Path::new("-"))]); - } - - #[test] - fn test_fileinput_read_byte() { - let filenames = make_path_option_vec(vec::from_fn( - 3, - |i| format!("tmp/lib-fileinput-test-fileinput-read-byte-{}.tmp", i)), true); - - // 3 files containing 0\n, 1\n, and 2\n respectively - for (i, filename) in filenames.iter().enumerate() { - make_file(filename.get_ref(), [format!("{}", i)]); - } - - let fi = FileInput::from_vec(filenames.clone()); - - for (line, c) in "012".iter().enumerate() { - assert_eq!(fi.read_byte(), c as int); - assert_eq!(fi.state().line_num, line); - assert_eq!(fi.state().line_num_file, 0); - assert_eq!(fi.read_byte(), '\n' as int); - assert_eq!(fi.state().line_num, line + 1); - assert_eq!(fi.state().line_num_file, 1); - - assert_eq!(fi.state().current_path.clone(), filenames[line].clone()); - } - - assert_eq!(fi.read_byte(), -1); - assert!(fi.eof()); - assert_eq!(fi.state().line_num, 3) - - } - - #[test] - fn test_fileinput_read() { - let filenames = make_path_option_vec(vec::from_fn( - 3, - |i| format!("tmp/lib-fileinput-test-fileinput-read-{}.tmp", i)), true); - - // 3 files containing 1\n, 2\n, and 3\n respectively - for (i, filename) in filenames.iter().enumerate() { - make_file(filename.get_ref(), [format!("{}", i)]); - } - - let fi = FileInput::from_vec(filenames); - let mut buf : ~[u8] = vec::from_elem(6, 0u8); - let count = fi.read(buf, 10); - assert_eq!(count, 6); - assert_eq!(buf, "0\n1\n2\n".as_bytes().to_owned()); - assert!(fi.eof()) - assert_eq!(fi.state().line_num, 3); - } - - #[test] - fn test_input_vec() { - let mut all_lines = ~[]; - let filenames = make_path_option_vec(vec::from_fn( - 3, - |i| format!("tmp/lib-fileinput-test-input-vec-{}.tmp", i)), true); - - for (i, filename) in filenames.iter().enumerate() { - let contents = - vec::from_fn(3, |j| format!("{} {}", i, j)); - make_file(filename.get_ref(), contents); - debug!("contents={:?}", contents); - all_lines.push_all(contents); - } - - let mut read_lines = ~[]; - do input_vec(filenames) |line| { - read_lines.push(line.to_owned()); - true - }; - assert_eq!(read_lines, all_lines); - } - - #[test] - fn test_input_vec_state() { - let filenames = make_path_option_vec(vec::from_fn( - 3, - |i| format!("tmp/lib-fileinput-test-input-vec-state-{}.tmp", i)),true); - - for (i, filename) in filenames.iter().enumerate() { - let contents = - vec::from_fn(3, |j| format!("{} {}", i, j + 1)); - make_file(filename.get_ref(), contents); - } - - do input_vec_state(filenames) |line, state| { - let nums: ~[&str] = line.split_iter(' ').collect(); - let file_num = from_str::(nums[0]).unwrap(); - let line_num = from_str::(nums[1]).unwrap(); - assert_eq!(line_num, state.line_num_file); - assert_eq!(file_num * 3 + line_num, state.line_num); - true - }; - } - - #[test] - fn test_empty_files() { - let filenames = make_path_option_vec(vec::from_fn( - 3, - |i| format!("tmp/lib-fileinput-test-empty-files-{}.tmp", i)),true); - - make_file(filenames[0].get_ref(), [~"1", ~"2"]); - make_file(filenames[1].get_ref(), []); - make_file(filenames[2].get_ref(), [~"3", ~"4"]); - - let mut count = 0; - do input_vec_state(filenames.clone()) |line, state| { - let expected_path = match line { - "1" | "2" => filenames[0].clone(), - "3" | "4" => filenames[2].clone(), - _ => fail!("unexpected line") - }; - assert_eq!(state.current_path.clone(), expected_path); - count += 1; - true - }; - assert_eq!(count, 4); - } - - #[test] - fn test_no_trailing_newline() { - let f1 = - Some(Path::new("tmp/lib-fileinput-test-no-trailing-newline-1.tmp")); - let f2 = - Some(Path::new("tmp/lib-fileinput-test-no-trailing-newline-2.tmp")); - - { - let mut wr = file::open(f1.get_ref(), io::CreateOrTruncate, - io::Write).unwrap(); - wr.write("1\n2".as_bytes()); - let mut wr = file::open(f2.get_ref(), io::CreateOrTruncate, - io::Write).unwrap(); - wr.write("3\n4".as_bytes()); - } - - let mut lines = ~[]; - do input_vec(~[f1, f2]) |line| { - lines.push(line.to_owned()); - true - }; - assert_eq!(lines, ~[~"1", ~"2", ~"3", ~"4"]); - } - - - #[test] - fn test_next_file() { - let filenames = make_path_option_vec(vec::from_fn( - 3, - |i| format!("tmp/lib-fileinput-test-next-file-{}.tmp", i)),true); - - for (i, filename) in filenames.iter().enumerate() { - let contents = vec::from_fn(3, |j| format!("{} {}", i, j + 1)); - make_file(filename.get_ref(), contents); - } - - let input = FileInput::from_vec(filenames); - - // read once from 0 - assert_eq!(input.read_line(), ~"0 1"); - input.next_file(); // skip the rest of 1 - - // read all lines from 1 (but don't read any from 2), - for i in range(1u, 4) { - assert_eq!(input.read_line(), format!("1 {}", i)); - } - // 1 is finished, but 2 hasn't been started yet, so this will - // just "skip" to the beginning of 2 (Python's fileinput does - // the same) - input.next_file(); - - assert_eq!(input.read_line(), ~"2 1"); - } - - #[test] - #[should_fail] - fn test_input_vec_missing_file() { - do input_vec(make_path_option_vec([~"this/file/doesnt/exist"], true)) |line| { - println(line); - true - }; - } -} diff --git a/src/libextra/io_util.rs b/src/libextra/io_util.rs deleted file mode 100644 index 27a09be3a625b..0000000000000 --- a/src/libextra/io_util.rs +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[allow(missing_doc)]; - -use std::io::{Reader, BytesReader}; -use std::io; -use std::cast; - -/// An implementation of the io::Reader interface which reads a buffer of bytes -pub struct BufReader { - /// The buffer of bytes to read - priv buf: ~[u8], - /// The current position in the buffer of bytes - priv pos: @mut uint -} - -impl BufReader { - /// Creates a new buffer reader for the specified buffer - pub fn new(v: ~[u8]) -> BufReader { - BufReader { - buf: v, - pos: @mut 0 - } - } - - fn as_bytes_reader(&self, f: &fn(&BytesReader) -> A) -> A { - // FIXME(#5723) - let bytes = ::std::util::id::<&[u8]>(self.buf); - let bytes: &'static [u8] = unsafe { cast::transmute(bytes) }; - // Recreating the BytesReader state every call since - // I can't get the borrowing to work correctly - let bytes_reader = BytesReader { - bytes: bytes, - pos: @mut *self.pos - }; - - let res = f(&bytes_reader); - - // FIXME #4429: This isn't correct if f fails - *self.pos = *bytes_reader.pos; - - return res; - } -} - -impl Reader for BufReader { - fn read(&self, bytes: &mut [u8], len: uint) -> uint { - self.as_bytes_reader(|r| r.read(bytes, len) ) - } - fn read_byte(&self) -> int { - self.as_bytes_reader(|r| r.read_byte() ) - } - fn eof(&self) -> bool { - self.as_bytes_reader(|r| r.eof() ) - } - fn seek(&self, offset: int, whence: io::SeekStyle) { - self.as_bytes_reader(|r| r.seek(offset, whence) ) - } - fn tell(&self) -> uint { - self.as_bytes_reader(|r| r.tell() ) - } -} diff --git a/src/libextra/json.rs b/src/libextra/json.rs index 90260282e4b5b..0aab7b743ba73 100644 --- a/src/libextra/json.rs +++ b/src/libextra/json.rs @@ -20,8 +20,10 @@ use std::char; use std::cast::transmute; use std::f64; use std::hashmap::HashMap; -use std::io::WriterUtil; -use std::io; +use std::rt::io; +use std::rt::io::Decorator; +use std::rt::io::extensions::ReaderUtil; +use std::rt::io::mem::MemWriter; use std::num; use std::str; use std::to_str; @@ -86,19 +88,17 @@ fn spaces(n: uint) -> ~str { /// A structure for implementing serialization to JSON. pub struct Encoder { - priv wr: @io::Writer, + priv wr: @mut io::Writer, } /// Creates a new JSON encoder whose output will be written to the writer /// specified. -pub fn Encoder(wr: @io::Writer) -> Encoder { - Encoder { - wr: wr - } +pub fn Encoder(wr: @mut io::Writer) -> Encoder { + Encoder { wr: wr } } impl serialize::Encoder for Encoder { - fn emit_nil(&mut self) { self.wr.write_str("null") } + fn emit_nil(&mut self) { write!(self.wr, "null") } fn emit_uint(&mut self, v: uint) { self.emit_f64(v as f64); } fn emit_u64(&mut self, v: u64) { self.emit_f64(v as f64); } @@ -114,17 +114,21 @@ impl serialize::Encoder for Encoder { fn emit_bool(&mut self, v: bool) { if v { - self.wr.write_str("true"); + write!(self.wr, "true"); } else { - self.wr.write_str("false"); + write!(self.wr, "false"); } } - fn emit_f64(&mut self, v: f64) { self.wr.write_str(f64::to_str_digits(v, 6u)) } + fn emit_f64(&mut self, v: f64) { + write!(self.wr, "{}", f64::to_str_digits(v, 6u)) + } fn emit_f32(&mut self, v: f32) { self.emit_f64(v as f64); } fn emit_char(&mut self, v: char) { self.emit_str(str::from_char(v)) } - fn emit_str(&mut self, v: &str) { self.wr.write_str(escape_str(v)) } + fn emit_str(&mut self, v: &str) { + write!(self.wr, "{}", escape_str(v)) + } fn emit_enum(&mut self, _name: &str, f: &fn(&mut Encoder)) { f(self) } @@ -137,23 +141,19 @@ impl serialize::Encoder for Encoder { // Bunny => "Bunny" // Kangaroo(34,"William") => {"variant": "Kangaroo", "fields": [34,"William"]} if cnt == 0 { - self.wr.write_str(escape_str(name)); + write!(self.wr, "{}", escape_str(name)); } else { - self.wr.write_char('{'); - self.wr.write_str("\"variant\""); - self.wr.write_char(':'); - self.wr.write_str(escape_str(name)); - self.wr.write_char(','); - self.wr.write_str("\"fields\""); - self.wr.write_str(":["); + write!(self.wr, "\\{\"variant\":"); + write!(self.wr, "{}", escape_str(name)); + write!(self.wr, ",\"fields\":["); f(self); - self.wr.write_str("]}"); + write!(self.wr, "]\\}"); } } fn emit_enum_variant_arg(&mut self, idx: uint, f: &fn(&mut Encoder)) { if idx != 0 { - self.wr.write_char(','); + write!(self.wr, ","); } f(self); } @@ -174,18 +174,17 @@ impl serialize::Encoder for Encoder { } fn emit_struct(&mut self, _: &str, _: uint, f: &fn(&mut Encoder)) { - self.wr.write_char('{'); + write!(self.wr, r"\{"); f(self); - self.wr.write_char('}'); + write!(self.wr, r"\}"); } fn emit_struct_field(&mut self, name: &str, idx: uint, f: &fn(&mut Encoder)) { - if idx != 0 { self.wr.write_char(','); } - self.wr.write_str(escape_str(name)); - self.wr.write_char(':'); + if idx != 0 { write!(self.wr, ",") } + write!(self.wr, "{}:", escape_str(name)); f(self); } @@ -211,31 +210,31 @@ impl serialize::Encoder for Encoder { fn emit_option_some(&mut self, f: &fn(&mut Encoder)) { f(self); } fn emit_seq(&mut self, _len: uint, f: &fn(&mut Encoder)) { - self.wr.write_char('['); + write!(self.wr, "["); f(self); - self.wr.write_char(']'); + write!(self.wr, "]"); } fn emit_seq_elt(&mut self, idx: uint, f: &fn(&mut Encoder)) { if idx != 0 { - self.wr.write_char(','); + write!(self.wr, ","); } f(self) } fn emit_map(&mut self, _len: uint, f: &fn(&mut Encoder)) { - self.wr.write_char('{'); + write!(self.wr, r"\{"); f(self); - self.wr.write_char('}'); + write!(self.wr, r"\}"); } fn emit_map_elt_key(&mut self, idx: uint, f: &fn(&mut Encoder)) { - if idx != 0 { self.wr.write_char(','); } + if idx != 0 { write!(self.wr, ",") } f(self) } fn emit_map_elt_val(&mut self, _idx: uint, f: &fn(&mut Encoder)) { - self.wr.write_char(':'); + write!(self.wr, ":"); f(self) } } @@ -243,12 +242,12 @@ impl serialize::Encoder for Encoder { /// Another encoder for JSON, but prints out human-readable JSON instead of /// compact data pub struct PrettyEncoder { - priv wr: @io::Writer, + priv wr: @mut io::Writer, priv indent: uint, } /// Creates a new encoder whose output will be written to the specified writer -pub fn PrettyEncoder(wr: @io::Writer) -> PrettyEncoder { +pub fn PrettyEncoder(wr: @mut io::Writer) -> PrettyEncoder { PrettyEncoder { wr: wr, indent: 0, @@ -256,7 +255,7 @@ pub fn PrettyEncoder(wr: @io::Writer) -> PrettyEncoder { } impl serialize::Encoder for PrettyEncoder { - fn emit_nil(&mut self) { self.wr.write_str("null") } + fn emit_nil(&mut self) { write!(self.wr, "null") } fn emit_uint(&mut self, v: uint) { self.emit_f64(v as f64); } fn emit_u64(&mut self, v: u64) { self.emit_f64(v as f64); } @@ -272,17 +271,19 @@ impl serialize::Encoder for PrettyEncoder { fn emit_bool(&mut self, v: bool) { if v { - self.wr.write_str("true"); + write!(self.wr, "true"); } else { - self.wr.write_str("false"); + write!(self.wr, "false"); } } - fn emit_f64(&mut self, v: f64) { self.wr.write_str(f64::to_str_digits(v, 6u)) } + fn emit_f64(&mut self, v: f64) { + write!(self.wr, "{}", f64::to_str_digits(v, 6u)) + } fn emit_f32(&mut self, v: f32) { self.emit_f64(v as f64); } fn emit_char(&mut self, v: char) { self.emit_str(str::from_char(v)) } - fn emit_str(&mut self, v: &str) { self.wr.write_str(escape_str(v)); } + fn emit_str(&mut self, v: &str) { write!(self.wr, "{}", escape_str(v)); } fn emit_enum(&mut self, _name: &str, f: &fn(&mut PrettyEncoder)) { f(self) @@ -294,19 +295,13 @@ impl serialize::Encoder for PrettyEncoder { cnt: uint, f: &fn(&mut PrettyEncoder)) { if cnt == 0 { - self.wr.write_str(escape_str(name)); + write!(self.wr, "{}", escape_str(name)); } else { - self.wr.write_char('['); self.indent += 2; - self.wr.write_char('\n'); - self.wr.write_str(spaces(self.indent)); - self.wr.write_str(escape_str(name)); - self.wr.write_str(",\n"); + write!(self.wr, "[\n{}{},\n", spaces(self.indent), escape_str(name)); f(self); - self.wr.write_char('\n'); self.indent -= 2; - self.wr.write_str(spaces(self.indent)); - self.wr.write_char(']'); + write!(self.wr, "\n{}]", spaces(self.indent)); } } @@ -314,9 +309,9 @@ impl serialize::Encoder for PrettyEncoder { idx: uint, f: &fn(&mut PrettyEncoder)) { if idx != 0 { - self.wr.write_str(",\n"); + write!(self.wr, ",\n"); } - self.wr.write_str(spaces(self.indent)); + write!(self.wr, "{}", spaces(self.indent)); f(self) } @@ -341,15 +336,13 @@ impl serialize::Encoder for PrettyEncoder { len: uint, f: &fn(&mut PrettyEncoder)) { if len == 0 { - self.wr.write_str("{}"); + write!(self.wr, "\\{\\}"); } else { - self.wr.write_char('{'); + write!(self.wr, "\\{"); self.indent += 2; f(self); - self.wr.write_char('\n'); self.indent -= 2; - self.wr.write_str(spaces(self.indent)); - self.wr.write_char('}'); + write!(self.wr, "\n{}\\}", spaces(self.indent)); } } @@ -358,13 +351,11 @@ impl serialize::Encoder for PrettyEncoder { idx: uint, f: &fn(&mut PrettyEncoder)) { if idx == 0 { - self.wr.write_char('\n'); + write!(self.wr, "\n"); } else { - self.wr.write_str(",\n"); + write!(self.wr, ",\n"); } - self.wr.write_str(spaces(self.indent)); - self.wr.write_str(escape_str(name)); - self.wr.write_str(": "); + write!(self.wr, "{}{}: ", spaces(self.indent), escape_str(name)); f(self); } @@ -393,54 +384,50 @@ impl serialize::Encoder for PrettyEncoder { fn emit_seq(&mut self, len: uint, f: &fn(&mut PrettyEncoder)) { if len == 0 { - self.wr.write_str("[]"); + write!(self.wr, "[]"); } else { - self.wr.write_char('['); + write!(self.wr, "["); self.indent += 2; f(self); - self.wr.write_char('\n'); self.indent -= 2; - self.wr.write_str(spaces(self.indent)); - self.wr.write_char(']'); + write!(self.wr, "\n{}]", spaces(self.indent)); } } fn emit_seq_elt(&mut self, idx: uint, f: &fn(&mut PrettyEncoder)) { if idx == 0 { - self.wr.write_char('\n'); + write!(self.wr, "\n"); } else { - self.wr.write_str(",\n"); + write!(self.wr, ",\n"); } - self.wr.write_str(spaces(self.indent)); + write!(self.wr, "{}", spaces(self.indent)); f(self) } fn emit_map(&mut self, len: uint, f: &fn(&mut PrettyEncoder)) { if len == 0 { - self.wr.write_str("{}"); + write!(self.wr, "\\{\\}"); } else { - self.wr.write_char('{'); + write!(self.wr, "\\{"); self.indent += 2; f(self); - self.wr.write_char('\n'); self.indent -= 2; - self.wr.write_str(spaces(self.indent)); - self.wr.write_char('}'); + write!(self.wr, "\n{}\\}", spaces(self.indent)); } } fn emit_map_elt_key(&mut self, idx: uint, f: &fn(&mut PrettyEncoder)) { if idx == 0 { - self.wr.write_char('\n'); + write!(self.wr, "\n"); } else { - self.wr.write_str(",\n"); + write!(self.wr, ",\n"); } - self.wr.write_str(spaces(self.indent)); + write!(self.wr, "{}", spaces(self.indent)); f(self); } fn emit_map_elt_val(&mut self, _idx: uint, f: &fn(&mut PrettyEncoder)) { - self.wr.write_str(": "); + write!(self.wr, ": "); f(self); } } @@ -460,21 +447,23 @@ impl serialize::Encodable for Json { impl Json{ /// Encodes a json value into a io::writer. Uses a single line. - pub fn to_writer(&self, wr: @io::Writer) { + pub fn to_writer(&self, wr: @mut io::Writer) { let mut encoder = Encoder(wr); self.encode(&mut encoder) } /// Encodes a json value into a io::writer. /// Pretty-prints in a more readable format. - pub fn to_pretty_writer(&self, wr: @io::Writer) { + pub fn to_pretty_writer(&self, wr: @mut io::Writer) { let mut encoder = PrettyEncoder(wr); self.encode(&mut encoder) } /// Encodes a json value into a string pub fn to_pretty_str(&self) -> ~str { - io::with_str_writer(|wr| self.to_pretty_writer(wr)) + let s = @mut MemWriter::new(); + self.to_pretty_writer(s as @mut io::Writer); + str::from_utf8(s.inner_ref().as_slice()) } } @@ -853,9 +842,9 @@ impl> Parser { } } -/// Decodes a json value from an @io::Reader -pub fn from_reader(rdr: @io::Reader) -> Result { - let s = str::from_utf8(rdr.read_whole_stream()); +/// Decodes a json value from an `&mut io::Reader` +pub fn from_reader(mut rdr: &mut io::Reader) -> Result { + let s = str::from_utf8(rdr.read_to_end()); let mut parser = Parser(~s.iter()); parser.parse() } @@ -1306,7 +1295,9 @@ impl ToJson for Option { impl to_str::ToStr for Json { /// Encodes a json value into a string fn to_str(&self) -> ~str { - io::with_str_writer(|wr| self.to_writer(wr)) + let s = @mut MemWriter::new(); + self.to_writer(s as @mut io::Writer); + str::from_utf8(s.inner_ref().as_slice()) } } @@ -1321,8 +1312,7 @@ mod tests { use super::*; - use std::io; - + use std::rt::io; use serialize::Decodable; use treemap::TreeMap; @@ -1493,18 +1483,28 @@ mod tests { assert_eq!(a.clone(), from_str(a.to_pretty_str()).unwrap()); } + fn with_str_writer(f: &fn(@mut io::Writer)) -> ~str { + use std::rt::io::mem::MemWriter; + use std::rt::io::Decorator; + use std::str; + + let m = @mut MemWriter::new(); + f(m as @mut io::Writer); + str::from_utf8(*m.inner_ref()) + } + #[test] fn test_write_enum() { let animal = Dog; assert_eq!( - do io::with_str_writer |wr| { + do with_str_writer |wr| { let mut encoder = Encoder(wr); animal.encode(&mut encoder); }, ~"\"Dog\"" ); assert_eq!( - do io::with_str_writer |wr| { + do with_str_writer |wr| { let mut encoder = PrettyEncoder(wr); animal.encode(&mut encoder); }, @@ -1513,14 +1513,14 @@ mod tests { let animal = Frog(~"Henry", 349); assert_eq!( - do io::with_str_writer |wr| { + do with_str_writer |wr| { let mut encoder = Encoder(wr); animal.encode(&mut encoder); }, ~"{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}" ); assert_eq!( - do io::with_str_writer |wr| { + do with_str_writer |wr| { let mut encoder = PrettyEncoder(wr); animal.encode(&mut encoder); }, @@ -1536,14 +1536,14 @@ mod tests { #[test] fn test_write_some() { let value = Some(~"jodhpurs"); - let s = do io::with_str_writer |wr| { + let s = do with_str_writer |wr| { let mut encoder = Encoder(wr); value.encode(&mut encoder); }; assert_eq!(s, ~"\"jodhpurs\""); let value = Some(~"jodhpurs"); - let s = do io::with_str_writer |wr| { + let s = do with_str_writer |wr| { let mut encoder = PrettyEncoder(wr); value.encode(&mut encoder); }; @@ -1553,13 +1553,13 @@ mod tests { #[test] fn test_write_none() { let value: Option<~str> = None; - let s = do io::with_str_writer |wr| { + let s = do with_str_writer |wr| { let mut encoder = Encoder(wr); value.encode(&mut encoder); }; assert_eq!(s, ~"null"); - let s = do io::with_str_writer |wr| { + let s = do with_str_writer |wr| { let mut encoder = Encoder(wr); value.encode(&mut encoder); }; diff --git a/src/libextra/semver.rs b/src/libextra/semver.rs index 02c35000ce3a4..0ab38cdb5df83 100644 --- a/src/libextra/semver.rs +++ b/src/libextra/semver.rs @@ -30,8 +30,6 @@ use std::char; use std::cmp; -use std::io::{ReaderUtil}; -use std::io; use std::option::{Option, Some, None}; use std::to_str::ToStr; @@ -147,14 +145,19 @@ condition! { bad_parse: () -> (); } -fn take_nonempty_prefix(rdr: @io::Reader, - ch: char, - pred: &fn(char) -> bool) -> (~str, char) { +fn take_nonempty_prefix>(rdr: &mut T, + pred: &fn(char) -> bool) -> (~str, Option) { let mut buf = ~""; - let mut ch = ch; - while pred(ch) { - buf.push_char(ch); - ch = rdr.read_char(); + let mut ch = rdr.next(); + loop { + match ch { + None => break, + Some(c) if !pred(c) => break, + Some(c) => { + buf.push_char(c); + ch = rdr.next(); + } + } } if buf.is_empty() { bad_parse::cond.raise(()) @@ -163,16 +166,16 @@ fn take_nonempty_prefix(rdr: @io::Reader, (buf, ch) } -fn take_num(rdr: @io::Reader, ch: char) -> (uint, char) { - let (s, ch) = take_nonempty_prefix(rdr, ch, char::is_digit); +fn take_num>(rdr: &mut T) -> (uint, Option) { + let (s, ch) = take_nonempty_prefix(rdr, char::is_digit); match from_str::(s) { None => { bad_parse::cond.raise(()); (0, ch) }, Some(i) => (i, ch) } } -fn take_ident(rdr: @io::Reader, ch: char) -> (Identifier, char) { - let (s,ch) = take_nonempty_prefix(rdr, ch, char::is_alphanumeric); +fn take_ident>(rdr: &mut T) -> (Identifier, Option) { + let (s,ch) = take_nonempty_prefix(rdr, char::is_alphanumeric); if s.iter().all(char::is_digit) { match from_str::(s) { None => { bad_parse::cond.raise(()); (Numeric(0), ch) }, @@ -183,38 +186,38 @@ fn take_ident(rdr: @io::Reader, ch: char) -> (Identifier, char) { } } -fn expect(ch: char, c: char) { - if ch != c { +fn expect(ch: Option, c: char) { + if ch != Some(c) { bad_parse::cond.raise(()) } } -fn parse_reader(rdr: @io::Reader) -> Version { - let (major, ch) = take_num(rdr, rdr.read_char()); +fn parse_iter>(rdr: &mut T) -> Version { + let (major, ch) = take_num(rdr); expect(ch, '.'); - let (minor, ch) = take_num(rdr, rdr.read_char()); + let (minor, ch) = take_num(rdr); expect(ch, '.'); - let (patch, ch) = take_num(rdr, rdr.read_char()); + let (patch, ch) = take_num(rdr); let mut pre = ~[]; let mut build = ~[]; let mut ch = ch; - if ch == '-' { + if ch == Some('-') { loop { - let (id, c) = take_ident(rdr, rdr.read_char()); + let (id, c) = take_ident(rdr); pre.push(id); ch = c; - if ch != '.' { break; } + if ch != Some('.') { break; } } } - if ch == '+' { + if ch == Some('+') { loop { - let (id, c) = take_ident(rdr, rdr.read_char()); + let (id, c) = take_ident(rdr); build.push(id); ch = c; - if ch != '.' { break; } + if ch != Some('.') { break; } } } @@ -236,13 +239,11 @@ pub fn parse(s: &str) -> Option { let s = s.trim(); let mut bad = false; do bad_parse::cond.trap(|_| { debug!("bad"); bad = true }).inside { - do io::with_str_reader(s) |rdr| { - let v = parse_reader(rdr); - if bad || v.to_str() != s.to_owned() { - None - } else { - Some(v) - } + let v = parse_iter(&mut s.iter()); + if bad || v.to_str() != s.to_owned() { + None + } else { + Some(v) } } } diff --git a/src/libextra/stats.rs b/src/libextra/stats.rs index 40f99716ca796..497145ca7c992 100644 --- a/src/libextra/stats.rs +++ b/src/libextra/stats.rs @@ -13,7 +13,7 @@ use sort; use std::cmp; use std::hashmap; -use std::io; +use std::rt::io; use std::num; // NB: this can probably be rewritten in terms of num::Num @@ -273,14 +273,14 @@ pub fn winsorize(samples: &mut [f64], pct: f64) { } /// Render writes the min, max and quartiles of the provided `Summary` to the provided `Writer`. -pub fn write_5_number_summary(w: @io::Writer, s: &Summary) { +pub fn write_5_number_summary(w: &mut io::Writer, s: &Summary) { let (q1,q2,q3) = s.quartiles; - w.write_str(format!("(min={}, q1={}, med={}, q3={}, max={})", + write!(w, "(min={}, q1={}, med={}, q3={}, max={})", s.min, q1, q2, q3, - s.max)); + s.max); } /// Render a boxplot to the provided writer. The boxplot shows the min, max and quartiles of the @@ -295,7 +295,7 @@ pub fn write_5_number_summary(w: @io::Writer, s: &Summary) { /// 10 | [--****#******----------] | 40 /// ~~~~ -pub fn write_boxplot(w: @io::Writer, s: &Summary, width_hint: uint) { +pub fn write_boxplot(w: &mut io::Writer, s: &Summary, width_hint: uint) { let (q1,q2,q3) = s.quartiles; @@ -325,52 +325,48 @@ pub fn write_boxplot(w: @io::Writer, s: &Summary, width_hint: uint) { let range_width = width_hint - overhead_width;; let char_step = range / (range_width as f64); - w.write_str(lostr); - w.write_char(' '); - w.write_char('|'); + write!(w, "{} |", lostr); let mut c = 0; let mut v = lo; while c < range_width && v < s.min { - w.write_char(' '); + write!(w, " "); v += char_step; c += 1; } - w.write_char('['); + write!(w, "["); c += 1; while c < range_width && v < q1 { - w.write_char('-'); + write!(w, "-"); v += char_step; c += 1; } while c < range_width && v < q2 { - w.write_char('*'); + write!(w, "*"); v += char_step; c += 1; } - w.write_char('#'); + write!(w, r"\#"); c += 1; while c < range_width && v < q3 { - w.write_char('*'); + write!(w, "*"); v += char_step; c += 1; } while c < range_width && v < s.max { - w.write_char('-'); + write!(w, "-"); v += char_step; c += 1; } - w.write_char(']'); + write!(w, "]"); while c < range_width { - w.write_char(' '); + write!(w, " "); v += char_step; c += 1; } - w.write_char('|'); - w.write_char(' '); - w.write_str(histr); + write!(w, "| {}", histr); } /// Returns a HashMap with the number of occurrences of every element in the @@ -392,18 +388,20 @@ mod tests { use stats::Summary; use stats::write_5_number_summary; use stats::write_boxplot; - use std::io; + use std::rt::io; + use std::str; fn check(samples: &[f64], summ: &Summary) { let summ2 = Summary::new(samples); - let w = io::stdout(); - w.write_char('\n'); + let mut w = io::stdout(); + let w = &mut w as &mut io::Writer; + write!(w, "\n"); write_5_number_summary(w, &summ2); - w.write_char('\n'); + write!(w, "\n"); write_boxplot(w, &summ2, 50); - w.write_char('\n'); + write!(w, "\n"); assert_eq!(summ.sum, summ2.sum); assert_eq!(summ.min, summ2.min); @@ -944,10 +942,11 @@ mod tests { #[test] fn test_boxplot_nonpositive() { fn t(s: &Summary, expected: ~str) { - let out = do io::with_str_writer |w| { - write_boxplot(w, s, 30) - }; - + use std::rt::io::mem::MemWriter; + use std::rt::io::Decorator; + let mut m = MemWriter::new(); + write_boxplot(&mut m as &mut io::Writer, s, 30); + let out = str::from_utf8_owned(m.inner()); assert_eq!(out, expected); } diff --git a/src/libextra/term.rs b/src/libextra/term.rs index 878224890e619..22ce833ea24d9 100644 --- a/src/libextra/term.rs +++ b/src/libextra/term.rs @@ -13,7 +13,7 @@ #[allow(missing_doc)]; -use std::io; +use std::rt::io; #[cfg(not(target_os = "win32"))] use std::os; #[cfg(not(target_os = "win32"))] use terminfo::*; @@ -96,19 +96,19 @@ fn cap_for_attr(attr: attr::Attr) -> &'static str { #[cfg(not(target_os = "win32"))] pub struct Terminal { priv num_colors: u16, - priv out: @io::Writer, + priv out: @mut io::Writer, priv ti: ~TermInfo } #[cfg(target_os = "win32")] pub struct Terminal { priv num_colors: u16, - priv out: @io::Writer, + priv out: @mut io::Writer, } #[cfg(not(target_os = "win32"))] impl Terminal { - pub fn new(out: @io::Writer) -> Result { + pub fn new(out: @mut io::Writer) -> Result { let term = os::getenv("TERM"); if term.is_none() { return Err(~"TERM environment variable undefined"); @@ -243,7 +243,7 @@ impl Terminal { #[cfg(target_os = "win32")] impl Terminal { - pub fn new(out: @io::Writer) -> Result { + pub fn new(out: @mut io::Writer) -> Result { return Ok(Terminal {out: out, num_colors: 0}); } diff --git a/src/libextra/test.rs b/src/libextra/test.rs index f95c7aa22b7f0..457f7868e237a 100644 --- a/src/libextra/test.rs +++ b/src/libextra/test.rs @@ -30,8 +30,8 @@ use treemap::TreeMap; use std::clone::Clone; use std::comm::{stream, SharedChan, GenericPort, GenericChan}; -use std::io; -use std::result; +use std::rt::io; +use std::rt::io::file::FileInfo; use std::task; use std::to_str::ToStr; use std::f64; @@ -336,8 +336,8 @@ pub enum TestResult { } struct ConsoleTestState { - out: @io::Writer, - log_out: Option<@io::Writer>, + out: @mut io::Writer, + log_out: Option<@mut io::Writer>, term: Option, use_color: bool, total: uint, @@ -353,17 +353,13 @@ struct ConsoleTestState { impl ConsoleTestState { pub fn new(opts: &TestOpts) -> ConsoleTestState { let log_out = match opts.logfile { - Some(ref path) => match io::file_writer(path, - [io::Create, - io::Truncate]) { - result::Ok(w) => Some(w), - result::Err(ref s) => { - fail!("can't open output file: {}", *s) - } + Some(ref path) => { + let out = path.open_writer(io::CreateOrTruncate); + Some(@mut out as @mut io::Writer) }, None => None }; - let out = io::stdout(); + let out = @mut io::stdio::stdout() as @mut io::Writer; let term = match term::Terminal::new(out) { Err(_) => None, Ok(t) => Some(t) @@ -424,12 +420,12 @@ impl ConsoleTestState { word: &str, color: term::color::Color) { match self.term { - None => self.out.write_str(word), + None => self.out.write(word.as_bytes()), Some(ref t) => { if self.use_color { t.fg(color); } - self.out.write_str(word); + self.out.write(word.as_bytes()); if self.use_color { t.reset(); } @@ -440,12 +436,12 @@ impl ConsoleTestState { pub fn write_run_start(&mut self, len: uint) { self.total = len; let noun = if len != 1 { &"tests" } else { &"test" }; - self.out.write_line(format!("\nrunning {} {}", len, noun)); + write!(self.out, "\nrunning {} {}\n", len, noun); } pub fn write_test_start(&self, test: &TestDesc, align: NamePadding) { let name = test.padded_name(self.max_name_len, align); - self.out.write_str(format!("test {} ... ", name)); + write!(self.out, "test {} ... ", name); } pub fn write_result(&self, result: &TestResult) { @@ -455,41 +451,40 @@ impl ConsoleTestState { TrIgnored => self.write_ignored(), TrMetrics(ref mm) => { self.write_metric(); - self.out.write_str(": " + fmt_metrics(mm)); + write!(self.out, ": {}", fmt_metrics(mm)); } TrBench(ref bs) => { self.write_bench(); - self.out.write_str(": " + fmt_bench_samples(bs)) + write!(self.out, ": {}", fmt_bench_samples(bs)); } } - self.out.write_str(&"\n"); + write!(self.out, "\n"); } pub fn write_log(&self, test: &TestDesc, result: &TestResult) { match self.log_out { None => (), Some(out) => { - out.write_line(format!("{} {}", - match *result { + write!(out, "{} {}",match *result { TrOk => ~"ok", TrFailed => ~"failed", TrIgnored => ~"ignored", TrMetrics(ref mm) => fmt_metrics(mm), TrBench(ref bs) => fmt_bench_samples(bs) - }, test.name.to_str())); + }, test.name.to_str()); } } } pub fn write_failures(&self) { - self.out.write_line("\nfailures:"); + write!(self.out, "\nfailures:\n"); let mut failures = ~[]; for f in self.failures.iter() { failures.push(f.name.to_str()); } sort::tim_sort(failures); for name in failures.iter() { - self.out.write_line(format!(" {}", name.to_str())); + writeln!(self.out, " {}", name.to_str()); } } @@ -506,36 +501,34 @@ impl ConsoleTestState { MetricAdded => { added += 1; self.write_added(); - self.out.write_line(format!(": {}", *k)); + writeln!(self.out, ": {}", *k); } MetricRemoved => { removed += 1; self.write_removed(); - self.out.write_line(format!(": {}", *k)); + writeln!(self.out, ": {}", *k); } Improvement(pct) => { improved += 1; - self.out.write_str(*k); - self.out.write_str(": "); + write!(self.out, "{}: ", *k); self.write_improved(); - self.out.write_line(format!(" by {:.2f}%", pct as f64)) + writeln!(self.out, " by {:.2f}%", pct as f64); } Regression(pct) => { regressed += 1; - self.out.write_str(*k); - self.out.write_str(": "); + write!(self.out, "{}: ", *k); self.write_regressed(); - self.out.write_line(format!(" by {:.2f}%", pct as f64)) + writeln!(self.out, " by {:.2f}%", pct as f64); } } } - self.out.write_line(format!("result of ratchet: {} matrics added, {} removed, \ - {} improved, {} regressed, {} noise", - added, removed, improved, regressed, noise)); + writeln!(self.out, "result of ratchet: {} matrics added, {} removed, \ + {} improved, {} regressed, {} noise", + added, removed, improved, regressed, noise); if regressed == 0 { - self.out.write_line("updated ratchet file") + writeln!(self.out, "updated ratchet file"); } else { - self.out.write_line("left ratchet file untouched") + writeln!(self.out, "left ratchet file untouched"); } } @@ -547,12 +540,12 @@ impl ConsoleTestState { let ratchet_success = match *ratchet_metrics { None => true, Some(ref pth) => { - self.out.write_str(format!("\nusing metrics ratchet: {}\n", pth.display())); + write!(self.out, "\nusing metrics ratcher: {}\n", pth.display()); match ratchet_pct { None => (), Some(pct) => - self.out.write_str(format!("with noise-tolerance forced to: {}%%\n", - pct as f64)) + writeln!(self.out, "with noise-tolerance forced to: {}%", + pct) } let (diff, ok) = self.metrics.ratchet(pth, ratchet_pct); self.write_metric_diff(&diff); @@ -567,15 +560,15 @@ impl ConsoleTestState { let success = ratchet_success && test_success; - self.out.write_str("\ntest result: "); + write!(self.out, "\ntest result: "); if success { // There's no parallelism at this point so it's safe to use color self.write_ok(); } else { self.write_failed(); } - self.out.write_str(format!(". {} passed; {} failed; {} ignored; {} measured\n\n", - self.passed, self.failed, self.ignored, self.measured)); + write!(self.out, ". {} passed; {} failed; {} ignored; {} measured\n\n", + self.passed, self.failed, self.ignored, self.measured); return success; } } @@ -659,7 +652,7 @@ pub fn run_tests_console(opts: &TestOpts, None => (), Some(ref pth) => { st.metrics.save(pth); - st.out.write_str(format!("\nmetrics saved to: {}", pth.display())); + write!(st.out, "\nmetrics saved to: {}", pth.display()); } } return st.write_run_finish(&opts.ratchet_metrics, opts.ratchet_noise_percent); @@ -667,39 +660,43 @@ pub fn run_tests_console(opts: &TestOpts, #[test] fn should_sort_failures_before_printing_them() { + use std::rt::io; + use std::rt::io::Decorator; + use std::rt::io::mem::MemWriter; + use std::str; fn dummy() {} - let s = do io::with_str_writer |wr| { - let test_a = TestDesc { - name: StaticTestName("a"), - ignore: false, - should_fail: false - }; - - let test_b = TestDesc { - name: StaticTestName("b"), - ignore: false, - should_fail: false - }; + let m = @mut MemWriter::new(); + let test_a = TestDesc { + name: StaticTestName("a"), + ignore: false, + should_fail: false + }; - let st = @ConsoleTestState { - out: wr, - log_out: None, - term: None, - use_color: false, - total: 0u, - passed: 0u, - failed: 0u, - ignored: 0u, - measured: 0u, - metrics: MetricMap::new(), - failures: ~[test_b, test_a], - max_name_len: 0u, - }; + let test_b = TestDesc { + name: StaticTestName("b"), + ignore: false, + should_fail: false + }; - st.write_failures(); + let st = @ConsoleTestState { + out: m as @mut io::Writer, + log_out: None, + term: None, + use_color: false, + total: 0u, + passed: 0u, + failed: 0u, + ignored: 0u, + measured: 0u, + max_name_len: 10u, + metrics: MetricMap::new(), + failures: ~[test_b, test_a] }; + st.write_failures(); + let s = str::from_utf8(*m.inner_ref()); + let apos = s.find_str("a").unwrap(); let bpos = s.find_str("b").unwrap(); assert!(apos < bpos); @@ -939,15 +936,15 @@ impl MetricMap { /// Load MetricDiff from a file. pub fn load(p: &Path) -> MetricMap { assert!(os::path_exists(p)); - let f = io::file_reader(p).unwrap(); + let f = @mut p.open_reader(io::Open) as @mut io::Reader; let mut decoder = json::Decoder(json::from_reader(f).unwrap()); MetricMap(Decodable::decode(&mut decoder)) } /// Write MetricDiff to a file. pub fn save(&self, p: &Path) { - let f = io::file_writer(p, [io::Create, io::Truncate]).unwrap(); - self.to_json().to_pretty_writer(f); + let f = @mut p.open_writer(io::CreateOrTruncate); + self.to_json().to_pretty_writer(f as @mut io::Writer); } /// Compare against another MetricMap. Optionally compare all diff --git a/src/libextra/time.rs b/src/libextra/time.rs index f675c6f2392c7..2950f02ad19dd 100644 --- a/src/libextra/time.rs +++ b/src/libextra/time.rs @@ -10,7 +10,8 @@ #[allow(missing_doc)]; -use std::io; +use std::rt::io::Reader; +use std::rt::io::mem::BufReader; use std::num; use std::str; @@ -666,61 +667,69 @@ pub fn strptime(s: &str, format: &str) -> Result { } } - do io::with_str_reader(format) |rdr| { - let mut tm = Tm { - tm_sec: 0_i32, - tm_min: 0_i32, - tm_hour: 0_i32, - tm_mday: 0_i32, - tm_mon: 0_i32, - tm_year: 0_i32, - tm_wday: 0_i32, - tm_yday: 0_i32, - tm_isdst: 0_i32, - tm_gmtoff: 0_i32, - tm_zone: ~"", - tm_nsec: 0_i32, - }; - let mut pos = 0u; - let len = s.len(); - let mut result = Err(~"Invalid time"); + let mut rdr = BufReader::new(format.as_bytes()); + let mut tm = Tm { + tm_sec: 0_i32, + tm_min: 0_i32, + tm_hour: 0_i32, + tm_mday: 0_i32, + tm_mon: 0_i32, + tm_year: 0_i32, + tm_wday: 0_i32, + tm_yday: 0_i32, + tm_isdst: 0_i32, + tm_gmtoff: 0_i32, + tm_zone: ~"", + tm_nsec: 0_i32, + }; + let mut pos = 0u; + let len = s.len(); + let mut result = Err(~"Invalid time"); - while !rdr.eof() && pos < len { - let range = s.char_range_at(pos); - let ch = range.ch; - let next = range.next; - - match rdr.read_char() { - '%' => { - match parse_type(s, pos, rdr.read_char(), &mut tm) { - Ok(next) => pos = next, - Err(e) => { result = Err(e); break; } - } - }, - c => { - if c != ch { break } - pos = next; + while pos < len { + let range = s.char_range_at(pos); + let ch = range.ch; + let next = range.next; + + let mut buf = [0]; + let c = match rdr.read(buf) { + Some(*) => buf[0] as u8 as char, + None => break + }; + match c { + '%' => { + let ch = match rdr.read(buf) { + Some(*) => buf[0] as u8 as char, + None => break + }; + match parse_type(s, pos, ch, &mut tm) { + Ok(next) => pos = next, + Err(e) => { result = Err(e); break; } } + }, + c => { + if c != ch { break } + pos = next; } } - - if pos == len && rdr.eof() { - Ok(Tm { - tm_sec: tm.tm_sec, - tm_min: tm.tm_min, - tm_hour: tm.tm_hour, - tm_mday: tm.tm_mday, - tm_mon: tm.tm_mon, - tm_year: tm.tm_year, - tm_wday: tm.tm_wday, - tm_yday: tm.tm_yday, - tm_isdst: tm.tm_isdst, - tm_gmtoff: tm.tm_gmtoff, - tm_zone: tm.tm_zone.clone(), - tm_nsec: tm.tm_nsec, - }) - } else { result } } + + if pos == len && rdr.eof() { + Ok(Tm { + tm_sec: tm.tm_sec, + tm_min: tm.tm_min, + tm_hour: tm.tm_hour, + tm_mday: tm.tm_mday, + tm_mon: tm.tm_mon, + tm_year: tm.tm_year, + tm_wday: tm.tm_wday, + tm_yday: tm.tm_yday, + tm_isdst: tm.tm_isdst, + tm_gmtoff: tm.tm_gmtoff, + tm_zone: tm.tm_zone.clone(), + tm_nsec: tm.tm_nsec, + }) + } else { result } } /// Formats the time according to the format string. @@ -929,18 +938,26 @@ pub fn strftime(format: &str, tm: &Tm) -> ~str { } } - let mut buf = ~""; + let mut buf = ~[]; - do io::with_str_reader(format) |rdr| { - while !rdr.eof() { - match rdr.read_char() { - '%' => buf.push_str(parse_type(rdr.read_char(), tm)), - ch => buf.push_char(ch) + let mut rdr = BufReader::new(format.as_bytes()); + loop { + let mut b = [0]; + let ch = match rdr.read(b) { + Some(*) => b[0], + None => break, + }; + match ch as char { + '%' => { + rdr.read(b); + let s = parse_type(b[0] as char, tm); + buf.push_all(s.as_bytes()); } + ch => buf.push(ch as u8) } } - buf + str::from_utf8_owned(buf) } #[cfg(test)] diff --git a/src/libextra/url.rs b/src/libextra/url.rs index e836d3b52709c..bfa3934700a51 100644 --- a/src/libextra/url.rs +++ b/src/libextra/url.rs @@ -12,10 +12,9 @@ #[allow(missing_doc)]; - +use std::rt::io::{Reader, Seek}; +use std::rt::io::mem::BufReader; use std::cmp::Eq; -use std::io::{Reader, ReaderUtil}; -use std::io; use std::hashmap::HashMap; use std::to_bytes; use std::uint; @@ -68,42 +67,46 @@ impl UserInfo { } fn encode_inner(s: &str, full_url: bool) -> ~str { - do io::with_str_reader(s) |rdr| { - let mut out = ~""; - - while !rdr.eof() { - let ch = rdr.read_byte() as u8 as char; - match ch { - // unreserved: - 'A' .. 'Z' | - 'a' .. 'z' | - '0' .. '9' | - '-' | '.' | '_' | '~' => { - out.push_char(ch); - } - _ => { - if full_url { - match ch { - // gen-delims: - ':' | '/' | '?' | '#' | '[' | ']' | '@' | - - // sub-delims: - '!' | '$' | '&' | '"' | '(' | ')' | '*' | - '+' | ',' | ';' | '=' => { - out.push_char(ch); - } - - _ => out.push_str(format!("%{:X}", ch as uint)) - } - } else { - out.push_str(format!("%{:X}", ch as uint)); + let mut rdr = BufReader::new(s.as_bytes()); + let mut out = ~""; + + loop { + let mut buf = [0]; + let ch = match rdr.read(buf) { + None => break, + Some(*) => buf[0] as char, + }; + + match ch { + // unreserved: + 'A' .. 'Z' | + 'a' .. 'z' | + '0' .. '9' | + '-' | '.' | '_' | '~' => { + out.push_char(ch); + } + _ => { + if full_url { + match ch { + // gen-delims: + ':' | '/' | '?' | '#' | '[' | ']' | '@' | + + // sub-delims: + '!' | '$' | '&' | '"' | '(' | ')' | '*' | + '+' | ',' | ';' | '=' => { + out.push_char(ch); + } + + _ => out.push_str(format!("%{:X}", ch as uint)) } - } + } else { + out.push_str(format!("%{:X}", ch as uint)); } + } } - - out } + + out } /** @@ -128,41 +131,49 @@ pub fn encode_component(s: &str) -> ~str { } fn decode_inner(s: &str, full_url: bool) -> ~str { - do io::with_str_reader(s) |rdr| { - let mut out = ~""; - - while !rdr.eof() { - match rdr.read_char() { - '%' => { - let bytes = rdr.read_bytes(2u); - let ch = uint::parse_bytes(bytes, 16u).unwrap() as u8 as char; - - if full_url { - // Only decode some characters: - match ch { - // gen-delims: - ':' | '/' | '?' | '#' | '[' | ']' | '@' | - - // sub-delims: - '!' | '$' | '&' | '"' | '(' | ')' | '*' | - '+' | ',' | ';' | '=' => { - out.push_char('%'); - out.push_char(bytes[0u] as char); - out.push_char(bytes[1u] as char); - } - - ch => out.push_char(ch) - } - } else { - out.push_char(ch); + let mut rdr = BufReader::new(s.as_bytes()); + let mut out = ~""; + + loop { + let mut buf = [0]; + let ch = match rdr.read(buf) { + None => break, + Some(*) => buf[0] as char + }; + match ch { + '%' => { + let mut bytes = [0, 0]; + match rdr.read(bytes) { + Some(2) => {} + _ => fail2!() // XXX: malformed url? + } + let ch = uint::parse_bytes(bytes, 16u).unwrap() as u8 as char; + + if full_url { + // Only decode some characters: + match ch { + // gen-delims: + ':' | '/' | '?' | '#' | '[' | ']' | '@' | + + // sub-delims: + '!' | '$' | '&' | '"' | '(' | ')' | '*' | + '+' | ',' | ';' | '=' => { + out.push_char('%'); + out.push_char(bytes[0u] as char); + out.push_char(bytes[1u] as char); + } + + ch => out.push_char(ch) } - } - ch => out.push_char(ch) + } else { + out.push_char(ch); } + } + ch => out.push_char(ch) } - - out } + + out } /** @@ -182,22 +193,25 @@ pub fn decode_component(s: &str) -> ~str { } fn encode_plus(s: &str) -> ~str { - do io::with_str_reader(s) |rdr| { - let mut out = ~""; - - while !rdr.eof() { - let ch = rdr.read_byte() as u8 as char; - match ch { - 'A' .. 'Z' | 'a' .. 'z' | '0' .. '9' | '_' | '.' | '-' => { - out.push_char(ch); - } - ' ' => out.push_char('+'), - _ => out.push_str(format!("%{:X}", ch as uint)) - } - } + let mut rdr = BufReader::new(s.as_bytes()); + let mut out = ~""; - out + loop { + let mut buf = [0]; + let ch = match rdr.read(buf) { + Some(*) => buf[0] as char, + None => break, + }; + match ch { + 'A' .. 'Z' | 'a' .. 'z' | '0' .. '9' | '_' | '.' | '-' => { + out.push_char(ch); + } + ' ' => out.push_char('+'), + _ => out.push_str(format!("%{:X}", ch as uint)) + } } + + out } /** @@ -230,61 +244,69 @@ pub fn encode_form_urlencoded(m: &HashMap<~str, ~[~str]>) -> ~str { * type into a hashmap. */ pub fn decode_form_urlencoded(s: &[u8]) -> HashMap<~str, ~[~str]> { - do io::with_bytes_reader(s) |rdr| { - let mut m = HashMap::new(); - let mut key = ~""; - let mut value = ~""; - let mut parsing_key = true; - - while !rdr.eof() { - match rdr.read_char() { - '&' | ';' => { - if key != ~"" && value != ~"" { - let mut values = match m.pop(&key) { - Some(values) => values, - None => ~[], - }; - - values.push(value); - m.insert(key, values); - } + let mut rdr = BufReader::new(s); + let mut m = HashMap::new(); + let mut key = ~""; + let mut value = ~""; + let mut parsing_key = true; + + loop { + let mut buf = [0]; + let ch = match rdr.read(buf) { + Some(*) => buf[0] as char, + None => break, + }; + match ch { + '&' | ';' => { + if key != ~"" && value != ~"" { + let mut values = match m.pop(&key) { + Some(values) => values, + None => ~[], + }; - parsing_key = true; - key = ~""; - value = ~""; + values.push(value); + m.insert(key, values); } - '=' => parsing_key = false, - ch => { - let ch = match ch { - '%' => { - let bytes = rdr.read_bytes(2u); - uint::parse_bytes(bytes, 16u).unwrap() as u8 as char - } - '+' => ' ', - ch => ch - }; - if parsing_key { - key.push_char(ch) - } else { - value.push_char(ch) + parsing_key = true; + key = ~""; + value = ~""; + } + '=' => parsing_key = false, + ch => { + let ch = match ch { + '%' => { + let mut bytes = [0, 0]; + match rdr.read(bytes) { + Some(2) => {} + _ => fail2!() // XXX: malformed? + } + uint::parse_bytes(bytes, 16u).unwrap() as u8 as char } + '+' => ' ', + ch => ch + }; + + if parsing_key { + key.push_char(ch) + } else { + value.push_char(ch) } } } + } - if key != ~"" && value != ~"" { - let mut values = match m.pop(&key) { - Some(values) => values, - None => ~[], - }; - - values.push(value); - m.insert(key, values); - } + if key != ~"" && value != ~"" { + let mut values = match m.pop(&key) { + Some(values) => values, + None => ~[], + }; - m + values.push(value); + m.insert(key, values); } + + m } @@ -292,16 +314,18 @@ fn split_char_first(s: &str, c: char) -> (~str, ~str) { let len = s.len(); let mut index = len; let mut mat = 0; - do io::with_str_reader(s) |rdr| { - let mut ch; - while !rdr.eof() { - ch = rdr.read_byte() as u8 as char; - if ch == c { - // found a match, adjust markers - index = rdr.tell()-1; - mat = 1; - break; - } + let mut rdr = BufReader::new(s.as_bytes()); + loop { + let mut buf = [0]; + let ch = match rdr.read(buf) { + Some(*) => buf[0] as char, + None => break, + }; + if ch == c { + // found a match, adjust markers + index = (rdr.tell() as uint) - 1; + mat = 1; + break; } } if index+mat == len { diff --git a/src/libextra/workcache.rs b/src/libextra/workcache.rs index 4d79b2059db5c..30efecde37f91 100644 --- a/src/libextra/workcache.rs +++ b/src/libextra/workcache.rs @@ -19,7 +19,13 @@ use arc::{Arc,RWArc}; use treemap::TreeMap; use std::cell::Cell; use std::comm::{PortOne, oneshot}; -use std::{io, os, task}; +use std::{os, str, task}; +use std::rt::io; +use std::rt::io::Writer; +use std::rt::io::Decorator; +use std::rt::io::extensions::ReaderUtil; +use std::rt::io::mem::MemWriter; +use std::rt::io::file::FileInfo; /** * @@ -174,19 +180,19 @@ impl Database { // FIXME #4330: This should have &mut self and should set self.db_dirty to false. fn save(&self) { - let f = io::file_writer(&self.db_filename, [io::Create, io::Truncate]).unwrap(); - self.db_cache.to_json().to_pretty_writer(f); + let f = @mut self.db_filename.open_writer(io::CreateOrTruncate); + self.db_cache.to_json().to_pretty_writer(f as @mut io::Writer); } fn load(&mut self) { assert!(!self.db_dirty); assert!(os::path_exists(&self.db_filename)); - let f = io::file_reader(&self.db_filename); + let f = self.db_filename.open_reader(io::Open); match f { - Err(e) => fail!("Couldn't load workcache database {}: {}", - self.db_filename.display(), e.to_str()), - Ok(r) => - match json::from_reader(r) { + None => fail!("Couldn't load workcache database {}", + self.db_filename.display()), + Some(r) => + match json::from_reader(@mut r as @mut io::Reader) { Err(e) => fail!("Couldn't parse workcache database (from file {}): {}", self.db_filename.display(), e.to_str()), Ok(r) => { @@ -256,20 +262,18 @@ enum Work<'self, T> { } fn json_encode>(t: &T) -> ~str { - do io::with_str_writer |wr| { - let mut encoder = json::Encoder(wr); - t.encode(&mut encoder); - } + let writer = @mut MemWriter::new(); + let mut encoder = json::Encoder(writer as @mut io::Writer); + t.encode(&mut encoder); + str::from_utf8(writer.inner_ref().as_slice()) } // FIXME(#5121) fn json_decode>(s: &str) -> T { debug!("json decoding: {}", s); - do io::with_str_reader(s) |rdr| { - let j = json::from_reader(rdr).unwrap(); - let mut decoder = json::Decoder(j); - Decodable::decode(&mut decoder) - } + let j = json::from_str(s).unwrap(); + let mut decoder = json::Decoder(j); + Decodable::decode(&mut decoder) } fn digest>(t: &T) -> ~str { @@ -280,8 +284,8 @@ fn digest>(t: &T) -> ~str { fn digest_file(path: &Path) -> ~str { let mut sha = ~Sha1::new(); - let s = io::read_whole_file_str(path); - (*sha).input_str(s.unwrap()); + let s = path.open_reader(io::Open).read_to_end(); + (*sha).input(s); (*sha).result_str() } @@ -492,7 +496,6 @@ impl<'self, T:Send + #[test] fn test() { - use std::io::WriterUtil; use std::{os, run}; // Create a path to a new file 'filename' in the directory in which @@ -507,8 +510,7 @@ fn test() { let pth = make_path(~"foo.c"); { - let r = io::file_writer(&pth, [io::Create]); - r.unwrap().write_str("int main() { return 0; }"); + pth.open_writer(io::Create).write(bytes!("int main() { return 0; }")); } let db_path = make_path(~"db.json"); @@ -539,5 +541,5 @@ fn test() { } }; - io::println(s); + println(s); } diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 2438d22881fb5..1b9cb10f1dcfd 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -26,7 +26,6 @@ use std::c_str::ToCStr; use std::char; use std::hash::Streaming; use std::hash; -use std::io; use std::os::consts::{macos, freebsd, linux, android, win32}; use std::os; use std::ptr; @@ -930,7 +929,7 @@ pub fn link_binary(sess: Session, let cc_args = link_args(sess, obj_filename, out_filename, lm); debug!("{} link args: {}", cc_prog, cc_args.connect(" ")); if (sess.opts.debugging_opts & session::print_link_args) != 0 { - io::println(format!("{} link args: {}", cc_prog, cc_args.connect(" "))); + println!("{} link args: {}", cc_prog, cc_args.connect(" ")); } // We run 'cc' here diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 67a59f24e2938..d2b0dad80f656 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -26,7 +26,8 @@ use util::common::time; use util::ppaux; use std::hashmap::{HashMap,HashSet}; -use std::io; +use std::rt::io; +use std::rt::io::mem::MemReader; use std::os; use std::vec; use extra::getopts::groups::{optopt, optmulti, optflag, optflagopt}; @@ -552,17 +553,16 @@ pub fn pretty_print_input(sess: Session, }; let src = sess.codemap.get_filemap(source_name(input)).src; - do io::with_str_reader(src) |rdr| { - pprust::print_crate(sess.codemap, - token::get_ident_interner(), - sess.span_diagnostic, - &crate, - source_name(input), - rdr, - io::stdout(), - annotation, - is_expanded); - } + let rdr = @mut MemReader::new(src.as_bytes().to_owned()); + pprust::print_crate(sess.codemap, + token::get_ident_interner(), + sess.span_diagnostic, + &crate, + source_name(input), + rdr as @mut io::Reader, + @mut io::stdout() as @mut io::Writer, + annotation, + is_expanded); } pub fn get_os(triple: &str) -> Option { @@ -1048,7 +1048,7 @@ pub fn early_error(emitter: @diagnostic::Emitter, msg: &str) -> ! { fail!(); } -pub fn list_metadata(sess: Session, path: &Path, out: @io::Writer) { +pub fn list_metadata(sess: Session, path: &Path, out: @mut io::Writer) { metadata::loader::list_file_metadata( token::get_ident_interner(), session::sess_os_to_meta_os(sess.targ_cfg.os), path, out); diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 1023273032942..be118792f4987 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -27,8 +27,7 @@ use middle::astencode::vtable_decoder_helpers; use std::u64; -use std::io::WriterUtil; -use std::io; +use std::rt::io; use std::option; use std::str; use std::vec; @@ -56,14 +55,14 @@ fn lookup_hash(d: ebml::Doc, eq_fn: &fn(x:&[u8]) -> bool, hash: u64) -> let index = reader::get_doc(d, tag_index); let table = reader::get_doc(index, tag_index_table); let hash_pos = table.start + (hash % 256 * 4) as uint; - let pos = io::u64_from_be_bytes(*d.data, hash_pos, 4) as uint; + let pos = ::std::io::u64_from_be_bytes(*d.data, hash_pos, 4) as uint; let tagged_doc = reader::doc_at(d.data, pos); let belt = tag_index_buckets_bucket_elt; let mut ret = None; do reader::tagged_docs(tagged_doc.doc, belt) |elt| { - let pos = io::u64_from_be_bytes(*elt.data, elt.start, 4) as uint; + let pos = ::std::io::u64_from_be_bytes(*elt.data, elt.start, 4) as uint; if eq_fn(elt.data.slice(elt.start + 4, elt.end)) { ret = Some(reader::doc_at(d.data, pos).doc); false @@ -78,7 +77,7 @@ pub type GetCrateDataCb<'self> = &'self fn(ast::CrateNum) -> Cmd; pub fn maybe_find_item(item_id: int, items: ebml::Doc) -> Option { fn eq_item(bytes: &[u8], item_id: int) -> bool { - return io::u64_from_be_bytes( + return ::std::io::u64_from_be_bytes( bytes.slice(0u, 4u), 0u, 4u) as int == item_id; } @@ -1254,7 +1253,7 @@ fn family_names_type(fam: Family) -> bool { fn read_path(d: ebml::Doc) -> (~str, uint) { do reader::with_doc_data(d) |desc| { - let pos = io::u64_from_be_bytes(desc, 0u, 4u) as uint; + let pos = ::std::io::u64_from_be_bytes(desc, 0u, 4u) as uint; let pathbytes = desc.slice(4u, desc.len()); let path = str::from_utf8(pathbytes); @@ -1353,23 +1352,23 @@ fn get_attributes(md: ebml::Doc) -> ~[ast::Attribute] { fn list_meta_items(intr: @ident_interner, meta_items: ebml::Doc, - out: @io::Writer) { + out: @mut io::Writer) { let r = get_meta_items(meta_items); for mi in r.iter() { - out.write_str(format!("{}\n", pprust::meta_item_to_str(*mi, intr))); + write!(out, "{}\n", pprust::meta_item_to_str(*mi, intr)); } } fn list_crate_attributes(intr: @ident_interner, md: ebml::Doc, hash: &str, - out: @io::Writer) { - out.write_str(format!("=Crate Attributes ({})=\n", hash)); + out: @mut io::Writer) { + write!(out, "=Crate Attributes ({})=\n", hash); let r = get_attributes(md); for attr in r.iter() { - out.write_str(format!("{}\n", pprust::attribute_to_str(attr, intr))); + write!(out, "{}\n", pprust::attribute_to_str(attr, intr)); } - out.write_str("\n\n"); + write!(out, "\n\n"); } pub fn get_crate_attributes(data: @~[u8]) -> ~[ast::Attribute] { @@ -1404,17 +1403,16 @@ pub fn get_crate_deps(data: @~[u8]) -> ~[CrateDep] { return deps; } -fn list_crate_deps(data: @~[u8], out: @io::Writer) { - out.write_str("=External Dependencies=\n"); +fn list_crate_deps(data: @~[u8], out: @mut io::Writer) { + write!(out, "=External Dependencies=\n"); let r = get_crate_deps(data); for dep in r.iter() { - out.write_str( - format!("{} {}-{}-{}\n", - dep.cnum, token::ident_to_str(&dep.name), dep.hash, dep.vers)); + write!(out, "{} {}-{}-{}\n", + dep.cnum, token::ident_to_str(&dep.name), dep.hash, dep.vers); } - out.write_str("\n"); + write!(out, "\n"); } pub fn get_crate_hash(data: @~[u8]) -> @str { @@ -1434,7 +1432,7 @@ pub fn get_crate_vers(data: @~[u8]) -> @str { } pub fn list_crate_metadata(intr: @ident_interner, bytes: @~[u8], - out: @io::Writer) { + out: @mut io::Writer) { let hash = get_crate_hash(bytes); let md = reader::Doc(bytes); list_crate_attributes(intr, md, hash, out); diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index bae0dcc2a5203..e6d6b28257218 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -1819,7 +1819,7 @@ pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] { } } - io::println("metadata stats:"); + println("metadata stats:"); println!(" inline bytes: {}", ecx.stats.inline_bytes); println!(" attribute bytes: {}", ecx.stats.attr_bytes); println!(" dep bytes: {}", ecx.stats.dep_bytes); diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index e682ff299a935..34eb387a3f5d4 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -25,7 +25,7 @@ use syntax::attr::AttrMetaMethods; use std::c_str::ToCStr; use std::cast; -use std::io; +use std::rt::io; use std::num; use std::option; use std::os::consts::{macos, freebsd, linux, android, win32}; @@ -271,11 +271,11 @@ pub fn read_meta_section_name(os: Os) -> &'static str { pub fn list_file_metadata(intr: @ident_interner, os: Os, path: &Path, - out: @io::Writer) { + out: @mut io::Writer) { match get_metadata_section(os, path) { option::Some(bytes) => decoder::list_crate_metadata(intr, bytes, out), option::None => { - out.write_str(format!("could not find metadata in {}.\n", path.display())) + write!(out, "could not find metadata in {}.\n", path.display()) } } } diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 2722fff12a828..55daff90e62e2 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -21,7 +21,6 @@ use util::common::stmt_set; use util::ppaux::{note_and_explain_region, Repr, UserString}; use std::hashmap::{HashSet, HashMap}; -use std::io; use std::ops::{BitOr, BitAnd}; use std::result::{Result}; use syntax::ast; @@ -99,7 +98,7 @@ pub fn check_crate( visit::walk_crate(bccx, crate, ()); if tcx.sess.borrowck_stats() { - io::println("--- borrowck stats ---"); + println("--- borrowck stats ---"); println!("paths requiring guarantees: {}", bccx.stats.guaranteed_paths); println!("paths requiring loans : {}", diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 22fd1d393e972..7ad55936b9ed7 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -18,7 +18,7 @@ use std::cast; -use std::io; +use std::rt::io; use std::uint; use std::vec; use std::hashmap::HashMap; @@ -349,12 +349,12 @@ impl DataFlowContext { debug!("Dataflow result:"); debug!("{}", { let this = @(*self).clone(); - this.pretty_print_to(io::stderr(), blk); + this.pretty_print_to(@mut io::stderr() as @mut io::Writer, blk); "" }); } - fn pretty_print_to(@self, wr: @io::Writer, blk: &ast::Block) { + fn pretty_print_to(@self, wr: @mut io::Writer, blk: &ast::Block) { let ps = pprust::rust_printer_annotated(wr, self.tcx.sess.intr(), self as @pprust::pp_ann); diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 71934c9f2a7ed..695f4a6fd13b5 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -111,7 +111,8 @@ use middle::moves; use std::cast::transmute; use std::hashmap::HashMap; -use std::io; +use std::rt::io; +use std::str; use std::to_str; use std::uint; use std::vec; @@ -739,15 +740,14 @@ impl Liveness { } pub fn write_vars(&self, - wr: @io::Writer, + wr: &mut io::Writer, ln: LiveNode, test: &fn(uint) -> LiveNode) { let node_base_idx = self.idx(ln, Variable(0)); for var_idx in range(0u, self.ir.num_vars) { let idx = node_base_idx + var_idx; if test(idx).is_valid() { - wr.write_str(" "); - wr.write_str(Variable(var_idx).to_str()); + write!(wr, " {}", Variable(var_idx).to_str()); } } } @@ -784,20 +784,14 @@ impl Liveness { } pub fn ln_str(&self, ln: LiveNode) -> ~str { - do io::with_str_writer |wr| { - wr.write_str("[ln("); - wr.write_uint(*ln); - wr.write_str(") of kind "); - wr.write_str(format!("{:?}", self.ir.lnks[*ln])); - wr.write_str(" reads"); + str::from_utf8_owned(do io::mem::with_mem_writer |wr| { + let wr = wr as &mut io::Writer; + write!(wr, "[ln({}) of kind {:?} reads", *ln, self.ir.lnks[*ln]); self.write_vars(wr, ln, |idx| self.users[idx].reader ); - wr.write_str(" writes"); + write!(wr, " writes"); self.write_vars(wr, ln, |idx| self.users[idx].writer ); - wr.write_str(" "); - wr.write_str(" precedes "); - wr.write_str((self.successors[*ln]).to_str()); - wr.write_str("]"); - } + write!(wr, " precedes {}]", self.successors[*ln].to_str()); + }) } pub fn init_empty(&self, ln: LiveNode, succ_ln: LiveNode) { diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index df7b09f9db79a..8b5167b7e8fa5 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -70,7 +70,6 @@ use middle::trans::type_::Type; use std::c_str::ToCStr; use std::hash; use std::hashmap::HashMap; -use std::io; use std::libc::c_uint; use std::vec; use std::local_data; @@ -3163,7 +3162,7 @@ pub fn trans_crate(sess: session::Session, // Translate the metadata. write_metadata(ccx, &crate); if ccx.sess.trans_stats() { - io::println("--- trans stats ---"); + println("--- trans stats ---"); println!("n_static_tydescs: {}", ccx.stats.n_static_tydescs); println!("n_glues_created: {}", ccx.stats.n_glues_created); println!("n_null_glues: {}", ccx.stats.n_null_glues); @@ -3173,7 +3172,7 @@ pub fn trans_crate(sess: session::Session, println!("n_monos: {}", ccx.stats.n_monos); println!("n_inlines: {}", ccx.stats.n_inlines); println!("n_closures: {}", ccx.stats.n_closures); - io::println("fn stats:"); + println("fn stats:"); do sort::quick_sort(ccx.stats.fn_stats) |&(_, _, insns_a), &(_, _, insns_b)| { insns_a > insns_b } diff --git a/src/librustc/rustc.rs b/src/librustc/rustc.rs index ecf45d5c424cc..ce50397d00322 100644 --- a/src/librustc/rustc.rs +++ b/src/librustc/rustc.rs @@ -36,7 +36,8 @@ use driver::session; use middle::lint; use std::comm; -use std::io; +use std::rt::io; +use std::rt::io::extensions::ReaderUtil; use std::num; use std::os; use std::result; @@ -181,7 +182,7 @@ Available lint options: lint::level_to_str(spec.default), spec.desc); } - io::println(""); + println(""); } pub fn describe_debug_flags() { @@ -247,7 +248,7 @@ pub fn run_compiler(args: &[~str], demitter: @diagnostic::Emitter) { 1u => { let ifile = matches.free[0].as_slice(); if "-" == ifile { - let src = str::from_utf8(io::stdin().read_whole_stream()); + let src = str::from_utf8(io::stdin().read_to_end()); str_input(src.to_managed()) } else { file_input(Path::new(ifile)) @@ -275,7 +276,7 @@ pub fn run_compiler(args: &[~str], demitter: @diagnostic::Emitter) { if ls { match input { file_input(ref ifile) => { - list_metadata(sess, &(*ifile), io::stdout()); + list_metadata(sess, &(*ifile), @mut io::stdout() as @mut io::Writer); } str_input(_) => { early_error(demitter, "can not list metadata for stdin"); diff --git a/src/librustdoc/rustdoc.rs b/src/librustdoc/rustdoc.rs index 4c53fe48fe15c..c0fab1ad98f2f 100644 --- a/src/librustdoc/rustdoc.rs +++ b/src/librustdoc/rustdoc.rs @@ -28,6 +28,9 @@ use std::local_data; use std::rt::io::Writer; use std::rt::io::file::FileInfo; use std::rt::io; +use std::rt::io::mem::MemWriter; +use std::rt::io::Decorator; +use std::str; use extra::getopts; use extra::getopts::groups; use extra::json; @@ -257,11 +260,11 @@ fn rust_input(cratefile: &str, matches: &getopts::Matches) -> Output { /// This input format purely deserializes the json output file. No passes are /// run over the deserialized output. fn json_input(input: &str) -> Result { - let input = match ::std::io::file_reader(&Path::new(input)) { - Ok(i) => i, - Err(s) => return Err(s), + let input = match Path::new(input).open_reader(io::Open) { + Some(f) => f, + None => return Err(format!("couldn't open {} for reading", input)), }; - match json::from_reader(input) { + match json::from_reader(@mut input as @mut io::Reader) { Err(s) => Err(s.to_str()), Ok(json::Object(obj)) => { let mut obj = obj; @@ -306,8 +309,10 @@ fn json_output(crate: clean::Crate, res: ~[plugins::PluginJson], dst: Path) { // FIXME #8335: yuck, Rust -> str -> JSON round trip! No way to .encode // straight to the Rust JSON representation. - let crate_json_str = do std::io::with_str_writer |w| { - crate.encode(&mut json::Encoder(w)); + let crate_json_str = { + let w = @mut MemWriter::new(); + crate.encode(&mut json::Encoder(w as @mut io::Writer)); + str::from_utf8(*w.inner_ref()) }; let crate_json = match json::from_str(crate_json_str) { Ok(j) => j, diff --git a/src/librustpkg/context.rs b/src/librustpkg/context.rs index 72197219fc5ae..bee21d70b2d87 100644 --- a/src/librustpkg/context.rs +++ b/src/librustpkg/context.rs @@ -10,7 +10,7 @@ // Context data structure used by rustpkg -use std::{io, os}; +use std::os; use extra::workcache; use rustc::driver::session::{OptLevel, No}; @@ -243,43 +243,43 @@ pub fn flags_forbidden_for_cmd(flags: &RustcFlags, }; if flags.linker.is_some() && cmd != "build" && cmd != "install" { - io::println("The --linker option can only be used with the build or install commands."); + println("The --linker option can only be used with the build or install commands."); return true; } if flags.link_args.is_some() && cmd != "build" && cmd != "install" { - io::println("The --link-args option can only be used with the build or install commands."); + println("The --link-args option can only be used with the build or install commands."); return true; } if !cfgs.is_empty() && cmd != "build" && cmd != "install" { - io::println("The --cfg option can only be used with the build or install commands."); + println("The --cfg option can only be used with the build or install commands."); return true; } if user_supplied_opt_level && cmd != "build" && cmd != "install" { - io::println("The -O and --opt-level options can only be used with the build \ + println("The -O and --opt-level options can only be used with the build \ or install commands."); return true; } if flags.save_temps && cmd != "build" && cmd != "install" { - io::println("The --save-temps option can only be used with the build \ + println("The --save-temps option can only be used with the build \ or install commands."); return true; } if flags.target.is_some() && cmd != "build" && cmd != "install" { - io::println("The --target option can only be used with the build \ + println("The --target option can only be used with the build \ or install commands."); return true; } if flags.target_cpu.is_some() && cmd != "build" && cmd != "install" { - io::println("The --target-cpu option can only be used with the build \ + println("The --target-cpu option can only be used with the build \ or install commands."); return true; } if flags.experimental_features.is_some() && cmd != "build" && cmd != "install" { - io::println("The -Z option can only be used with the build or install commands."); + println("The -Z option can only be used with the build or install commands."); return true; } diff --git a/src/librustpkg/messages.rs b/src/librustpkg/messages.rs index 96c99a7a0f17e..79c8ff794ab56 100644 --- a/src/librustpkg/messages.rs +++ b/src/librustpkg/messages.rs @@ -9,31 +9,38 @@ // except according to those terms. use extra::term; -use std::io; +use std::rt::io; pub fn note(msg: &str) { - pretty_message(msg, "note: ", term::color::GREEN, io::stdout()) + pretty_message(msg, "note: ", term::color::GREEN, + @mut io::stdout() as @mut io::Writer) } pub fn warn(msg: &str) { - pretty_message(msg, "warning: ", term::color::YELLOW, io::stdout()) + pretty_message(msg, "warning: ", term::color::YELLOW, + @mut io::stdout() as @mut io::Writer) } pub fn error(msg: &str) { - pretty_message(msg, "error: ", term::color::RED, io::stdout()) + pretty_message(msg, "error: ", term::color::RED, + @mut io::stdout() as @mut io::Writer) } -fn pretty_message<'a>(msg: &'a str, prefix: &'a str, color: term::color::Color, out: @io::Writer) { +fn pretty_message<'a>(msg: &'a str, + prefix: &'a str, + color: term::color::Color, + out: @mut io::Writer) { let term = term::Terminal::new(out); match term { Ok(ref t) => { t.fg(color); - out.write_str(prefix); + out.write(prefix.as_bytes()); t.reset(); }, _ => { - out.write_str(prefix); + out.write(prefix.as_bytes()); } } - out.write_line(msg); + out.write(msg.as_bytes()); + out.write(['\n' as u8]); } diff --git a/src/librustpkg/rustpkg.rs b/src/librustpkg/rustpkg.rs index 2c1fdccd13c7e..bd3a1b2f67282 100644 --- a/src/librustpkg/rustpkg.rs +++ b/src/librustpkg/rustpkg.rs @@ -24,7 +24,7 @@ extern mod extra; extern mod rustc; extern mod syntax; -use std::{io, os, result, run, str, task}; +use std::{os, result, run, str, task}; pub use std::path::Path; use extra::workcache; @@ -346,7 +346,7 @@ impl CtxMethods for BuildContext { } } "list" => { - io::println("Installed packages:"); + println("Installed packages:"); do installed_packages::list_installed_packages |pkg_id| { do pkg_id.path.display().with_str |s| { println(s); @@ -726,7 +726,7 @@ impl CtxMethods for BuildContext { } pub fn main() { - io::println("WARNING: The Rust package manager is experimental and may be unstable"); + println("WARNING: The Rust package manager is experimental and may be unstable"); os::set_exit_status(main_args(os::args())); } diff --git a/src/librustpkg/source_control.rs b/src/librustpkg/source_control.rs index 9a571e0757084..c3e4205dfc972 100644 --- a/src/librustpkg/source_control.rs +++ b/src/librustpkg/source_control.rs @@ -10,7 +10,7 @@ // Utils for working with version control repositories. Just git right now. -use std::{io, os, run, str}; +use std::{os, run, str}; use std::run::{ProcessOutput, ProcessOptions, Process}; use extra::tempfile::TempDir; use version::*; @@ -36,8 +36,8 @@ pub fn safe_git_clone(source: &Path, v: &Version, target: &Path) -> CloneResult source.as_str().unwrap().to_owned(), target.as_str().unwrap().to_owned()]); if outp.status != 0 { - io::println(str::from_utf8_owned(outp.output.clone())); - io::println(str::from_utf8_owned(outp.error)); + println(str::from_utf8_owned(outp.output.clone())); + println(str::from_utf8_owned(outp.error)); return DirToUse(target.clone()); } else { @@ -52,8 +52,8 @@ pub fn safe_git_clone(source: &Path, v: &Version, target: &Path) -> CloneResult format!("--git-dir={}", git_dir.as_str().unwrap().to_owned()), ~"checkout", format!("{}", *s)]); if outp.status != 0 { - io::println(str::from_utf8_owned(outp.output.clone())); - io::println(str::from_utf8_owned(outp.error)); + println(str::from_utf8_owned(outp.output.clone())); + println(str::from_utf8_owned(outp.error)); return DirToUse(target.clone()); } } diff --git a/src/librustpkg/testsuite/fail/src/no-inferred-crates/src/zzyzx.rs b/src/librustpkg/testsuite/fail/src/no-inferred-crates/src/zzyzx.rs index 0fd68ca3a2042..6c9a63fe7bd8a 100644 --- a/src/librustpkg/testsuite/fail/src/no-inferred-crates/src/zzyzx.rs +++ b/src/librustpkg/testsuite/fail/src/no-inferred-crates/src/zzyzx.rs @@ -15,8 +15,6 @@ The test runner should check that, after `rustpkg build hello-world`: * testsuite/hello-world/build/ does not contain a library */ -use std::io; - fn main() { - io::println(~"Hello world!"); + println(~"Hello world!"); } diff --git a/src/librustpkg/testsuite/pass/src/hello-world/main.rs b/src/librustpkg/testsuite/pass/src/hello-world/main.rs index c8b2ce97c0c00..d4c65954fe629 100644 --- a/src/librustpkg/testsuite/pass/src/hello-world/main.rs +++ b/src/librustpkg/testsuite/pass/src/hello-world/main.rs @@ -18,8 +18,6 @@ The test runner should check that, after `rustpkg build hello-world`: * testsuite/pass/hello-world/build is empty */ -use std::io; - fn main() { - io::println(~"Hello world!"); + println(~"Hello world!"); } diff --git a/src/librustpkg/usage.rs b/src/librustpkg/usage.rs index 4b10451c81363..ef6ac485b7294 100644 --- a/src/librustpkg/usage.rs +++ b/src/librustpkg/usage.rs @@ -8,10 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::io; - pub fn general() { - io::println("Usage: rustpkg [options] [args..] + println("Usage: rustpkg [options] [args..] Where is one of: build, clean, do, info, install, list, prefer, test, uninstall, unprefer @@ -24,7 +22,7 @@ Options: } pub fn build() { - io::println("rustpkg build [options..] [package-ID] + println("rustpkg build [options..] [package-ID] Build the given package ID if specified. With no package ID argument, build the package in the current directory. In that case, the current @@ -50,21 +48,21 @@ Options: } pub fn clean() { - io::println("rustpkg clean + println("rustpkg clean Remove all build files in the work cache for the package in the current directory."); } pub fn do_cmd() { - io::println("rustpkg do + println("rustpkg do Runs a command in the package script. You can listen to a command by tagging a function with the attribute `#[pkg_do(cmd)]`."); } pub fn info() { - io::println("rustpkg [options..] info + println("rustpkg [options..] info Probe the package script in the current directory for information. @@ -73,13 +71,13 @@ Options: } pub fn list() { - io::println("rustpkg list + println("rustpkg list List all installed packages."); } pub fn install() { - io::println("rustpkg install [options..] [package-ID] + println("rustpkg install [options..] [package-ID] Install the given package ID if specified. With no package ID argument, install the package in the current directory. @@ -105,14 +103,14 @@ Options: } pub fn uninstall() { - io::println("rustpkg uninstall [@version] + println("rustpkg uninstall [@version] Remove a package by id or name and optionally version. If the package(s) is/are depended on by another package then they cannot be removed."); } pub fn prefer() { - io::println("rustpkg [options..] prefer [@version] + println("rustpkg [options..] prefer [@version] By default all binaries are given a unique name so that multiple versions can coexist. The prefer command will symlink the uniquely named binary to @@ -130,7 +128,7 @@ Example: } pub fn unprefer() { - io::println("rustpkg [options..] unprefer [@version] + println("rustpkg [options..] unprefer [@version] Remove all symlinks from the store to the binary directory for a package name and optionally version. If version is not supplied, the latest version @@ -139,7 +137,7 @@ information."); } pub fn test() { - io::println("rustpkg [options..] test + println("rustpkg [options..] test Build all test crates in the current directory with the test flag. Then, run all the resulting test executables, redirecting the output @@ -150,7 +148,7 @@ Options: } pub fn init() { - io::println("rustpkg init + println("rustpkg init This will turn the current working directory into a workspace. The first command you run when starting off a new project. diff --git a/src/librustpkg/workcache_support.rs b/src/librustpkg/workcache_support.rs index d49a581e07047..b68e42d8ebe24 100644 --- a/src/librustpkg/workcache_support.rs +++ b/src/librustpkg/workcache_support.rs @@ -8,21 +8,27 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::rt::io; +use std::rt::io::extensions::ReaderUtil; +use std::rt::io::file::FileInfo; + use extra::sha1::Sha1; use extra::digest::Digest; use extra::workcache; -use std::io; /// Hashes the file contents along with the last-modified time pub fn digest_file_with_date(path: &Path) -> ~str { use conditions::bad_path::cond; use cond1 = conditions::bad_stat::cond; - let s = io::read_whole_file_str(path); - match s { - Ok(s) => { + let mut err = None; + let bytes = do io::io_error::cond.trap(|e| err = Some(e)).inside { + path.open_reader(io::Open).read_to_end() + }; + match err { + None => { let mut sha = Sha1::new(); - sha.input_str(s); + sha.input(bytes); let st = match path.stat() { Some(st) => st, None => cond1.raise((path.clone(), format!("Couldn't get file access time"))) @@ -30,11 +36,9 @@ pub fn digest_file_with_date(path: &Path) -> ~str { sha.input_str(st.modified.to_str()); sha.result_str() } - Err(e) => { - let path = cond.raise((path.clone(), format!("Couldn't read file: {}", e))); - // FIXME (#9639): This needs to handle non-utf8 paths - // XXX: I'm pretty sure this is the wrong return value - path.as_str().unwrap().to_owned() + Some(e) => { + cond.raise((path.clone(), format!("Couldn't read file: {}", e.desc))); + ~"" } } } diff --git a/src/libstd/io.rs b/src/libstd/io.rs index 4e55c5fe60eb5..2ffe654d3bdbc 100644 --- a/src/libstd/io.rs +++ b/src/libstd/io.rs @@ -65,15 +65,17 @@ use ptr; use result::{Result, Ok, Err}; use str::{StrSlice, OwnedStr}; use str; -use to_str::ToStr; use uint; use vec::{MutableVector, ImmutableVector, OwnedVector, OwnedCopyableVector, CopyableVector}; use vec; +#[cfg(stage0)] +pub use rt::io::stdio::{print, println}; + #[allow(non_camel_case_types)] // not sure what to do about this -pub type fd_t = c_int; +type fd_t = c_int; -pub mod rustrt { +mod rustrt { use libc; #[link_name = "rustrt"] @@ -1013,7 +1015,7 @@ pub struct FILERes { } impl FILERes { - pub fn new(f: *libc::FILE) -> FILERes { + fn new(f: *libc::FILE) -> FILERes { FILERes { f: f } } } @@ -1028,37 +1030,6 @@ impl Drop for FILERes { } } -pub fn FILE_reader(f: *libc::FILE, cleanup: bool) -> @Reader { - if cleanup { - @Wrapper { base: f, cleanup: FILERes::new(f) } as @Reader - } else { - @f as @Reader - } -} - -// FIXME (#2004): this should either be an trait-less impl, a set of -// top-level functions that take a reader, or a set of default methods on -// reader (which can then be called reader) - -/** -* Gives a `Reader` that allows you to read values from standard input. -* -* # Example -* -* ```rust -* let stdin = std::io::stdin(); -* let line = stdin.read_line(); -* std::io::print(line); -* ``` -*/ -pub fn stdin() -> @Reader { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - @rustrt::rust_get_stdin() as @Reader - } -} - pub fn file_reader(path: &Path) -> Result<@Reader, ~str> { #[fixed_stack_segment]; #[inline(never)]; @@ -1073,71 +1044,10 @@ pub fn file_reader(path: &Path) -> Result<@Reader, ~str> { Err(~"error opening " + p) } } else { - Ok(FILE_reader(f, true)) - } -} - - -// Byte readers -pub struct BytesReader { - // FIXME(#5723) see other FIXME below - // FIXME(#7268) this should also be parameterized over <'self> - bytes: &'static [u8], - pos: @mut uint -} - -impl Reader for BytesReader { - fn read(&self, bytes: &mut [u8], len: uint) -> uint { - let count = num::min(len, self.bytes.len() - *self.pos); - - let view = self.bytes.slice(*self.pos, self.bytes.len()); - vec::bytes::copy_memory(bytes, view, count); - - *self.pos += count; - - count - } - - fn read_byte(&self) -> int { - if *self.pos == self.bytes.len() { - return -1; - } - - let b = self.bytes[*self.pos]; - *self.pos += 1u; - b as int - } - - fn eof(&self) -> bool { - *self.pos == self.bytes.len() - } - - fn seek(&self, offset: int, whence: SeekStyle) { - let pos = *self.pos; - *self.pos = seek_in_buf(offset, pos, self.bytes.len(), whence); - } - - fn tell(&self) -> uint { - *self.pos + Ok(@Wrapper { base: f, cleanup: FILERes::new(f) } as @Reader) } } -pub fn with_bytes_reader(bytes: &[u8], f: &fn(@Reader) -> T) -> T { - // XXX XXX XXX this is glaringly unsound - // FIXME(#5723) Use a &Reader for the callback's argument. Should be: - // fn with_bytes_reader<'r, T>(bytes: &'r [u8], f: &fn(&'r Reader) -> T) -> T - let bytes: &'static [u8] = unsafe { cast::transmute(bytes) }; - f(@BytesReader { - bytes: bytes, - pos: @mut 0 - } as @Reader) -} - -pub fn with_str_reader(s: &str, f: &fn(@Reader) -> T) -> T { - // FIXME(#5723): As above. - with_bytes_reader(s.as_bytes(), f) -} - // Writing pub enum FileFlag { Append, Create, Truncate, NoFlag, } @@ -1286,7 +1196,7 @@ pub struct FdRes { } impl FdRes { - pub fn new(fd: fd_t) -> FdRes { + fn new(fd: fd_t) -> FdRes { FdRes { fd: fd } } } @@ -1301,15 +1211,6 @@ impl Drop for FdRes { } } -pub fn fd_writer(fd: fd_t, cleanup: bool) -> @Writer { - if cleanup { - @Wrapper { base: fd, cleanup: FdRes::new(fd) } as @Writer - } else { - @fd as @Writer - } -} - - pub fn mk_file_writer(path: &Path, flags: &[FileFlag]) -> Result<@Writer, ~str> { #[fixed_stack_segment]; #[inline(never)]; @@ -1339,7 +1240,7 @@ pub fn mk_file_writer(path: &Path, flags: &[FileFlag]) if fd < (0 as c_int) { Err(format!("error opening {}: {}", path.display(), os::last_os_error())) } else { - Ok(fd_writer(fd, true)) + Ok(@Wrapper { base: fd, cleanup: FdRes::new(fd) } as @Writer) } } @@ -1615,64 +1516,6 @@ pub fn file_writer(path: &Path, flags: &[FileFlag]) -> Result<@Writer, ~str> { // FIXME (#2004) why are these different from the way stdin() is // implemented? - -/** -* Gives a `Writer` which allows you to write to the standard output. -* -* # Example -* -* ```rust -* let stdout = std::io::stdout(); -* stdout.write_str("hello\n"); -* ``` -*/ -pub fn stdout() -> @Writer { fd_writer(libc::STDOUT_FILENO as c_int, false) } - -/** -* Gives a `Writer` which allows you to write to standard error. -* -* # Example -* -* ```rust -* let stderr = std::io::stderr(); -* stderr.write_str("hello\n"); -* ``` -*/ -pub fn stderr() -> @Writer { fd_writer(libc::STDERR_FILENO as c_int, false) } - -/** -* Prints a string to standard output. -* -* This string will not have an implicit newline at the end. If you want -* an implicit newline, please see `println`. -* -* # Example -* -* ```rust -* // print is imported into the prelude, and so is always available. -* print("hello"); -* ``` -*/ -pub fn print(s: &str) { - stdout().write_str(s); -} - -/** -* Prints a string to standard output, followed by a newline. -* -* If you do not want an implicit newline, please see `print`. -* -* # Example -* -* ```rust -* // println is imported into the prelude, and so is always available. -* println("hello"); -* ``` -*/ -pub fn println(s: &str) { - stdout().write_line(s); -} - pub struct BytesWriter { bytes: @mut ~[u8], pos: @mut uint, @@ -1736,7 +1579,7 @@ pub fn with_str_writer(f: &fn(@Writer)) -> ~str { } // Utility functions -pub fn seek_in_buf(offset: int, pos: uint, len: uint, whence: SeekStyle) -> +fn seek_in_buf(offset: int, pos: uint, len: uint, whence: SeekStyle) -> uint { let mut bpos = pos as int; let blen = len as int; @@ -1749,137 +1592,6 @@ pub fn seek_in_buf(offset: int, pos: uint, len: uint, whence: SeekStyle) -> return bpos as uint; } -pub fn read_whole_file_str(file: &Path) -> Result<~str, ~str> { - do read_whole_file(file).and_then |bytes| { - if str::is_utf8(bytes) { - Ok(str::from_utf8(bytes)) - } else { - Err(file.display().to_str() + " is not UTF-8") - } - } -} - -// FIXME (#2004): implement this in a low-level way. Going through the -// abstractions is pointless. -pub fn read_whole_file(file: &Path) -> Result<~[u8], ~str> { - do file_reader(file).and_then |rdr| { - Ok(rdr.read_whole_stream()) - } -} - -// fsync related - -pub mod fsync { - use io::{FILERes, FdRes, fd_t}; - use libc; - use ops::Drop; - use option::{None, Option, Some}; - use os; - - pub enum Level { - // whatever fsync does on that platform - FSync, - - // fdatasync on linux, similiar or more on other platforms - FDataSync, - - // full fsync - // - // You must additionally sync the parent directory as well! - FullFSync, - } - - - // Artifacts that need to fsync on destruction - pub struct Res { - priv arg: Arg, - } - - impl Res { - pub fn new(arg: Arg) -> Res { - Res { arg: arg } - } - } - - #[unsafe_destructor] - impl Drop for Res { - fn drop(&mut self) { - match self.arg.opt_level { - None => (), - Some(level) => { - // fail hard if not succesful - assert!(((self.arg.fsync_fn)(&self.arg.val, level) != -1)); - } - } - } - } - - pub struct Arg { - priv val: t, - priv opt_level: Option, - priv fsync_fn: extern "Rust" fn(f: &t, Level) -> int, - } - - // fsync file after executing blk - // FIXME (#2004) find better way to create resources within lifetime of - // outer res - pub fn FILE_res_sync(file: &FILERes, - opt_level: Option, - blk: &fn(v: Res<*libc::FILE>)) { - blk(Res::new(Arg { - val: file.f, - opt_level: opt_level, - fsync_fn: fsync_FILE, - })); - - fn fileno(stream: *libc::FILE) -> libc::c_int { - #[fixed_stack_segment]; #[inline(never)]; - unsafe { libc::fileno(stream) } - } - - fn fsync_FILE(stream: &*libc::FILE, level: Level) -> int { - fsync_fd(fileno(*stream), level) - } - } - - // fsync fd after executing blk - pub fn fd_res_sync(fd: &FdRes, opt_level: Option, - blk: &fn(v: Res)) { - blk(Res::new(Arg { - val: fd.fd, - opt_level: opt_level, - fsync_fn: fsync_fd_helper, - })); - } - - fn fsync_fd(fd: libc::c_int, level: Level) -> int { - #[fixed_stack_segment]; #[inline(never)]; - - os::fsync_fd(fd, level) as int - } - - fn fsync_fd_helper(fd_ptr: &libc::c_int, level: Level) -> int { - fsync_fd(*fd_ptr, level) - } - - // Type of objects that may want to fsync - pub trait FSyncable { fn fsync(&self, l: Level) -> int; } - - // Call o.fsync after executing blk - pub fn obj_sync(o: @FSyncable, opt_level: Option, - blk: &fn(v: Res<@FSyncable>)) { - blk(Res::new(Arg { - val: o, - opt_level: opt_level, - fsync_fn: obj_fsync_fn, - })); - } - - fn obj_fsync_fn(o: &@FSyncable, level: Level) -> int { - (*o).fsync(level) - } -} - #[cfg(test)] mod tests { use prelude::*; @@ -1934,82 +1646,6 @@ mod tests { } } - #[test] - fn test_readchars_empty() { - do io::with_str_reader("") |inp| { - let res : ~[char] = inp.read_chars(128); - assert_eq!(res.len(), 0); - } - } - - #[test] - fn test_read_line_utf8() { - do io::with_str_reader("生锈的汤匙切肉汤hello生锈的汤匙切肉汤") |inp| { - let line = inp.read_line(); - assert_eq!(line, ~"生锈的汤匙切肉汤hello生锈的汤匙切肉汤"); - } - } - - #[test] - fn test_read_lines() { - do io::with_str_reader("a\nb\nc\n") |inp| { - assert_eq!(inp.read_lines(), ~[~"a", ~"b", ~"c"]); - } - - do io::with_str_reader("a\nb\nc") |inp| { - assert_eq!(inp.read_lines(), ~[~"a", ~"b", ~"c"]); - } - - do io::with_str_reader("") |inp| { - assert!(inp.read_lines().is_empty()); - } - } - - #[test] - fn test_readchars_wide() { - let wide_test = ~"生锈的汤匙切肉汤hello生锈的汤匙切肉汤"; - let ivals : ~[int] = ~[ - 29983, 38152, 30340, 27748, - 21273, 20999, 32905, 27748, - 104, 101, 108, 108, 111, - 29983, 38152, 30340, 27748, - 21273, 20999, 32905, 27748]; - fn check_read_ln(len : uint, s: &str, ivals: &[int]) { - do io::with_str_reader(s) |inp| { - let res : ~[char] = inp.read_chars(len); - if len <= ivals.len() { - assert_eq!(res.len(), len); - } - for (iv, c) in ivals.iter().zip(res.iter()) { - assert!(*iv == *c as int) - } - } - } - let mut i = 0; - while i < 8 { - check_read_ln(i, wide_test, ivals); - i += 1; - } - // check a long read for good measure - check_read_ln(128, wide_test, ivals); - } - - #[test] - fn test_readchar() { - do io::with_str_reader("生") |inp| { - let res = inp.read_char(); - assert_eq!(res as int, 29983); - } - } - - #[test] - fn test_readchar_empty() { - do io::with_str_reader("") |inp| { - let res = inp.read_char(); - assert_eq!(res, unsafe { transmute(-1u32) }); // FIXME: #8971: unsound - } - } - #[test] fn file_reader_not_exist() { match io::file_reader(&Path::new("not a file")) { diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 65190c5d8d623..99930b39a6533 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -32,7 +32,6 @@ use c_str::CString; use clone::Clone; use container::Container; -use io; use iter::range; use libc; use libc::{c_char, c_void, c_int, size_t}; @@ -356,64 +355,6 @@ pub fn fdopen(fd: c_int) -> *FILE { } } - -// fsync related - -#[cfg(windows)] -pub fn fsync_fd(fd: c_int, _level: io::fsync::Level) -> c_int { - #[fixed_stack_segment]; #[inline(never)]; - unsafe { - use libc::funcs::extra::msvcrt::*; - return commit(fd); - } -} - -#[cfg(target_os = "linux")] -#[cfg(target_os = "android")] -pub fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int { - #[fixed_stack_segment]; #[inline(never)]; - unsafe { - use libc::funcs::posix01::unistd::*; - match level { - io::fsync::FSync - | io::fsync::FullFSync => return fsync(fd), - io::fsync::FDataSync => return fdatasync(fd) - } - } -} - -#[cfg(target_os = "macos")] -pub fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - use libc::consts::os::extra::*; - use libc::funcs::posix88::fcntl::*; - use libc::funcs::posix01::unistd::*; - match level { - io::fsync::FSync => return fsync(fd), - _ => { - // According to man fnctl, the ok retval is only specified to be - // !=-1 - if (fcntl(F_FULLFSYNC as c_int, fd) == -1 as c_int) - { return -1 as c_int; } - else - { return 0 as c_int; } - } - } - } -} - -#[cfg(target_os = "freebsd")] -pub fn fsync_fd(fd: c_int, _l: io::fsync::Level) -> c_int { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - use libc::funcs::posix01::unistd::*; - return fsync(fd); - } -} - pub struct Pipe { input: c_int, out: c_int diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 1d9d5512ff424..456d344b838c5 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -962,7 +962,6 @@ pub fn segments_name_eq(a : &[ast::PathSegment], b : &[ast::PathSegment]) -> boo mod test { use ast::*; use super::*; - use std::io; use opt_vec; use std::hashmap::HashMap; @@ -1137,7 +1136,7 @@ mod test { // - two renames of the same var.. can only happen if you use // local-expand to prevent the inner binding from being renamed // during the rename-pass caused by the first: - io::println("about to run bad test"); + println("about to run bad test"); { let sc = unfold_test_sc(~[R(id(a,EMPTY_CTXT),50), R(id(a,EMPTY_CTXT),51)], EMPTY_CTXT,&mut t); diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index bbbaf2a2f6042..736f92910af20 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -11,7 +11,7 @@ use codemap::{Pos, Span}; use codemap; -use std::io; +use std::rt::io; use std::local_data; use extra::term; @@ -199,9 +199,14 @@ fn diagnosticcolor(lvl: level) -> term::color::Color { fn print_maybe_styled(msg: &str, color: term::attr::Attr) { local_data_key!(tls_terminal: @Option) - let stderr = io::stderr(); + let stderr = @mut io::stderr() as @mut io::Writer; + fn is_stderr_screen() -> bool { + #[fixed_stack_segment]; + use std::libc; + unsafe { libc::isatty(libc::STDERR_FILENO) != 0 } + } - if stderr.get_type() == io::Screen { + if is_stderr_screen() { let t = match local_data::get(tls_terminal, |v| v.map(|k| *k)) { None => { let t = term::Terminal::new(stderr); @@ -218,21 +223,21 @@ fn print_maybe_styled(msg: &str, color: term::attr::Attr) { match t { &Some(ref term) => { term.attr(color); - stderr.write_str(msg); + write!(stderr, "{}", msg); term.reset(); }, - _ => stderr.write_str(msg) + _ => write!(stderr, "{}", msg) } } else { - stderr.write_str(msg); + write!(stderr, "{}", msg); } } fn print_diagnostic(topic: &str, lvl: level, msg: &str) { - let stderr = io::stderr(); + let mut stderr = io::stderr(); if !topic.is_empty() { - stderr.write_str(format!("{} ", topic)); + write!(&mut stderr as &mut io::Writer, "{} ", topic); } print_maybe_styled(format!("{}: ", diagnosticstr(lvl)), @@ -266,6 +271,8 @@ fn highlight_lines(cm: @codemap::CodeMap, lvl: level, lines: @codemap::FileLines) { let fm = lines.file; + let mut err = io::stderr(); + let err = &mut err as &mut io::Writer; // arbitrarily only print up to six lines of the error let max_lines = 6u; @@ -277,21 +284,12 @@ fn highlight_lines(cm: @codemap::CodeMap, } // Print the offending lines for line in display_lines.iter() { - io::stderr().write_str(format!("{}:{} ", fm.name, *line + 1u)); - let s = fm.get_line(*line as int) + "\n"; - io::stderr().write_str(s); + write!(err, "{}:{} {}\n", fm.name, *line + 1, fm.get_line(*line as int)); } if elided { let last_line = display_lines[display_lines.len() - 1u]; let s = format!("{}:{} ", fm.name, last_line + 1u); - let mut indent = s.len(); - let mut out = ~""; - while indent > 0u { - out.push_char(' '); - indent -= 1u; - } - out.push_str("...\n"); - io::stderr().write_str(out); + write!(err, "{0:1$}...\n", "", s.len()); } // FIXME (#3260) @@ -325,7 +323,7 @@ fn highlight_lines(cm: @codemap::CodeMap, _ => s.push_char(' '), }; } - io::stderr().write_str(s); + write!(err, "{}", s); let mut s = ~"^"; let hi = cm.lookup_char_pos(sp.hi); if hi.col != lo.col { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 1018e79aabc6e..99bcb36eedbf5 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1524,7 +1524,8 @@ mod test { } fn fake_print_crate(crate: &ast::Crate) { - let s = pprust::rust_printer(std::io::stderr(),get_ident_interner()); + let out = @mut std::rt::io::stderr() as @mut std::rt::io::Writer; + let s = pprust::rust_printer(out, get_ident_interner()); pprust::print_crate_(s, crate); } @@ -1536,7 +1537,7 @@ mod test { //fn expand_and_resolve(crate_str: @str) -> ast::crate { //let expanded_ast = expand_crate_str(crate_str); - // std::io::println(format!("expanded: {:?}\n",expanded_ast)); + // println(format!("expanded: {:?}\n",expanded_ast)); //mtwt_resolve_crate(expanded_ast) //} //fn expand_and_resolve_and_pretty_print (crate_str : @str) -> ~str { @@ -1645,9 +1646,9 @@ mod test { let varref_marks = mtwt_marksof(varref.segments[0].identifier.ctxt, invalid_name); if (!(varref_name==binding_name)){ - std::io::println("uh oh, should match but doesn't:"); - std::io::println(format!("varref: {:?}",varref)); - std::io::println(format!("binding: {:?}", bindings[binding_idx])); + println("uh oh, should match but doesn't:"); + println!("varref: {:?}",varref); + println!("binding: {:?}", bindings[binding_idx]); ast_util::display_sctable(get_sctable()); } assert_eq!(varref_name,binding_name); @@ -1665,12 +1666,12 @@ mod test { println!("text of test case: \"{}\"", teststr); println!(""); println!("uh oh, matches but shouldn't:"); - std::io::println(format!("varref: {:?}",varref)); + println!("varref: {:?}",varref); // good lord, you can't make a path with 0 segments, can you? println!("varref's first segment's uint: {}, and string: \"{}\"", varref.segments[0].identifier.name, ident_to_str(&varref.segments[0].identifier)); - std::io::println(format!("binding: {:?}", bindings[binding_idx])); + println!("binding: {:?}", bindings[binding_idx]); ast_util::display_sctable(get_sctable()); } assert!(!fail); @@ -1703,17 +1704,17 @@ foo_module!() && (@"xx" == (ident_to_str(&p.segments[0].identifier))) }).enumerate() { if (mtwt_resolve(v.segments[0].identifier) != resolved_binding) { - std::io::println("uh oh, xx binding didn't match xx varref:"); - std::io::println(format!("this is xx varref \\# {:?}",idx)); - std::io::println(format!("binding: {:?}",cxbind)); - std::io::println(format!("resolves to: {:?}",resolved_binding)); - std::io::println(format!("varref: {:?}",v.segments[0].identifier)); - std::io::println(format!("resolves to: {:?}", - mtwt_resolve(v.segments[0].identifier))); + println("uh oh, xx binding didn't match xx varref:"); + println!("this is xx varref \\# {:?}",idx); + println!("binding: {:?}",cxbind); + println!("resolves to: {:?}",resolved_binding); + println!("varref: {:?}",v.segments[0].identifier); + println!("resolves to: {:?}", + mtwt_resolve(v.segments[0].identifier)); let table = get_sctable(); - std::io::println("SC table:"); + println("SC table:"); for (idx,val) in table.table.iter().enumerate() { - std::io::println(format!("{:4u} : {:?}",idx,val)); + println!("{:4u} : {:?}",idx,val); } } assert_eq!(mtwt_resolve(v.segments[0].identifier),resolved_binding); diff --git a/src/libsyntax/ext/log_syntax.rs b/src/libsyntax/ext/log_syntax.rs index 52807009073b1..3e07b16221ec1 100644 --- a/src/libsyntax/ext/log_syntax.rs +++ b/src/libsyntax/ext/log_syntax.rs @@ -15,15 +15,13 @@ use ext::base; use print; use parse::token::{get_ident_interner}; -use std::io; - pub fn expand_syntax_ext(cx: @ExtCtxt, sp: codemap::Span, tt: &[ast::token_tree]) -> base::MacResult { cx.print_backtrace(); - io::stdout().write_line( + println( print::pprust::tt_to_str( &ast::tt_delim(@mut tt.to_owned()), get_ident_interner())); diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index dcfeb99365a7b..df177cf75dc72 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -19,8 +19,10 @@ use parse; use parse::token::{get_ident_interner}; use print::pprust; -use std::io; -use std::result; +use std::rt::io; +use std::rt::io::extensions::ReaderUtil; +use std::rt::io::file::FileInfo; +use std::str; // These macros all relate to the file system; they either return // the column/row/filename of the expression, or they include @@ -89,14 +91,23 @@ pub fn expand_include(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree]) pub fn expand_include_str(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree]) -> base::MacResult { let file = get_single_str_from_tts(cx, sp, tts, "include_str!"); - let res = io::read_whole_file_str(&res_rel_file(cx, sp, &Path::new(file))); - match res { - result::Ok(res) => { - base::MRExpr(cx.expr_str(sp, res.to_managed())) - } - result::Err(e) => { - cx.span_fatal(sp, e); - } + let file = res_rel_file(cx, sp, &Path::new(file)); + let mut error = None; + let bytes = do io::read_error::cond.trap(|e| error = Some(e)).inside { + file.open_reader(io::Open).read_to_end() + }; + match error { + Some(e) => { + cx.span_fatal(sp, format!("couldn't read {}: {}", + file.display(), e.desc)); + } + None => {} + } + match str::from_utf8_owned_opt(bytes) { + Some(s) => base::MRExpr(cx.expr_str(sp, s.to_managed())), + None => { + cx.span_fatal(sp, format!("{} wasn't a utf-8 file", file.display())); + } } } @@ -106,13 +117,21 @@ pub fn expand_include_bin(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree]) use std::at_vec; let file = get_single_str_from_tts(cx, sp, tts, "include_bin!"); - match io::read_whole_file(&res_rel_file(cx, sp, &Path::new(file))) { - result::Ok(src) => { - let v = at_vec::to_managed_move(src); - base::MRExpr(cx.expr_lit(sp, ast::lit_binary(v))) + let file = res_rel_file(cx, sp, &Path::new(file)); + + let mut error = None; + let bytes = do io::read_error::cond.trap(|e| error = Some(e)).inside { + do io::io_error::cond.trap(|e| error = Some(e)).inside { + file.open_reader(io::Open).read_to_end() + } + }; + match error { + Some(e) => { + cx.span_fatal(sp, format!("couldn't read {}: {}", + file.display(), e.desc)); } - result::Err(ref e) => { - cx.parse_sess().span_diagnostic.handler().fatal((*e)) + None => { + base::MRExpr(cx.expr_lit(sp, ast::lit_binary(bytes))) } } } diff --git a/src/libsyntax/parse/comments.rs b/src/libsyntax/parse/comments.rs index 38921648a2bc6..e9e6eb872c86f 100644 --- a/src/libsyntax/parse/comments.rs +++ b/src/libsyntax/parse/comments.rs @@ -18,7 +18,8 @@ use parse::lexer; use parse::token; use parse::token::{get_ident_interner}; -use std::io; +use std::rt::io; +use std::rt::io::extensions::ReaderUtil; use std::str; use std::uint; @@ -346,9 +347,9 @@ pub struct lit { pub fn gather_comments_and_literals(span_diagnostic: @mut diagnostic::span_handler, path: @str, - srdr: @io::Reader) + mut srdr: &mut io::Reader) -> (~[cmnt], ~[lit]) { - let src = str::from_utf8(srdr.read_whole_stream()).to_managed(); + let src = str::from_utf8(srdr.read_to_end()).to_managed(); let cm = CodeMap::new(); let filemap = cm.new_filemap(path, src); let rdr = lexer::new_low_level_string_reader(span_diagnostic, filemap); diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index c9405d72464bb..93e5d3dd7727f 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -19,8 +19,11 @@ use parse::attr::parser_attr; use parse::lexer::reader; use parse::parser::Parser; -use std::io; use std::path::Path; +use std::rt::io; +use std::rt::io::extensions::ReaderUtil; +use std::rt::io::file::FileInfo; +use std::str; pub mod lexer; pub mod parser; @@ -260,16 +263,34 @@ pub fn new_parser_from_tts(sess: @mut ParseSess, /// add the path to the session's codemap and return the new filemap. pub fn file_to_filemap(sess: @mut ParseSess, path: &Path, spanopt: Option) -> @FileMap { - match io::read_whole_file_str(path) { - // FIXME (#9639): This needs to handle non-utf8 paths - Ok(src) => string_to_filemap(sess, src.to_managed(), path.as_str().unwrap().to_managed()), - Err(e) => { - match spanopt { - Some(span) => sess.span_diagnostic.span_fatal(span, e), - None => sess.span_diagnostic.handler().fatal(e) - } + let err = |msg: &str| { + match spanopt { + Some(sp) => sess.span_diagnostic.span_fatal(sp, msg), + None => sess.span_diagnostic.handler().fatal(msg), + } + }; + let mut error = None; + let bytes = do io::io_error::cond.trap(|e| error = Some(e)).inside { + do io::read_error::cond.trap(|e| error = Some(e)).inside { + path.open_reader(io::Open).read_to_end() } + }; + match error { + Some(e) => { + err(format!("couldn't read {}: {}", path.display(), e.desc)); + } + None => {} } + match str::from_utf8_owned_opt(bytes) { + Some(s) => { + return string_to_filemap(sess, s.to_managed(), + path.as_str().unwrap().to_managed()); + } + None => { + err(format!("{} is not UTF-8 encoded", path.display())) + } + } + unreachable!() } // given a session and a string, add the string to @@ -318,7 +339,10 @@ mod test { use super::*; use extra::serialize::Encodable; use extra; - use std::io; + use std::rt::io; + use std::rt::io::Decorator; + use std::rt::io::mem::MemWriter; + use std::str; use codemap::{Span, BytePos, Spanned}; use opt_vec; use ast; @@ -330,10 +354,10 @@ mod test { use util::parser_testing::string_to_stmt; #[cfg(test)] fn to_json_str>(val: @E) -> ~str { - do io::with_str_writer |writer| { - let mut encoder = extra::json::Encoder(writer); - val.encode(&mut encoder); - } + let writer = @mut MemWriter::new(); + let mut encoder = extra::json::Encoder(writer as @mut io::Writer); + val.encode(&mut encoder); + str::from_utf8(*writer.inner_ref()) } // produce a codemap::span diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs index 871584003b51e..4801fa21fc493 100644 --- a/src/libsyntax/print/pp.rs +++ b/src/libsyntax/print/pp.rs @@ -61,7 +61,7 @@ * avoid combining it with other lines and making matters even worse. */ -use std::io; +use std::rt::io; use std::vec; #[deriving(Clone, Eq)] @@ -148,7 +148,7 @@ pub struct print_stack_elt { pub static size_infinity: int = 0xffff; -pub fn mk_printer(out: @io::Writer, linewidth: uint) -> @mut Printer { +pub fn mk_printer(out: @mut io::Writer, linewidth: uint) -> @mut Printer { // Yes 3, it makes the ring buffers big enough to never // fall behind. let n: uint = 3 * linewidth; @@ -157,7 +157,7 @@ pub fn mk_printer(out: @io::Writer, linewidth: uint) -> @mut Printer { let size: ~[int] = vec::from_elem(n, 0); let scan_stack: ~[uint] = vec::from_elem(n, 0u); @mut Printer { - out: @out, + out: out, buf_len: n, margin: linewidth as int, space: linewidth as int, @@ -255,7 +255,7 @@ pub fn mk_printer(out: @io::Writer, linewidth: uint) -> @mut Printer { * called 'print'. */ pub struct Printer { - out: @@io::Writer, + out: @mut io::Writer, buf_len: uint, margin: int, // width of lines we're constrained to space: int, // number of spaces left on line @@ -452,7 +452,7 @@ impl Printer { } pub fn print_newline(&mut self, amount: int) { debug!("NEWLINE {}", amount); - (*self.out).write_str("\n"); + write!(self.out, "\n"); self.pending_indentation = 0; self.indent(amount); } @@ -474,10 +474,10 @@ impl Printer { } pub fn print_str(&mut self, s: &str) { while self.pending_indentation > 0 { - (*self.out).write_str(" "); + write!(self.out, " "); self.pending_indentation -= 1; } - (*self.out).write_str(s); + write!(self.out, "{}", s); } pub fn print(&mut self, x: token, L: int) { debug!("print {} {} (remaining line space={})", tok_str(x), L, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 0e330da31e623..400ff80448523 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -28,7 +28,10 @@ use print::pp; use print::pprust; use std::char; -use std::io; +use std::str; +use std::rt::io; +use std::rt::io::Decorator; +use std::rt::io::mem::MemWriter; // The @ps is stored here to prevent recursive type. pub enum ann_node<'self> { @@ -83,11 +86,11 @@ pub fn end(s: @ps) { pp::end(s.s); } -pub fn rust_printer(writer: @io::Writer, intr: @ident_interner) -> @ps { +pub fn rust_printer(writer: @mut io::Writer, intr: @ident_interner) -> @ps { return rust_printer_annotated(writer, intr, @no_ann::new() as @pp_ann); } -pub fn rust_printer_annotated(writer: @io::Writer, +pub fn rust_printer_annotated(writer: @mut io::Writer, intr: @ident_interner, ann: @pp_ann) -> @ps { @@ -118,8 +121,8 @@ pub fn print_crate(cm: @CodeMap, span_diagnostic: @mut diagnostic::span_handler, crate: &ast::Crate, filename: @str, - input: @io::Reader, - out: @io::Writer, + input: @mut io::Reader, + out: @mut io::Writer, ann: @pp_ann, is_expanded: bool) { let (cmnts, lits) = comments::gather_comments_and_literals( @@ -200,26 +203,26 @@ pub fn path_to_str(p: &ast::Path, intr: @ident_interner) -> ~str { pub fn fun_to_str(decl: &ast::fn_decl, purity: ast::purity, name: ast::Ident, opt_explicit_self: Option, generics: &ast::Generics, intr: @ident_interner) -> ~str { - do io::with_str_writer |wr| { - let s = rust_printer(wr, intr); - print_fn(s, decl, Some(purity), AbiSet::Rust(), - name, generics, opt_explicit_self, ast::inherited); - end(s); // Close the head box - end(s); // Close the outer box - eof(s.s); - } + let wr = @mut MemWriter::new(); + let s = rust_printer(wr as @mut io::Writer, intr); + print_fn(s, decl, Some(purity), AbiSet::Rust(), + name, generics, opt_explicit_self, ast::inherited); + end(s); // Close the head box + end(s); // Close the outer box + eof(s.s); + str::from_utf8(*wr.inner_ref()) } pub fn block_to_str(blk: &ast::Block, intr: @ident_interner) -> ~str { - do io::with_str_writer |wr| { - let s = rust_printer(wr, intr); - // containing cbox, will be closed by print-block at } - cbox(s, indent_unit); - // head-ibox, will be closed by print-block after { - ibox(s, 0u); - print_block(s, blk); - eof(s.s); - } + let wr = @mut MemWriter::new(); + let s = rust_printer(wr as @mut io::Writer, intr); + // containing cbox, will be closed by print-block at } + cbox(s, indent_unit); + // head-ibox, will be closed by print-block after { + ibox(s, 0u); + print_block(s, blk); + eof(s.s); + str::from_utf8(*wr.inner_ref()) } pub fn meta_item_to_str(mi: &ast::MetaItem, intr: @ident_interner) -> ~str { @@ -2196,11 +2199,11 @@ pub fn print_string(s: @ps, st: &str, style: ast::StrStyle) { } pub fn to_str(t: &T, f: &fn(@ps, &T), intr: @ident_interner) -> ~str { - do io::with_str_writer |wr| { - let s = rust_printer(wr, intr); - f(s, t); - eof(s.s); - } + let wr = @mut MemWriter::new(); + let s = rust_printer(wr as @mut io::Writer, intr); + f(s, t); + eof(s.s); + str::from_utf8(*wr.inner_ref()) } pub fn next_comment(s: @ps) -> Option { diff --git a/src/test/bench/core-map.rs b/src/test/bench/core-map.rs index 2d209e40e4249..f91327b6a6521 100644 --- a/src/test/bench/core-map.rs +++ b/src/test/bench/core-map.rs @@ -13,7 +13,6 @@ extern mod extra; use extra::time; use extra::treemap::TreeMap; use std::hashmap::{HashMap, HashSet}; -use std::io; use std::os; use std::rand::{Rng, IsaacRng, SeedableRng}; use std::trie::TrieMap; @@ -28,7 +27,7 @@ fn timed(label: &str, f: &fn()) { } fn ascending>(map: &mut M, n_keys: uint) { - io::println(" Ascending integers:"); + println(" Ascending integers:"); do timed("insert") { for i in range(0u, n_keys) { @@ -50,7 +49,7 @@ fn ascending>(map: &mut M, n_keys: uint) { } fn descending>(map: &mut M, n_keys: uint) { - io::println(" Descending integers:"); + println(" Descending integers:"); do timed("insert") { for i in range(0, n_keys).invert() { @@ -118,7 +117,7 @@ fn main() { println!("{} keys", n_keys); - io::println("\nTreeMap:"); + println("\nTreeMap:"); { let mut map: TreeMap = TreeMap::new(); @@ -131,12 +130,12 @@ fn main() { } { - io::println(" Random integers:"); + println(" Random integers:"); let mut map: TreeMap = TreeMap::new(); vector(&mut map, n_keys, rand); } - io::println("\nHashMap:"); + println("\nHashMap:"); { let mut map: HashMap = HashMap::new(); @@ -149,12 +148,12 @@ fn main() { } { - io::println(" Random integers:"); + println(" Random integers:"); let mut map: HashMap = HashMap::new(); vector(&mut map, n_keys, rand); } - io::println("\nTrieMap:"); + println("\nTrieMap:"); { let mut map: TrieMap = TrieMap::new(); @@ -167,7 +166,7 @@ fn main() { } { - io::println(" Random integers:"); + println(" Random integers:"); let mut map: TrieMap = TrieMap::new(); vector(&mut map, n_keys, rand); } diff --git a/src/test/bench/core-set.rs b/src/test/bench/core-set.rs index b9a8e74668fa9..9f65dc1e5555b 100644 --- a/src/test/bench/core-set.rs +++ b/src/test/bench/core-set.rs @@ -13,7 +13,6 @@ extern mod extra; use extra::bitv::BitvSet; use extra::treemap::TreeSet; use std::hashmap::HashSet; -use std::io; use std::os; use std::rand; use std::uint; @@ -123,12 +122,11 @@ impl Results { } fn write_header(header: &str) { - io::stdout().write_str(header); - io::stdout().write_str("\n"); + println(header); } fn write_row(label: &str, value: f64) { - io::stdout().write_str(format!("{:30s} {} s\n", label, value)); + println!("{:30s} {} s\n", label, value); } fn write_results(label: &str, results: &Results) { diff --git a/src/test/bench/msgsend-pipes-shared.rs b/src/test/bench/msgsend-pipes-shared.rs index 97479fc133a67..2a5971be216b8 100644 --- a/src/test/bench/msgsend-pipes-shared.rs +++ b/src/test/bench/msgsend-pipes-shared.rs @@ -22,7 +22,6 @@ extern mod extra; use std::comm::{Port, Chan, SharedChan}; use std::comm; -use std::io; use std::os; use std::task; use std::uint; @@ -90,10 +89,10 @@ fn run(args: &[~str]) { let result = from_child.recv(); let end = extra::time::precise_time_s(); let elapsed = end - start; - io::stdout().write_str(format!("Count is {:?}\n", result)); - io::stdout().write_str(format!("Test took {:?} seconds\n", elapsed)); + print!("Count is {:?}\n", result); + print!("Test took {:?} seconds\n", elapsed); let thruput = ((size / workers * workers) as f64) / (elapsed as f64); - io::stdout().write_str(format!("Throughput={} per sec\n", thruput)); + print!("Throughput={} per sec\n", thruput); assert_eq!(result, num_bytes * size); } diff --git a/src/test/bench/msgsend-pipes.rs b/src/test/bench/msgsend-pipes.rs index 584a8b8befcc6..1ff531324b358 100644 --- a/src/test/bench/msgsend-pipes.rs +++ b/src/test/bench/msgsend-pipes.rs @@ -17,7 +17,6 @@ extern mod extra; use std::comm::{SharedChan, Chan, stream}; -use std::io; use std::os; use std::task; use std::uint; @@ -84,10 +83,10 @@ fn run(args: &[~str]) { let result = from_child.recv(); let end = extra::time::precise_time_s(); let elapsed = end - start; - io::stdout().write_str(format!("Count is {:?}\n", result)); - io::stdout().write_str(format!("Test took {:?} seconds\n", elapsed)); + print!("Count is {:?}\n", result); + print!("Test took {:?} seconds\n", elapsed); let thruput = ((size / workers * workers) as f64) / (elapsed as f64); - io::stdout().write_str(format!("Throughput={} per sec\n", thruput)); + print!("Throughput={} per sec\n", thruput); assert_eq!(result, num_bytes * size); } diff --git a/src/test/bench/shootout-chameneos-redux.rs b/src/test/bench/shootout-chameneos-redux.rs index 96e87788b70d8..6bfb731badd5b 100644 --- a/src/test/bench/shootout-chameneos-redux.rs +++ b/src/test/bench/shootout-chameneos-redux.rs @@ -14,7 +14,6 @@ extern mod extra; use std::cell::Cell; use std::comm::{stream, SharedChan}; -use std::io; use std::option; use std::os; use std::task; @@ -191,15 +190,15 @@ fn rendezvous(nn: uint, set: ~[color]) { } // print each color in the set - io::println(show_color_list(set)); + println(show_color_list(set)); // print each creature's stats for rep in report.iter() { - io::println(*rep); + println(*rep); } // print the total number of creatures met - io::println(show_number(creatures_met)); + println(show_number(creatures_met)); } fn main() { @@ -215,10 +214,10 @@ fn main() { let nn = from_str::(args[1]).unwrap(); print_complements(); - io::println(""); + println(""); rendezvous(nn, ~[Blue, Red, Yellow]); - io::println(""); + println(""); rendezvous(nn, ~[Blue, Red, Yellow, Red, Yellow, Blue, Red, Yellow, Red, Blue]); diff --git a/src/test/bench/shootout-fasta.rs b/src/test/bench/shootout-fasta.rs index ef1061c780efd..3d1362b2f2931 100644 --- a/src/test/bench/shootout-fasta.rs +++ b/src/test/bench/shootout-fasta.rs @@ -18,7 +18,7 @@ extern mod extra; use std::int; -use std::io; +use std::rt::io; use std::os; use std::rand::Rng; use std::rand; @@ -68,12 +68,12 @@ fn select_random(r: u32, genelist: ~[AminoAcids]) -> char { bisect(genelist.clone(), 0, genelist.len() - 1, r) } -fn make_random_fasta(wr: @io::Writer, +fn make_random_fasta(wr: @mut io::Writer, id: ~str, desc: ~str, genelist: ~[AminoAcids], n: int) { - wr.write_line(~">" + id + " " + desc); + writeln!(wr, ">{} {}", id, desc); let mut rng = rand::rng(); let rng = @mut MyRandom { last: rng.gen() @@ -83,26 +83,26 @@ fn make_random_fasta(wr: @io::Writer, op.push_char(select_random(myrandom_next(rng, 100u32), genelist.clone())); if op.len() >= LINE_LENGTH { - wr.write_line(op); + writeln!(wr, "{}", op); op = ~""; } } - if op.len() > 0u { wr.write_line(op); } + if op.len() > 0u { writeln!(wr, "{}", op); } } -fn make_repeat_fasta(wr: @io::Writer, id: ~str, desc: ~str, s: ~str, n: int) { - wr.write_line(~">" + id + " " + desc); +fn make_repeat_fasta(wr: @mut io::Writer, id: ~str, desc: ~str, s: ~str, n: int) { + writeln!(wr, ">{} {}", id, desc); let mut op = str::with_capacity( LINE_LENGTH ); let sl = s.len(); for i in range(0u, n as uint) { if (op.len() >= LINE_LENGTH) { - wr.write_line( op ); + writeln!(wr, "{}", op); op = str::with_capacity( LINE_LENGTH ); } op.push_char( s[i % sl] as char ); } if op.len() > 0 { - wr.write_line(op) + writeln!(wr, "{}", op); } } @@ -122,10 +122,10 @@ fn main() { }; let writer = if os::getenv("RUST_BENCH").is_some() { - io::file_writer(&Path::new("./shootout-fasta.data"), - [io::Truncate, io::Create]).unwrap() + let file = "./shootout-fasta.data".open_writer(io::CreateOrTruncate); + @mut file as @mut io::Writer } else { - io::stdout() + @mut io::stdout() as @mut io::Writer }; let n = from_str::(args[1]).unwrap(); diff --git a/src/test/bench/shootout-k-nucleotide-pipes.rs b/src/test/bench/shootout-k-nucleotide-pipes.rs index 59dd0846b59aa..83a0fbd42ced2 100644 --- a/src/test/bench/shootout-k-nucleotide-pipes.rs +++ b/src/test/bench/shootout-k-nucleotide-pipes.rs @@ -18,8 +18,6 @@ use std::cmp::Ord; use std::comm::{stream, Port, Chan}; use std::comm; use std::hashmap::HashMap; -use std::io::ReaderUtil; -use std::io; use std::option; use std::os; use std::str; @@ -237,6 +235,6 @@ fn main() { // now fetch and print result messages for (ii, _sz) in sizes.iter().enumerate() { - io::println(from_child[ii].recv()); + println(from_child[ii].recv()); } } diff --git a/src/test/bench/shootout-pfib.rs b/src/test/bench/shootout-pfib.rs index 88b3cfdff4298..b3c3fa4db6fb6 100644 --- a/src/test/bench/shootout-pfib.rs +++ b/src/test/bench/shootout-pfib.rs @@ -23,8 +23,6 @@ extern mod extra; use extra::{time, getopts}; use std::comm::{stream, SharedChan}; -use std::io::WriterUtil; -use std::io; use std::os; use std::result::{Ok, Err}; use std::task; @@ -113,8 +111,6 @@ fn main() { let num_trials = 10; - let out = io::stdout(); - for n in range(1, max + 1) { for _ in range(0, num_trials) { let start = time::precise_time_ns(); @@ -123,8 +119,7 @@ fn main() { let elapsed = stop - start; - out.write_line(format!("{}\t{}\t{}", n, fibn, - elapsed.to_str())); + println!("{}\t{}\t{}", n, fibn, elapsed.to_str()); } } } diff --git a/src/test/bench/std-smallintmap.rs b/src/test/bench/std-smallintmap.rs index be2bd051cad86..e1b1f59298ed4 100644 --- a/src/test/bench/std-smallintmap.rs +++ b/src/test/bench/std-smallintmap.rs @@ -13,8 +13,6 @@ extern mod extra; use extra::smallintmap::SmallIntMap; -use std::io::WriterUtil; -use std::io; use std::os; use std::uint; @@ -59,8 +57,8 @@ fn main() { let maxf = max as f64; - io::stdout().write_str(format!("insert(): {:?} seconds\n", checkf)); - io::stdout().write_str(format!(" : {} op/sec\n", maxf/checkf)); - io::stdout().write_str(format!("get() : {:?} seconds\n", appendf)); - io::stdout().write_str(format!(" : {} op/sec\n", maxf/appendf)); + println!("insert(): {:?} seconds\n", checkf); + println!(" : {} op/sec\n", maxf/checkf); + println!("get() : {:?} seconds\n", appendf); + println!(" : {} op/sec\n", maxf/appendf); } diff --git a/src/test/bench/sudoku.rs b/src/test/bench/sudoku.rs index 189b3ef740e9c..21d492d85fc33 100644 --- a/src/test/bench/sudoku.rs +++ b/src/test/bench/sudoku.rs @@ -14,8 +14,7 @@ extern mod extra; -use std::io::{ReaderUtil, WriterUtil}; -use std::io; +use std::rt::io; use std::os; use std::uint; use std::unstable::intrinsics::cttz16; @@ -67,7 +66,7 @@ impl Sudoku { return true; } - pub fn read(reader: @io::Reader) -> Sudoku { + pub fn read(reader: @mut io::Reader) -> Sudoku { assert!(reader.read_line() == ~"9,9"); /* assert first line is exactly "9,9" */ let mut g = vec::from_fn(10u, { |_i| ~[0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8] }); @@ -87,7 +86,7 @@ impl Sudoku { return Sudoku::new(g) } - pub fn write(&self, writer: @io::Writer) { + pub fn write(&self, writer: @mut io::Writer) { for row in range(0u8, 9u8) { writer.write_str(format!("{}", self.grid[row][0] as uint)); for col in range(1u8, 9u8) { @@ -278,8 +277,8 @@ fn main() { let mut sudoku = if use_default { Sudoku::from_vec(&DEFAULT_SUDOKU) } else { - Sudoku::read(io::stdin()) + Sudoku::read(@mut io::stdin() as @mut io::Reader) }; sudoku.solve(); - sudoku.write(io::stdout()); + sudoku.write(@mut io::stdout() as @mut io::Writer); } diff --git a/src/test/compile-fail/issue-5060-fail.rs b/src/test/compile-fail/issue-5060-fail.rs index c50398544440a..ef5ad2766ca69 100644 --- a/src/test/compile-fail/issue-5060-fail.rs +++ b/src/test/compile-fail/issue-5060-fail.rs @@ -10,17 +10,15 @@ #[feature(macro_rules)]; -use std::io; - macro_rules! print_hd_tl ( ($field_hd:ident, $($field_tl:ident),+) => ({ - io::print(stringify!($field)); //~ ERROR unknown macro variable - io::print("::["); + print(stringify!($field)); //~ ERROR unknown macro variable + print("::["); $( - io::print(stringify!($field_tl)); - io::print(", "); + print(stringify!($field_tl)); + print(", "); )+ - io::print("]\n"); + print("]\n"); }) ) diff --git a/src/test/compile-fail/issue-5883.rs b/src/test/compile-fail/issue-5883.rs index a8b9000c6d9c9..621510cea99e4 100644 --- a/src/test/compile-fail/issue-5883.rs +++ b/src/test/compile-fail/issue-5883.rs @@ -8,13 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::io; +trait A {} struct Struct { - r: io::Reader //~ ERROR reference to trait `io::Reader` where a type is expected + r: A //~ ERROR reference to trait `A` where a type is expected } -fn new_struct(r: io::Reader) -> Struct { //~ ERROR reference to trait `io::Reader` where a type is expected +fn new_struct(r: A) -> Struct { //~ ERROR reference to trait `A` where a type is expected Struct { r: r } } diff --git a/src/test/compile-fail/issue-7573.rs b/src/test/compile-fail/issue-7573.rs index 2be763ee76850..9dc29e59f904a 100644 --- a/src/test/compile-fail/issue-7573.rs +++ b/src/test/compile-fail/issue-7573.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::io; - pub struct PkgId { local_path: ~str, junk: ~str @@ -32,7 +30,7 @@ pub fn remove_package_from_database() { list_database(push_id); for l in lines_to_use.iter() { - io::stdout().write_line(l.local_path); + println!("{}", l.local_path); } } diff --git a/src/test/compile-fail/lint-unused-imports.rs b/src/test/compile-fail/lint-unused-imports.rs index 22cf54428a73a..2818214c994b1 100644 --- a/src/test/compile-fail/lint-unused-imports.rs +++ b/src/test/compile-fail/lint-unused-imports.rs @@ -13,8 +13,6 @@ use cal = bar::c::cc; -use std::io; - use std::either::Right; //~ ERROR unused import use std::util::*; // shouldn't get errors for not using @@ -24,15 +22,23 @@ use std::util::*; // shouldn't get errors for not using use std::option::{Some, None}; //~ ERROR unused import //~^ ERROR unused import -use std::io::ReaderUtil; //~ ERROR unused import +use test::A; //~ ERROR unused import // Be sure that if we just bring some methods into scope that they're also // counted as being used. -use std::io::WriterUtil; +use test::B; // Make sure this import is warned about when at least one of its imported names // is unused use std::vec::{from_fn, from_elem}; //~ ERROR unused import +mod test { + pub trait A { fn a(&self) {} } + pub trait B { fn b(&self) {} } + pub struct C; + impl A for C {} + impl B for C {} +} + mod foo { pub struct Point{x: int, y: int} pub struct Square{p: Point, h: uint, w: uint} @@ -58,6 +64,6 @@ fn main() { cal(foo::Point{x:3, y:9}); let a = 3; ignore(a); - io::stdout().write_str("a"); + test::C.b(); let _a = from_elem(0, 0); } diff --git a/src/test/run-fail/issue-2156.rs b/src/test/run-fail/issue-2156.rs deleted file mode 100644 index 863663334f8ed..0000000000000 --- a/src/test/run-fail/issue-2156.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[allow(unnecessary_allocation)]; - -// error-pattern:explicit failure -// Don't double free the string -extern mod extra; - -use std::io::ReaderUtil; -use std::io; - -fn main() { - do io::with_str_reader(~"") |rdr| { - match rdr.read_char() { '=' => { } _ => { fail!() } } - } -} diff --git a/src/test/run-pass/auto-ref-bounded-ty-param.rs b/src/test/run-pass/auto-ref-bounded-ty-param.rs index bb01c27fa0d5c..5211e76d3d7d2 100644 --- a/src/test/run-pass/auto-ref-bounded-ty-param.rs +++ b/src/test/run-pass/auto-ref-bounded-ty-param.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::io; - trait Foo { fn f(&self); } @@ -30,7 +28,7 @@ impl Foo for T { impl Baz for Bar { fn g(&self) { - io::println(self.x.to_str()); + println(self.x.to_str()); } } diff --git a/src/test/run-pass/expr-repeat-vstore.rs b/src/test/run-pass/expr-repeat-vstore.rs index 8a498563359fb..2831740deaf47 100644 --- a/src/test/run-pass/expr-repeat-vstore.rs +++ b/src/test/run-pass/expr-repeat-vstore.rs @@ -1,7 +1,5 @@ #[feature(managed_boxes)]; -use std::io::println; - pub fn main() { let v: ~[int] = ~[ 1, ..5 ]; println(v[0].to_str()); diff --git a/src/test/run-pass/issue-2904.rs b/src/test/run-pass/issue-2904.rs index 0ef9e7108ae65..5a3b177aadcd2 100644 --- a/src/test/run-pass/issue-2904.rs +++ b/src/test/run-pass/issue-2904.rs @@ -16,8 +16,7 @@ extern mod extra; -use std::io::ReaderUtil; -use std::io; +use std::rt::io; use std::to_str; enum square { @@ -64,16 +63,15 @@ fn square_from_char(c: char) -> square { } fn read_board_grid(input: rdr) -> ~[~[square]] { - let input = @input as @io::Reader; + let input = @mut input as @mut io::Reader; let mut grid = ~[]; - do input.each_line |line| { - let mut row = ~[]; - for c in line.iter() { - row.push(square_from_char(c)) - } - grid.push(row); - true - }; + let mut line = [0, ..10]; + input.read(line); + let mut row = ~[]; + for c in line.iter() { + row.push(square_from_char(*c as char)) + } + grid.push(row); let width = grid[0].len(); for row in grid.iter() { assert!(row.len() == width) } grid diff --git a/src/test/run-pass/issue-3556.rs b/src/test/run-pass/issue-3556.rs index 2d4e128f62325..e092d45ce68c8 100644 --- a/src/test/run-pass/issue-3556.rs +++ b/src/test/run-pass/issue-3556.rs @@ -12,9 +12,6 @@ extern mod extra; -use std::io::WriterUtil; -use std::io; - enum Token { Text(@~str), ETag(@~[~str], @~str), @@ -28,8 +25,7 @@ fn check_strs(actual: &str, expected: &str) -> bool { if actual != expected { - io::stderr().write_line(format!("Found {}, but expected {}", actual, - expected)); + println!("Found {}, but expected {}", actual, expected); return false; } return true; diff --git a/src/test/run-pass/issue-3559.rs b/src/test/run-pass/issue-3559.rs index 9665da11b9334..ba92434ba69af 100644 --- a/src/test/run-pass/issue-3559.rs +++ b/src/test/run-pass/issue-3559.rs @@ -13,13 +13,11 @@ // rustc --test map_to_str.rs && ./map_to_str extern mod extra; -use std::io::{WriterUtil}; - fn check_strs(actual: &str, expected: &str) -> bool { if actual != expected { - io::stderr().write_line(fmt!("Found %s, but expected %s", actual, expected)); + println!("Found %s, but expected %s", actual, expected); return false; } return true; diff --git a/src/test/run-pass/issue-3563-3.rs b/src/test/run-pass/issue-3563-3.rs index 55273f7029b6f..50d6a3ae6b8db 100644 --- a/src/test/run-pass/issue-3563-3.rs +++ b/src/test/run-pass/issue-3563-3.rs @@ -20,8 +20,6 @@ extern mod extra; // Extern mod controls linkage. Use controls the visibility of names to modules that are // already linked in. Using WriterUtil allows us to use the write_line method. -use std::io::WriterUtil; -use std::io; use std::str; use std::vec; @@ -150,7 +148,7 @@ impl Canvas for AsciiArt { // this little helper. pub fn check_strs(actual: &str, expected: &str) -> bool { if actual != expected { - io::stderr().write_line(format!("Found:\n{}\nbut expected\n{}", actual, expected)); + println!("Found:\n{}\nbut expected\n{}", actual, expected); return false; } return true; diff --git a/src/test/run-pass/issue-4333.rs b/src/test/run-pass/issue-4333.rs index ebf29be6d5e45..86cef39abc81f 100644 --- a/src/test/run-pass/issue-4333.rs +++ b/src/test/run-pass/issue-4333.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::io; +use std::rt::io; pub fn main() { - let stdout = &io::stdout() as &io::WriterUtil; - stdout.write_line("Hello!"); + let stdout = &mut io::stdout() as &mut io::Writer; + stdout.write(bytes!("Hello!")); } diff --git a/src/test/run-pass/issue-4541.rs b/src/test/run-pass/issue-4541.rs index 7b80974313e37..32e13f5ac7f46 100644 --- a/src/test/run-pass/issue-4541.rs +++ b/src/test/run-pass/issue-4541.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::io; - fn parse_args() -> ~str { let args = ::std::os::args(); let mut n = 0; @@ -28,5 +26,5 @@ fn parse_args() -> ~str { } pub fn main() { - io::println(parse_args()); + println(parse_args()); } diff --git a/src/test/run-pass/issue-5060.rs b/src/test/run-pass/issue-5060.rs index e7d0cc012402a..7b96d5a48b9fd 100644 --- a/src/test/run-pass/issue-5060.rs +++ b/src/test/run-pass/issue-5060.rs @@ -10,17 +10,15 @@ #[feature(macro_rules)]; -use std::io; - macro_rules! print_hd_tl ( ($field_hd:ident, $($field_tl:ident),+) => ({ - io::print(stringify!($field_hd)); - io::print("::["); + print(stringify!($field_hd)); + print("::["); $( - io::print(stringify!($field_tl)); - io::print(", "); + print(stringify!($field_tl)); + print(", "); )+ - io::print("]\n"); + print("]\n"); }) ) diff --git a/src/test/run-pass/issue-5741.rs b/src/test/run-pass/issue-5741.rs index 46ec68675e7f3..4282e7acf19b1 100644 --- a/src/test/run-pass/issue-5741.rs +++ b/src/test/run-pass/issue-5741.rs @@ -10,9 +10,7 @@ #[allow(unreachable_code)]; -use std::io; - pub fn main() { return; - while io::stdin().read_line() != ~"quit" { }; + while true {}; } diff --git a/src/test/run-pass/issue-8498.rs b/src/test/run-pass/issue-8498.rs index 40f98355f34e1..247b74e464312 100644 --- a/src/test/run-pass/issue-8498.rs +++ b/src/test/run-pass/issue-8498.rs @@ -9,14 +9,13 @@ // except according to those terms. // xfail-test -use std::io; fn main() { // This is ok match &[(~5,~7)] { ps => { let (ref y, _) = ps[0]; - io::println(fmt!("1. y = %d", **y)); + println(fmt!("1. y = %d", **y)); assert!(**y == 5); } } @@ -25,8 +24,8 @@ fn main() { match Some(&[(~5,)]) { Some(ps) => { let (ref y,) = ps[0]; - io::println(fmt!("2. y = %d", **y)); - if **y != 5 { io::println("sadness"); } + println(fmt!("2. y = %d", **y)); + if **y != 5 { println("sadness"); } } None => () } @@ -35,7 +34,7 @@ fn main() { match Some(&[(~5,~7)]) { Some(ps) => { let (ref y, ref z) = ps[0]; - io::println(fmt!("3. y = %d z = %d", **y, **z)); + println(fmt!("3. y = %d z = %d", **y, **z)); assert!(**y == 5); } None => () diff --git a/src/test/run-pass/match-drop-strs-issue-4541.rs b/src/test/run-pass/match-drop-strs-issue-4541.rs index e90d6b2862671..0580bc938d7d4 100644 --- a/src/test/run-pass/match-drop-strs-issue-4541.rs +++ b/src/test/run-pass/match-drop-strs-issue-4541.rs @@ -2,7 +2,6 @@ // copying, and moving to ensure that we don't segfault // or double-free, as we were wont to do in the past. -use std::io; use std::os; fn parse_args() -> ~str { @@ -23,5 +22,5 @@ fn parse_args() -> ~str { } pub fn main() { - io::println(parse_args()); + println(parse_args()); } diff --git a/src/test/run-pass/monomorphized-callees-with-ty-params-3314.rs b/src/test/run-pass/monomorphized-callees-with-ty-params-3314.rs index 0259c3955d82c..5e03b47d1b1dc 100644 --- a/src/test/run-pass/monomorphized-callees-with-ty-params-3314.rs +++ b/src/test/run-pass/monomorphized-callees-with-ty-params-3314.rs @@ -12,8 +12,6 @@ extern mod extra; -use std::io; - trait Serializer { } @@ -33,15 +31,13 @@ impl Serializable for F { } } -impl Serializer for @io::Writer { +impl Serializer for int { } pub fn main() { - do io::with_str_writer |wr| { - let foo = F { a: 1 }; - foo.serialize(wr); + let foo = F { a: 1 }; + foo.serialize(1i); - let bar = F { a: F {a: 1 } }; - bar.serialize(wr); - }; + let bar = F { a: F {a: 1 } }; + bar.serialize(2i); } diff --git a/src/test/run-pass/new-import-syntax.rs b/src/test/run-pass/new-import-syntax.rs index c7497bf3de525..ef59606afe347 100644 --- a/src/test/run-pass/new-import-syntax.rs +++ b/src/test/run-pass/new-import-syntax.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::io::println; - pub fn main() { println("Hello world!"); } diff --git a/src/test/run-pass/new-style-constants.rs b/src/test/run-pass/new-style-constants.rs index e2402080bc3c8..fa681c81398fe 100644 --- a/src/test/run-pass/new-style-constants.rs +++ b/src/test/run-pass/new-style-constants.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::io::println; - static FOO: int = 3; pub fn main() { diff --git a/src/test/run-pass/stat.rs b/src/test/run-pass/stat.rs index 7501c46079d98..85cf265c2d0e8 100644 --- a/src/test/run-pass/stat.rs +++ b/src/test/run-pass/stat.rs @@ -13,8 +13,9 @@ extern mod extra; use extra::tempfile; -use std::io::WriterUtil; -use std::io; +use std::rt::io; +use std::rt::io::Writer; +use std::rt::io::file::FileInfo; use std::os; pub fn main() { @@ -22,11 +23,12 @@ pub fn main() { let path = dir.path().join("file"); { - match io::file_writer(&path, [io::Create, io::Truncate]) { - Err(ref e) => fail!("{}", e.clone()), - Ok(f) => { + match path.open_writer(io::CreateOrTruncate) { + None => unreachable!(), + Some(f) => { + let mut f = f; for _ in range(0u, 1000) { - f.write_u8(0); + f.write([0]); } } } diff --git a/src/test/run-pass/trait-static-method-overwriting.rs b/src/test/run-pass/trait-static-method-overwriting.rs index 5ac26e65d8880..c8f2afe8c6171 100644 --- a/src/test/run-pass/trait-static-method-overwriting.rs +++ b/src/test/run-pass/trait-static-method-overwriting.rs @@ -11,8 +11,6 @@ // except according to those terms. mod base { - use std::io; - pub trait HasNew { fn new() -> Self; } @@ -34,7 +32,7 @@ mod base { impl ::base::HasNew for Bar { fn new() -> Bar { - io::println("Bar"); + println("Bar"); Bar { dummy: () } } } From e117aa0e2a4121aab101cb7526a5e79812bfb76e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 17 Oct 2013 18:51:32 -0700 Subject: [PATCH 13/23] Stop logging task failure to task loggers The isn't an ideal patch, and the comment why is in the code. Basically uvio uses task::unkillable which touches the kill flag for a task, and if the task is failing due to mismangement of the kill flag, then there will be serious problems when the task tries to print that it's failing. --- src/libstd/rt/task.rs | 18 ++++++++++-------- src/libstd/rt/util.rs | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index 16ae28743c523..b3c65ce4749de 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -546,7 +546,6 @@ pub fn begin_unwind(msg: *c_char, file: *c_char, line: size_t) -> ! { use rt::in_green_task_context; use rt::task::Task; use rt::local::Local; - use rt::logging::Logger; use str::Str; use c_str::CString; use unstable::intrinsics; @@ -573,16 +572,19 @@ pub fn begin_unwind(msg: *c_char, file: *c_char, line: size_t) -> ! { // have been failing due to a lack of memory in the first place... let task: *mut Task = Local::unsafe_borrow(); let n = (*task).name.as_ref().map(|n| n.as_slice()).unwrap_or(""); + + // XXX: this should no get forcibly printed to the console, this should + // either be sent to the parent task (ideally), or get printed to + // the task's logger. Right now the logger is actually a uvio + // instance, which uses unkillable blocks internally for various + // reasons. This will cause serious trouble if the task is failing + // due to mismanagment of its own kill flag, so calling our own + // logger in its current state is a bit of a problem. match file.as_str() { Some(file) => { - format_args!(|args| { (*task).logger.log(args) }, - "task '{}' failed at '{}', {}:{}", - n, msg, file, line); - } - None => { - format_args!(|args| { (*task).logger.log(args) }, - "task '{}' failed at '{}'", n, msg); + rterrln!("task '{}' failed at '{}', {}:{}", n, msg, file, line); } + None => rterrln!("task '{}' failed at '{}'", n, msg), } if (*task).unwinder.unwinding { rtabort!("unwinding again"); diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs index f15aa01db954d..e859f8e4fdb35 100644 --- a/src/libstd/rt/util.rs +++ b/src/libstd/rt/util.rs @@ -72,8 +72,8 @@ pub fn default_sched_threads() -> uint { pub fn dumb_println(args: &fmt::Arguments) { use rt::io::native::stdio::stderr; use rt::io::{Writer, io_error, ResourceUnavailable}; - let mut out = stderr(); + let mut out = stderr(); let mut again = true; do io_error::cond.trap(|e| { again = e.kind == ResourceUnavailable; From 6b70ddfba1ed5fca7fa67e5f2d2691e9c667d3a3 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 18 Oct 2013 11:52:23 -0700 Subject: [PATCH 14/23] Remove io::read_error The general idea is to remove conditions completely from I/O, so in the meantime remove the read_error condition to mean the same thing as the io_error condition. --- src/libstd/rt/io/extensions.rs | 38 ++++++++++++++++---------------- src/libstd/rt/io/file.rs | 12 +++++----- src/libstd/rt/io/mod.rs | 8 +------ src/libstd/rt/io/net/tcp.rs | 8 +++---- src/libstd/rt/io/net/udp.rs | 4 ++-- src/libstd/rt/io/option.rs | 8 +++---- src/libstd/rt/io/pipe.rs | 4 ++-- src/libsyntax/ext/source_util.rs | 8 +++---- src/libsyntax/parse/mod.rs | 4 +--- 9 files changed, 42 insertions(+), 52 deletions(-) diff --git a/src/libstd/rt/io/extensions.rs b/src/libstd/rt/io/extensions.rs index 99634b532b082..c77e3b9160990 100644 --- a/src/libstd/rt/io/extensions.rs +++ b/src/libstd/rt/io/extensions.rs @@ -18,7 +18,7 @@ use int; use iter::Iterator; use vec; use rt::io::{Reader, Writer, Decorator}; -use rt::io::{read_error, standard_error, EndOfFile, DEFAULT_BUF_SIZE}; +use rt::io::{io_error, standard_error, EndOfFile, DEFAULT_BUF_SIZE}; use option::{Option, Some, None}; use unstable::finally::Finally; use cast; @@ -41,8 +41,8 @@ pub trait ReaderUtil { /// /// # Failure /// - /// Raises the same conditions as `read`. Additionally raises `read_error` - /// on EOF. If `read_error` is handled then `push_bytes` may push less + /// Raises the same conditions as `read`. Additionally raises `io_error` + /// on EOF. If `io_error` is handled then `push_bytes` may push less /// than the requested number of bytes. fn push_bytes(&mut self, buf: &mut ~[u8], len: uint); @@ -50,8 +50,8 @@ pub trait ReaderUtil { /// /// # Failure /// - /// Raises the same conditions as `read`. Additionally raises `read_error` - /// on EOF. If `read_error` is handled then the returned vector may + /// Raises the same conditions as `read`. Additionally raises `io_error` + /// on EOF. If `io_error` is handled then the returned vector may /// contain less than the requested number of bytes. fn read_bytes(&mut self, len: uint) -> ~[u8]; @@ -314,7 +314,7 @@ impl ReaderUtil for T { total_read += nread; } None => { - read_error::cond.raise(standard_error(EndOfFile)); + io_error::cond.raise(standard_error(EndOfFile)); break; } } @@ -334,11 +334,11 @@ impl ReaderUtil for T { fn read_to_end(&mut self) -> ~[u8] { let mut buf = vec::with_capacity(DEFAULT_BUF_SIZE); let mut keep_reading = true; - do read_error::cond.trap(|e| { + do io_error::cond.trap(|e| { if e.kind == EndOfFile { keep_reading = false; } else { - read_error::cond.raise(e) + io_error::cond.raise(e) } }).inside { while keep_reading { @@ -641,7 +641,7 @@ mod test { use cell::Cell; use rt::io::mem::{MemReader, MemWriter}; use rt::io::mock::MockReader; - use rt::io::{read_error, placeholder_error}; + use rt::io::{io_error, placeholder_error}; #[test] fn read_byte() { @@ -681,10 +681,10 @@ mod test { fn read_byte_error() { let mut reader = MockReader::new(); reader.read = |_| { - read_error::cond.raise(placeholder_error()); + io_error::cond.raise(placeholder_error()); None }; - do read_error::cond.trap(|_| { + do io_error::cond.trap(|_| { }).inside { let byte = reader.read_byte(); assert!(byte == None); @@ -722,11 +722,11 @@ mod test { fn bytes_error() { let mut reader = MockReader::new(); reader.read = |_| { - read_error::cond.raise(placeholder_error()); + io_error::cond.raise(placeholder_error()); None }; let mut it = reader.bytes(); - do read_error::cond.trap(|_| ()).inside { + do io_error::cond.trap(|_| ()).inside { let byte = it.next(); assert!(byte == None); } @@ -765,7 +765,7 @@ mod test { #[test] fn read_bytes_eof() { let mut reader = MemReader::new(~[10, 11]); - do read_error::cond.trap(|_| { + do io_error::cond.trap(|_| { }).inside { assert!(reader.read_bytes(4) == ~[10, 11]); } @@ -806,7 +806,7 @@ mod test { fn push_bytes_eof() { let mut reader = MemReader::new(~[10, 11]); let mut buf = ~[8, 9]; - do read_error::cond.trap(|_| { + do io_error::cond.trap(|_| { }).inside { reader.push_bytes(&mut buf, 4); assert!(buf == ~[8, 9, 10, 11]); @@ -824,13 +824,13 @@ mod test { buf[0] = 10; Some(1) } else { - read_error::cond.raise(placeholder_error()); + io_error::cond.raise(placeholder_error()); None } } }; let mut buf = ~[8, 9]; - do read_error::cond.trap(|_| { } ).inside { + do io_error::cond.trap(|_| { } ).inside { reader.push_bytes(&mut buf, 4); } assert!(buf == ~[8, 9, 10]); @@ -850,7 +850,7 @@ mod test { buf[0] = 10; Some(1) } else { - read_error::cond.raise(placeholder_error()); + io_error::cond.raise(placeholder_error()); None } } @@ -903,7 +903,7 @@ mod test { buf[1] = 11; Some(2) } else { - read_error::cond.raise(placeholder_error()); + io_error::cond.raise(placeholder_error()); None } } diff --git a/src/libstd/rt/io/file.rs b/src/libstd/rt/io/file.rs index 0bd0213b5b06e..381fa9f2d073a 100644 --- a/src/libstd/rt/io/file.rs +++ b/src/libstd/rt/io/file.rs @@ -19,7 +19,7 @@ on a `ToCStr` object. This trait is already defined for common objects such as strings and `Path` instances. All operations in this module, including those as part of `FileStream` et al -block the task during execution. Most will raise `std::rt::io::{io_error,read_error}` +block the task during execution. Most will raise `std::rt::io::{io_error,io_error}` conditions in the event of failure. Also included in this module are the `FileInfo` and `DirectoryInfo` traits. When @@ -35,7 +35,7 @@ use c_str::ToCStr; use super::{Reader, Writer, Seek}; use super::{SeekStyle, Read, Write}; use rt::rtio::{RtioFileStream, IoFactory, with_local_io}; -use rt::io::{io_error, read_error, EndOfFile, +use rt::io::{io_error, EndOfFile, FileMode, FileAccess, FileStat, IoError, PathAlreadyExists, PathDoesntExist, MismatchedFileTypeForOperation, ignore_io_error}; @@ -361,7 +361,7 @@ impl Reader for FileStream { Err(ioerr) => { // EOF is indicated by returning None if ioerr.kind != EndOfFile { - read_error::cond.raise(ioerr); + io_error::cond.raise(ioerr); } return None; } @@ -388,7 +388,7 @@ impl Writer for FileStream { match self.fd.flush() { Ok(_) => (), Err(ioerr) => { - read_error::cond.raise(ioerr); + io_error::cond.raise(ioerr); } } } @@ -401,7 +401,7 @@ impl Seek for FileStream { match res { Ok(cursor) => cursor, Err(ioerr) => { - read_error::cond.raise(ioerr); + io_error::cond.raise(ioerr); return -1; } } @@ -415,7 +415,7 @@ impl Seek for FileStream { () }, Err(ioerr) => { - read_error::cond.raise(ioerr); + io_error::cond.raise(ioerr); } } } diff --git a/src/libstd/rt/io/mod.rs b/src/libstd/rt/io/mod.rs index 240210880bfab..7f5b01bb1ece9 100644 --- a/src/libstd/rt/io/mod.rs +++ b/src/libstd/rt/io/mod.rs @@ -404,12 +404,6 @@ condition! { pub io_error: IoError -> (); } -// XXX: Can't put doc comments on macros -// Raised by `read` on error -condition! { - pub read_error: IoError -> (); -} - /// Helper for wrapper calls where you want to /// ignore any io_errors that might be raised pub fn ignore_io_error(cb: &fn() -> T) -> T { @@ -429,7 +423,7 @@ pub trait Reader { /// /// # Failure /// - /// Raises the `read_error` condition on error. If the condition + /// Raises the `io_error` condition on error. If the condition /// is handled then no guarantee is made about the number of bytes /// read and the contents of `buf`. If the condition is handled /// returns `None` (XXX see below). diff --git a/src/libstd/rt/io/net/tcp.rs b/src/libstd/rt/io/net/tcp.rs index 21f98c272968f..4e841b36a5d37 100644 --- a/src/libstd/rt/io/net/tcp.rs +++ b/src/libstd/rt/io/net/tcp.rs @@ -12,7 +12,7 @@ use option::{Option, Some, None}; use result::{Ok, Err}; use rt::io::net::ip::SocketAddr; use rt::io::{Reader, Writer, Listener, Acceptor}; -use rt::io::{io_error, read_error, EndOfFile}; +use rt::io::{io_error, EndOfFile}; use rt::rtio::{IoFactory, with_local_io, RtioSocket, RtioTcpListener, RtioTcpAcceptor, RtioTcpStream}; @@ -67,7 +67,7 @@ impl Reader for TcpStream { Err(ioerr) => { // EOF is indicated by returning None if ioerr.kind != EndOfFile { - read_error::cond.raise(ioerr); + io_error::cond.raise(ioerr); } return None; } @@ -308,7 +308,7 @@ mod test { let mut buf = [0]; let nread = stream.read(buf); assert!(nread.is_none()); - do read_error::cond.trap(|e| { + do io_error::cond.trap(|e| { if cfg!(windows) { assert_eq!(e.kind, NotConnected); } else { @@ -343,7 +343,7 @@ mod test { let mut buf = [0]; let nread = stream.read(buf); assert!(nread.is_none()); - do read_error::cond.trap(|e| { + do io_error::cond.trap(|e| { if cfg!(windows) { assert_eq!(e.kind, NotConnected); } else { diff --git a/src/libstd/rt/io/net/udp.rs b/src/libstd/rt/io/net/udp.rs index eee5dce7b6c68..2e4ae95d98eea 100644 --- a/src/libstd/rt/io/net/udp.rs +++ b/src/libstd/rt/io/net/udp.rs @@ -12,7 +12,7 @@ use option::{Option, Some, None}; use result::{Ok, Err}; use rt::io::net::ip::SocketAddr; use rt::io::{Reader, Writer}; -use rt::io::{io_error, read_error, EndOfFile}; +use rt::io::{io_error, EndOfFile}; use rt::rtio::{RtioSocket, RtioUdpSocket, IoFactory, with_local_io}; pub struct UdpSocket { @@ -38,7 +38,7 @@ impl UdpSocket { Err(ioerr) => { // EOF is indicated by returning None if ioerr.kind != EndOfFile { - read_error::cond.raise(ioerr); + io_error::cond.raise(ioerr); } None } diff --git a/src/libstd/rt/io/option.rs b/src/libstd/rt/io/option.rs index ecfc4a832bfb5..52699964b6241 100644 --- a/src/libstd/rt/io/option.rs +++ b/src/libstd/rt/io/option.rs @@ -16,7 +16,7 @@ use option::*; use super::{Reader, Writer, Listener, Acceptor, Seek, SeekStyle}; -use super::{standard_error, PreviousIoError, io_error, read_error, IoError}; +use super::{standard_error, PreviousIoError, io_error, IoError}; fn prev_io_error() -> IoError { standard_error(PreviousIoError) @@ -43,7 +43,7 @@ impl Reader for Option { match *self { Some(ref mut reader) => reader.read(buf), None => { - read_error::cond.raise(prev_io_error()); + io_error::cond.raise(prev_io_error()); None } } @@ -107,7 +107,7 @@ mod test { use option::*; use super::super::mem::*; use rt::test::*; - use super::super::{PreviousIoError, io_error, read_error}; + use super::super::{PreviousIoError, io_error, io_error}; #[test] fn test_option_writer() { @@ -161,7 +161,7 @@ mod test { let mut buf = []; let mut called = false; - do read_error::cond.trap(|err| { + do io_error::cond.trap(|err| { assert_eq!(err.kind, PreviousIoError); called = true; }).inside { diff --git a/src/libstd/rt/io/pipe.rs b/src/libstd/rt/io/pipe.rs index c15fbc79da9f6..eba58b97c4df4 100644 --- a/src/libstd/rt/io/pipe.rs +++ b/src/libstd/rt/io/pipe.rs @@ -15,7 +15,7 @@ use prelude::*; use super::{Reader, Writer}; -use rt::io::{io_error, read_error, EndOfFile}; +use rt::io::{io_error, EndOfFile}; use rt::rtio::RtioPipe; pub struct PipeStream { @@ -35,7 +35,7 @@ impl Reader for PipeStream { Err(ioerr) => { // EOF is indicated by returning None if ioerr.kind != EndOfFile { - read_error::cond.raise(ioerr); + io_error::cond.raise(ioerr); } return None; } diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index df177cf75dc72..047fc541ba8b3 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -93,7 +93,7 @@ pub fn expand_include_str(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree]) let file = get_single_str_from_tts(cx, sp, tts, "include_str!"); let file = res_rel_file(cx, sp, &Path::new(file)); let mut error = None; - let bytes = do io::read_error::cond.trap(|e| error = Some(e)).inside { + let bytes = do io::io_error::cond.trap(|e| error = Some(e)).inside { file.open_reader(io::Open).read_to_end() }; match error { @@ -120,10 +120,8 @@ pub fn expand_include_bin(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree]) let file = res_rel_file(cx, sp, &Path::new(file)); let mut error = None; - let bytes = do io::read_error::cond.trap(|e| error = Some(e)).inside { - do io::io_error::cond.trap(|e| error = Some(e)).inside { - file.open_reader(io::Open).read_to_end() - } + let bytes = do io::io_error::cond.trap(|e| error = Some(e)).inside { + file.open_reader(io::Open).read_to_end() }; match error { Some(e) => { diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 93e5d3dd7727f..fad9eab754200 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -271,9 +271,7 @@ pub fn file_to_filemap(sess: @mut ParseSess, path: &Path, spanopt: Option) }; let mut error = None; let bytes = do io::io_error::cond.trap(|e| error = Some(e)).inside { - do io::read_error::cond.trap(|e| error = Some(e)).inside { - path.open_reader(io::Open).read_to_end() - } + path.open_reader(io::Open).read_to_end() }; match error { Some(e) => { From 279c35182050889cba42e4adb1438a7f640fdabd Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 18 Oct 2013 14:01:22 -0700 Subject: [PATCH 15/23] Move stdin to using libuv's pipes instead of a tty I was seeing a lot of weird behavior with stdin behaving as a tty, and it doesn't really quite make sense, so instead this moves to using libuv's pipes instead (which make more sense for stdin specifically). This prevents piping input to rustc hanging forever. --- src/libstd/rt/io/file.rs | 2 +- src/libstd/rt/io/net/unix.rs | 2 +- src/libstd/rt/io/pipe.rs | 6 +-- src/libstd/rt/io/process.rs | 2 +- src/libstd/rt/io/stdio.rs | 36 ++++++---------- src/libstd/rt/rtio.rs | 1 + src/libstd/rt/uv/net.rs | 2 +- src/libstd/rt/uv/process.rs | 2 +- src/libstd/rt/uv/uvio.rs | 79 ++++++++++++------------------------ 9 files changed, 48 insertions(+), 84 deletions(-) diff --git a/src/libstd/rt/io/file.rs b/src/libstd/rt/io/file.rs index 381fa9f2d073a..d035e2f457cc2 100644 --- a/src/libstd/rt/io/file.rs +++ b/src/libstd/rt/io/file.rs @@ -19,7 +19,7 @@ on a `ToCStr` object. This trait is already defined for common objects such as strings and `Path` instances. All operations in this module, including those as part of `FileStream` et al -block the task during execution. Most will raise `std::rt::io::{io_error,io_error}` +block the task during execution. Most will raise `std::rt::io::io_error` conditions in the event of failure. Also included in this module are the `FileInfo` and `DirectoryInfo` traits. When diff --git a/src/libstd/rt/io/net/unix.rs b/src/libstd/rt/io/net/unix.rs index fc7839d545fa9..e424956e2ff63 100644 --- a/src/libstd/rt/io/net/unix.rs +++ b/src/libstd/rt/io/net/unix.rs @@ -37,7 +37,7 @@ pub struct UnixStream { impl UnixStream { fn new(obj: ~RtioPipe) -> UnixStream { - UnixStream { obj: PipeStream::new_bound(obj) } + UnixStream { obj: PipeStream::new(obj) } } /// Connect to a pipe named by `path`. This will attempt to open a diff --git a/src/libstd/rt/io/pipe.rs b/src/libstd/rt/io/pipe.rs index eba58b97c4df4..979a1dfc65e33 100644 --- a/src/libstd/rt/io/pipe.rs +++ b/src/libstd/rt/io/pipe.rs @@ -23,7 +23,7 @@ pub struct PipeStream { } impl PipeStream { - pub fn new_bound(inner: ~RtioPipe) -> PipeStream { + pub fn new(inner: ~RtioPipe) -> PipeStream { PipeStream { obj: inner } } } @@ -42,7 +42,7 @@ impl Reader for PipeStream { } } - fn eof(&mut self) -> bool { fail!() } + fn eof(&mut self) -> bool { false } } impl Writer for PipeStream { @@ -55,5 +55,5 @@ impl Writer for PipeStream { } } - fn flush(&mut self) { fail!() } + fn flush(&mut self) {} } diff --git a/src/libstd/rt/io/process.rs b/src/libstd/rt/io/process.rs index c45429ca2e6cd..a5750211b492c 100644 --- a/src/libstd/rt/io/process.rs +++ b/src/libstd/rt/io/process.rs @@ -89,7 +89,7 @@ impl Process { Ok((p, io)) => Some(Process{ handle: p, io: io.move_iter().map(|p| - p.map(|p| io::PipeStream::new_bound(p)) + p.map(|p| io::PipeStream::new(p)) ).collect() }), Err(ioerr) => { diff --git a/src/libstd/rt/io/stdio.rs b/src/libstd/rt/io/stdio.rs index 294df9a6442a1..e601ece88bb5f 100644 --- a/src/libstd/rt/io/stdio.rs +++ b/src/libstd/rt/io/stdio.rs @@ -30,7 +30,7 @@ use fmt; use libc; use option::{Option, Some, None}; use result::{Ok, Err}; -use rt::rtio::{IoFactory, RtioTTY, with_local_io}; +use rt::rtio::{IoFactory, RtioTTY, with_local_io, RtioPipe}; use super::{Reader, Writer, io_error}; #[fixed_stack_segment] #[inline(never)] @@ -52,8 +52,17 @@ fn tty(fd: libc::c_int, f: &fn(~RtioTTY) -> T) -> T { /// Creates a new non-blocking handle to the stdin of the current process. /// /// See `stdout()` for notes about this function. +#[fixed_stack_segment] #[inline(never)] pub fn stdin() -> StdReader { - do tty(libc::STDIN_FILENO) |tty| { StdReader { inner: tty } } + do with_local_io |io| { + match io.pipe_open(unsafe { libc::dup(libc::STDIN_FILENO) }) { + Ok(stream) => Some(StdReader { inner: stream }), + Err(e) => { + io_error::cond.raise(e); + None + } + } + }.unwrap() } /// Creates a new non-blocking handle to the stdout of the current process. @@ -108,28 +117,7 @@ pub fn println_args(fmt: &fmt::Arguments) { /// Representation of a reader of a standard input stream pub struct StdReader { - priv inner: ~RtioTTY -} - -impl StdReader { - /// Controls whether this output stream is a "raw stream" or simply a normal - /// stream. - /// - /// # Failure - /// - /// This function will raise on the `io_error` condition if an error - /// happens. - pub fn set_raw(&mut self, raw: bool) { - match self.inner.set_raw(raw) { - Ok(()) => {}, - Err(e) => io_error::cond.raise(e), - } - } - - /// Returns whether this tream is attached to a TTY instance or not. - /// - /// This is similar to libc's isatty() function - pub fn isatty(&self) -> bool { self.inner.isatty() } + priv inner: ~RtioPipe } impl Reader for StdReader { diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index 4a4ce4edcc2d6..45c720a89b34c 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -94,6 +94,7 @@ pub trait IoFactory { fn spawn(&mut self, config: ProcessConfig) -> Result<(~RtioProcess, ~[Option<~RtioPipe>]), IoError>; + fn pipe_open(&mut self, fd: c_int) -> Result<~RtioPipe, IoError>; fn unix_bind(&mut self, path: &CString) -> Result<~RtioUnixListener, IoError>; fn unix_connect(&mut self, path: &CString) -> Result<~RtioPipe, IoError>; diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs index 3ab0655071acb..22d7c9c61b3a9 100644 --- a/src/libstd/rt/uv/net.rs +++ b/src/libstd/rt/uv/net.rs @@ -159,7 +159,7 @@ impl StreamWatcher { // but read_stop may be called from inside one of them and we // would end up freeing the in-use environment let handle = self.native_handle(); - unsafe { uvll::read_stop(handle); } + unsafe { assert_eq!(uvll::read_stop(handle), 0); } } pub fn write(&mut self, buf: Buf, cb: ConnectionCallback) { diff --git a/src/libstd/rt/uv/process.rs b/src/libstd/rt/uv/process.rs index c3417109645d4..a039bbc9fc029 100644 --- a/src/libstd/rt/uv/process.rs +++ b/src/libstd/rt/uv/process.rs @@ -146,7 +146,7 @@ unsafe fn set_stdio(dst: *uvll::uv_stdio_container_t, if writable { flags |= uvll::STDIO_WRITABLE_PIPE as libc::c_int; } - let pipe = UvUnboundPipe::new_fresh(loop_); + let pipe = UvUnboundPipe::new(loop_); let handle = pipe.pipe.as_stream().native_handle(); uvll::set_stdio_container_flags(dst, flags); uvll::set_stdio_container_stream(dst, handle); diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 915c7d0da528b..0d22aa51be5be 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -805,47 +805,32 @@ impl IoFactory for UvIoFactory { fn unix_bind(&mut self, path: &CString) -> Result<~RtioUnixListener, IoError> { - let mut pipe = Pipe::new(self.uv_loop(), false); - match pipe.bind(path) { - Ok(()) => { - let handle = get_handle_to_current_scheduler!(); - let pipe = UvUnboundPipe::new(pipe, handle); - Ok(~UvUnixListener::new(pipe) as ~RtioUnixListener) - } - Err(e) => { - let scheduler: ~Scheduler = Local::take(); - do scheduler.deschedule_running_task_and_then |_, task| { - let task_cell = Cell::new(task); - do pipe.close { - let scheduler: ~Scheduler = Local::take(); - scheduler.resume_blocked_task_immediately( - task_cell.take()); - } - } - Err(uv_error_to_io_error(e)) - } + let mut pipe = UvUnboundPipe::new(self.uv_loop()); + match pipe.pipe.bind(path) { + Ok(()) => Ok(~UvUnixListener::new(pipe) as ~RtioUnixListener), + Err(e) => Err(uv_error_to_io_error(e)), } } fn unix_connect(&mut self, path: &CString) -> Result<~RtioPipe, IoError> { - let scheduler: ~Scheduler = Local::take(); - let mut pipe = Pipe::new(self.uv_loop(), false); + let pipe = UvUnboundPipe::new(self.uv_loop()); + let mut rawpipe = pipe.pipe; + let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell> = &result_cell; + let pipe_cell = Cell::new(pipe); + let pipe_cell_ptr: *Cell = &pipe_cell; + let scheduler: ~Scheduler = Local::take(); do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); - do pipe.connect(path) |stream, err| { + do rawpipe.connect(path) |_stream, err| { let res = match err { None => { - let handle = stream.native_handle(); - let pipe = NativeHandle::from_native_handle( - handle as *uvll::uv_pipe_t); - let home = get_handle_to_current_scheduler!(); - let pipe = UvUnboundPipe::new(pipe, home); + let pipe = unsafe { (*pipe_cell_ptr).take() }; Ok(~UvPipeStream::new(pipe) as ~RtioPipe) } - Some(e) => { Err(uv_error_to_io_error(e)) } + Some(e) => Err(uv_error_to_io_error(e)), }; unsafe { (*result_cell_ptr).put_back(res); } let scheduler: ~Scheduler = Local::take(); @@ -854,18 +839,7 @@ impl IoFactory for UvIoFactory { } assert!(!result_cell.is_empty()); - let ret = result_cell.take(); - if ret.is_err() { - let scheduler: ~Scheduler = Local::take(); - do scheduler.deschedule_running_task_and_then |_, task| { - let task_cell = Cell::new(task); - do pipe.close { - let scheduler: ~Scheduler = Local::take(); - scheduler.resume_blocked_task_immediately(task_cell.take()); - } - } - } - return ret; + return result_cell.take(); } fn tty_open(&mut self, fd: c_int, readable: bool) @@ -879,6 +853,14 @@ impl IoFactory for UvIoFactory { Err(e) => Err(uv_error_to_io_error(e)) } } + + fn pipe_open(&mut self, fd: c_int) -> Result<~RtioPipe, IoError> { + let mut pipe = UvUnboundPipe::new(self.uv_loop()); + match pipe.pipe.open(fd) { + Ok(()) => Ok(~UvPipeStream::new(pipe) as ~RtioPipe), + Err(e) => Err(uv_error_to_io_error(e)) + } + } } pub struct UvTcpListener { @@ -1075,14 +1057,9 @@ pub struct UvUnboundPipe { } impl UvUnboundPipe { - /// Takes ownership of an unbound pipe along with the scheduler that it is - /// homed on. - fn new(pipe: Pipe, home: SchedHandle) -> UvUnboundPipe { - UvUnboundPipe { pipe: pipe, home: home } - } - - /// Creates a fresh new unbound pipe on the specified I/O loop - pub fn new_fresh(loop_: &Loop) -> UvUnboundPipe { + /// Creates a new unbound pipe homed to the current scheduler, placed on the + /// specified event loop + pub fn new(loop_: &Loop) -> UvUnboundPipe { UvUnboundPipe { pipe: Pipe::new(loop_, false), home: get_handle_to_current_scheduler!(), @@ -1727,10 +1704,8 @@ impl RtioUnixListener for UvUnixListener { let inc = match status { Some(e) => Err(uv_error_to_io_error(e)), None => { - let inc = Pipe::new(&server.event_loop(), false); - server.accept(inc.as_stream()); - let home = get_handle_to_current_scheduler!(); - let pipe = UvUnboundPipe::new(inc, home); + let pipe = UvUnboundPipe::new(&server.event_loop()); + server.accept(pipe.pipe.as_stream()); Ok(~UvPipeStream::new(pipe) as ~RtioPipe) } }; From 620ab3853abf99ecea3a3d055f47cd6d06433c95 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 17 Oct 2013 21:08:48 -0700 Subject: [PATCH 16/23] Test fixes and merge conflicts --- doc/tutorial-conditions.md | 10 +-- doc/tutorial-tasks.md | 1 - doc/tutorial.md | 4 +- src/libstd/os.rs | 4 +- src/libstd/rt/io/native/file.rs | 18 ++++- src/libstd/rt/io/net/addrinfo.rs | 7 +- src/libstd/rt/util.rs | 20 +++-- src/libstd/rt/uv/addrinfo.rs | 14 +++- src/libstd/rt/uv/mod.rs | 7 ++ src/libstd/rt/uv/net.rs | 53 +++++++------ src/libstd/rt/uv/uvio.rs | 2 +- src/libstd/rt/uv/uvll.rs | 25 ++++--- src/libstd/run.rs | 17 +---- src/libsyntax/ext/source_util.rs | 1 + src/rt/rust_uv.cpp | 13 ---- src/rt/rustrt.def.in | 12 --- src/test/bench/shootout-fasta.rs | 3 +- src/test/bench/shootout-k-nucleotide-pipes.rs | 75 ++++++++++--------- src/test/bench/sudoku.rs | 20 +++-- 19 files changed, 158 insertions(+), 148 deletions(-) diff --git a/doc/tutorial-conditions.md b/doc/tutorial-conditions.md index 726b8bb2b8001..056d967ae6ca8 100644 --- a/doc/tutorial-conditions.md +++ b/doc/tutorial-conditions.md @@ -43,7 +43,7 @@ $ ./example numbers.txt An example program that does this task reads like this: -~~~~ +~~~~{.xfail-test} # #[allow(unused_imports)]; extern mod extra; use extra::fileinput::FileInput; @@ -430,7 +430,7 @@ To trap a condition, use `Condition::trap` in some caller of the site that calls For example, this version of the program traps the `malformed_line` condition and replaces bad input lines with the pair `(-1,-1)`: -~~~~ +~~~~{.xfail-test} # #[allow(unused_imports)]; extern mod extra; use extra::fileinput::FileInput; @@ -507,7 +507,7 @@ In the example program, the first form of the `malformed_line` API implicitly as This assumption may not be correct; some callers may wish to skip malformed lines, for example. Changing the condition's return type from `(int,int)` to `Option<(int,int)>` will suffice to support this type of recovery: -~~~~ +~~~~{.xfail-test} # #[allow(unused_imports)]; extern mod extra; use extra::fileinput::FileInput; @@ -594,7 +594,7 @@ until all relevant combinations encountered in practice are encoded. In the example, suppose a third possible recovery form arose: reusing the previous value read. This can be encoded in the handler API by introducing a helper type: `enum MalformedLineFix`. -~~~~ +~~~~{.xfail-test} # #[allow(unused_imports)]; extern mod extra; use extra::fileinput::FileInput; @@ -720,7 +720,7 @@ task failed at 'called `Option::unwrap()` on a `None` value', .../libs To make the program robust -- or at least flexible -- in the face of this potential failure, a second condition and a helper function will suffice: -~~~~ +~~~~{.xfail-test} # #[allow(unused_imports)]; extern mod extra; use extra::fileinput::FileInput; diff --git a/doc/tutorial-tasks.md b/doc/tutorial-tasks.md index 767f712a8d8c1..4983a5af3e5ab 100644 --- a/doc/tutorial-tasks.md +++ b/doc/tutorial-tasks.md @@ -69,7 +69,6 @@ calling the `spawn` function with a closure argument. `spawn` executes the closure in the new task. ~~~~ -# use std::io::println; # use std::task::spawn; // Print something profound in a different task using a named function diff --git a/doc/tutorial.md b/doc/tutorial.md index 7451919c5becf..f9f110c122b28 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -2907,12 +2907,12 @@ you just have to import it with an `use` statement. For example, it re-exports `println` which is defined in `std::io::println`: ~~~ -use puts = std::io::println; +use puts = std::rt::io::stdio::println; fn main() { println("println is imported per default."); puts("Doesn't hinder you from importing it under an different name yourself."); - ::std::io::println("Or from not using the automatic import."); + ::std::rt::io::stdio::println("Or from not using the automatic import."); } ~~~ diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 99930b39a6533..1f32c6a0a35ef 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -189,6 +189,8 @@ pub fn env() -> ~[(~str,~str)] { #[cfg(windows)] unsafe fn get_env_pairs() -> ~[~str] { #[fixed_stack_segment]; #[inline(never)]; + use c_str; + use str::StrSlice; use libc::funcs::extra::kernel32::{ GetEnvironmentStringsA, @@ -201,7 +203,7 @@ pub fn env() -> ~[(~str,~str)] { } let mut result = ~[]; do c_str::from_c_multistring(ch as *libc::c_char, None) |cstr| { - result.push(cstr.as_str().to_owned()); + result.push(cstr.as_str().unwrap().to_owned()); }; FreeEnvironmentStringsA(ch); result diff --git a/src/libstd/rt/io/native/file.rs b/src/libstd/rt/io/native/file.rs index a2b2289679afc..ba819df071a97 100644 --- a/src/libstd/rt/io/native/file.rs +++ b/src/libstd/rt/io/native/file.rs @@ -17,9 +17,18 @@ use os; use prelude::*; use super::super::*; -fn raise_error() { +#[cfg(windows)] +fn get_err(errno: i32) -> (IoErrorKind, &'static str) { + match errno { + libc::EOF => (EndOfFile, "end of file"), + _ => (OtherIoError, "unknown error"), + } +} + +#[cfg(not(windows))] +fn get_err(errno: i32) -> (IoErrorKind, &'static str) { // XXX: this should probably be a bit more descriptive... - let (kind, desc) = match os::errno() as i32 { + match errno { libc::EOF => (EndOfFile, "end of file"), // These two constants can have the same value on some systems, but @@ -28,8 +37,11 @@ fn raise_error() { (ResourceUnavailable, "resource temporarily unavailable"), _ => (OtherIoError, "unknown error"), - }; + } +} +fn raise_error() { + let (kind, desc) = get_err(os::errno() as i32); io_error::cond.raise(IoError { kind: kind, desc: desc, diff --git a/src/libstd/rt/io/net/addrinfo.rs b/src/libstd/rt/io/net/addrinfo.rs index e0c92730cd905..27cf9781c9c3c 100644 --- a/src/libstd/rt/io/net/addrinfo.rs +++ b/src/libstd/rt/io/net/addrinfo.rs @@ -91,8 +91,11 @@ pub fn get_host_addresses(host: &str) -> Option<~[IpAddr]> { /// # Failure /// /// On failure, this will raise on the `io_error` condition. -pub fn lookup(hostname: Option<&str>, servname: Option<&str>, - hint: Option) -> Option<~[Info]> { +/// +/// XXX: this is not public because the `Hint` structure is not ready for public +/// consumption just yet. +fn lookup(hostname: Option<&str>, servname: Option<&str>, + hint: Option) -> Option<~[Info]> { do with_local_io |io| { match io.get_host_addresses(hostname, servname, hint) { Ok(i) => Some(i), diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs index e859f8e4fdb35..070985fb0a5cf 100644 --- a/src/libstd/rt/util.rs +++ b/src/libstd/rt/util.rs @@ -72,16 +72,22 @@ pub fn default_sched_threads() -> uint { pub fn dumb_println(args: &fmt::Arguments) { use rt::io::native::stdio::stderr; use rt::io::{Writer, io_error, ResourceUnavailable}; + use rt::task::Task; + use rt::local::Local; let mut out = stderr(); - let mut again = true; - do io_error::cond.trap(|e| { - again = e.kind == ResourceUnavailable; - }).inside { - while again { - again = false; - fmt::writeln(&mut out as &mut Writer, args); + if Local::exists(None::) { + let mut again = true; + do io_error::cond.trap(|e| { + again = e.kind == ResourceUnavailable; + }).inside { + while again { + again = false; + fmt::writeln(&mut out as &mut Writer, args); + } } + } else { + fmt::writeln(&mut out as &mut Writer, args); } } diff --git a/src/libstd/rt/uv/addrinfo.rs b/src/libstd/rt/uv/addrinfo.rs index 7556d7db665ef..a1593d5c8db73 100644 --- a/src/libstd/rt/uv/addrinfo.rs +++ b/src/libstd/rt/uv/addrinfo.rs @@ -73,13 +73,14 @@ impl GetAddrInfoRequest { cb(req, addrinfo, err) }; - let hint = hints.map(|hint| unsafe { + let hint = hints.map(|hint| { let mut flags = 0; do each_ai_flag |cval, aival| { if hint.flags & (aival as uint) != 0 { flags |= cval as i32; } } + /* XXX: do we really want to support these? let socktype = match hint.socktype { Some(ai::Stream) => uvll::rust_SOCK_STREAM(), Some(ai::Datagram) => uvll::rust_SOCK_DGRAM(), @@ -91,6 +92,9 @@ impl GetAddrInfoRequest { Some(ai::TCP) => uvll::rust_IPPROTO_TCP(), _ => 0, }; + */ + let socktype = 0; + let protocol = 0; uvll::addrinfo { ai_flags: flags, @@ -167,7 +171,8 @@ impl GetAddrInfoRequest { } } -fn each_ai_flag(f: &fn(c_int, ai::Flag)) { +fn each_ai_flag(_f: &fn(c_int, ai::Flag)) { + /* XXX: do we really want to support these? unsafe { f(uvll::rust_AI_ADDRCONFIG(), ai::AddrConfig); f(uvll::rust_AI_ALL(), ai::All); @@ -177,6 +182,7 @@ fn each_ai_flag(f: &fn(c_int, ai::Flag)) { f(uvll::rust_AI_PASSIVE(), ai::Passive); f(uvll::rust_AI_V4MAPPED(), ai::V4Mapped); } + */ } // Traverse the addrinfo linked list, producing a vector of Rust socket addresses @@ -197,6 +203,7 @@ pub fn accum_addrinfo(addr: &net::UvAddrInfo) -> ~[ai::Info] { } } + /* XXX: do we really want to support these let protocol = match (*addr).ai_protocol { p if p == uvll::rust_IPPROTO_UDP() => Some(ai::UDP), p if p == uvll::rust_IPPROTO_TCP() => Some(ai::TCP), @@ -208,6 +215,9 @@ pub fn accum_addrinfo(addr: &net::UvAddrInfo) -> ~[ai::Info] { p if p == uvll::rust_SOCK_RAW() => Some(ai::Raw), _ => None, }; + */ + let protocol = None; + let socktype = None; addrs.push(ai::Info { address: rustaddr, diff --git a/src/libstd/rt/uv/mod.rs b/src/libstd/rt/uv/mod.rs index 18c9915770763..88bb28d3763f0 100644 --- a/src/libstd/rt/uv/mod.rs +++ b/src/libstd/rt/uv/mod.rs @@ -336,6 +336,13 @@ pub fn status_to_maybe_uv_error(status: c_int) -> Option /// The uv buffer type pub type Buf = uvll::uv_buf_t; +pub fn empty_buf() -> Buf { + uvll::uv_buf_t { + base: null(), + len: 0, + } +} + /// Borrow a slice to a Buf pub fn slice_to_uv_buf(v: &[u8]) -> Buf { let data = vec::raw::to_ptr(v); diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs index 22d7c9c61b3a9..77de8348c1461 100644 --- a/src/libstd/rt/uv/net.rs +++ b/src/libstd/rt/uv/net.rs @@ -14,7 +14,7 @@ use rt::uv::uvll; use rt::uv::uvll::*; use rt::uv::{AllocCallback, ConnectionCallback, ReadCallback, UdpReceiveCallback, UdpSendCallback}; use rt::uv::{Loop, Watcher, Request, UvError, Buf, NativeHandle, - status_to_maybe_uv_error, vec_to_uv_buf}; + status_to_maybe_uv_error, empty_buf}; use rt::io::net::ip::{SocketAddr, Ipv4Addr, Ipv6Addr}; use vec; use str; @@ -119,23 +119,17 @@ impl Watcher for StreamWatcher { } impl StreamWatcher { pub fn read_start(&mut self, alloc: AllocCallback, cb: ReadCallback) { - { - let data = self.get_watcher_data(); - data.alloc_cb = Some(alloc); - data.read_cb = Some(cb); - } - - let ret = unsafe { uvll::read_start(self.native_handle(), alloc_cb, read_cb) }; - - if ret != 0 { - // uvll::read_start failed, so read_cb will not be called. - // Call it manually for scheduling. - call_read_cb(self.native_handle(), ret as ssize_t); - } - - fn call_read_cb(stream: *uvll::uv_stream_t, errno: ssize_t) { - #[fixed_stack_segment]; #[inline(never)]; - read_cb(stream, errno, vec_to_uv_buf(~[])); + unsafe { + match uvll::read_start(self.native_handle(), alloc_cb, read_cb) { + 0 => { + let data = self.get_watcher_data(); + data.alloc_cb = Some(alloc); + data.read_cb = Some(cb); + } + n => { + cb(*self, 0, empty_buf(), Some(UvError(n))) + } + } } extern fn alloc_cb(stream: *uvll::uv_stream_t, suggested_size: size_t) -> Buf { @@ -163,16 +157,21 @@ impl StreamWatcher { } pub fn write(&mut self, buf: Buf, cb: ConnectionCallback) { - { - let data = self.get_watcher_data(); - assert!(data.write_cb.is_none()); - data.write_cb = Some(cb); - } - let req = WriteRequest::new(); - unsafe { - assert_eq!(0, uvll::write(req.native_handle(), self.native_handle(), [buf], write_cb)); - } + return unsafe { + match uvll::write(req.native_handle(), self.native_handle(), + [buf], write_cb) { + 0 => { + let data = self.get_watcher_data(); + assert!(data.write_cb.is_none()); + data.write_cb = Some(cb); + } + n => { + req.delete(); + cb(*self, Some(UvError(n))) + } + } + }; extern fn write_cb(req: *uvll::uv_write_t, status: c_int) { let write_request: WriteRequest = NativeHandle::from_native_handle(req); diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 0d22aa51be5be..f12b1bce9e67d 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -229,7 +229,7 @@ impl EventLoop for UvEventLoop { } } - fn remote_callback(&mut self, f: ~fn()) -> ~RemoteCallback{ + fn remote_callback(&mut self, f: ~fn()) -> ~RemoteCallback { ~UvRemoteCallback::new(self.uvio.uv_loop(), f) as ~RemoteCallback } diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index 8f8aea9d12169..f3e14dc314b70 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -1146,17 +1146,18 @@ extern { height: *c_int) -> c_int; fn rust_uv_guess_handle(fd: c_int) -> uv_handle_type; + // XXX: see comments in addrinfo.rs // These should all really be constants... - #[rust_stack] pub fn rust_SOCK_STREAM() -> c_int; - #[rust_stack] pub fn rust_SOCK_DGRAM() -> c_int; - #[rust_stack] pub fn rust_SOCK_RAW() -> c_int; - #[rust_stack] pub fn rust_IPPROTO_UDP() -> c_int; - #[rust_stack] pub fn rust_IPPROTO_TCP() -> c_int; - #[rust_stack] pub fn rust_AI_ADDRCONFIG() -> c_int; - #[rust_stack] pub fn rust_AI_ALL() -> c_int; - #[rust_stack] pub fn rust_AI_CANONNAME() -> c_int; - #[rust_stack] pub fn rust_AI_NUMERICHOST() -> c_int; - #[rust_stack] pub fn rust_AI_NUMERICSERV() -> c_int; - #[rust_stack] pub fn rust_AI_PASSIVE() -> c_int; - #[rust_stack] pub fn rust_AI_V4MAPPED() -> c_int; + //#[rust_stack] pub fn rust_SOCK_STREAM() -> c_int; + //#[rust_stack] pub fn rust_SOCK_DGRAM() -> c_int; + //#[rust_stack] pub fn rust_SOCK_RAW() -> c_int; + //#[rust_stack] pub fn rust_IPPROTO_UDP() -> c_int; + //#[rust_stack] pub fn rust_IPPROTO_TCP() -> c_int; + //#[rust_stack] pub fn rust_AI_ADDRCONFIG() -> c_int; + //#[rust_stack] pub fn rust_AI_ALL() -> c_int; + //#[rust_stack] pub fn rust_AI_CANONNAME() -> c_int; + //#[rust_stack] pub fn rust_AI_NUMERICHOST() -> c_int; + //#[rust_stack] pub fn rust_AI_NUMERICSERV() -> c_int; + //#[rust_stack] pub fn rust_AI_PASSIVE() -> c_int; + //#[rust_stack] pub fn rust_AI_V4MAPPED() -> c_int; } diff --git a/src/libstd/run.rs b/src/libstd/run.rs index c4cb8be2061f9..d5f8e82b90fc5 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -19,6 +19,7 @@ use libc; use prelude::*; use rt::io::native::process; use rt::io; +use rt::io::extensions::ReaderUtil; use task; /** @@ -189,18 +190,6 @@ impl Process { let output = Cell::new(self.inner.take_output()); let error = Cell::new(self.inner.take_error()); - fn read_everything(r: &mut io::Reader) -> ~[u8] { - let mut ret = ~[]; - let mut buf = [0, ..1024]; - loop { - match r.read(buf) { - Some(n) => { ret.push_all(buf.slice_to(n)); } - None => break - } - } - return ret; - } - // Spawn two entire schedulers to read both stdout and sterr // in parallel so we don't deadlock while blocking on one // or the other. FIXME (#2625): Surely there's a much more @@ -210,13 +199,13 @@ impl Process { let ch_clone = ch.clone(); do task::spawn_sched(task::SingleThreaded) { match error.take() { - Some(ref mut e) => ch.send((2, read_everything(*e))), + Some(ref mut e) => ch.send((2, e.read_to_end())), None => ch.send((2, ~[])) } } do task::spawn_sched(task::SingleThreaded) { match output.take() { - Some(ref mut e) => ch_clone.send((1, read_everything(*e))), + Some(ref mut e) => ch_clone.send((1, e.read_to_end())), None => ch_clone.send((1, ~[])) } } diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 047fc541ba8b3..119a74cccd6d5 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -129,6 +129,7 @@ pub fn expand_include_bin(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree]) file.display(), e.desc)); } None => { + let bytes = at_vec::to_managed_move(bytes); base::MRExpr(cx.expr_lit(sp, ast::lit_binary(bytes))) } } diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index 7ab57e6909aa7..55fa09c38183d 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -638,19 +638,6 @@ rust_uv_pipe_init(uv_loop_t *loop, uv_pipe_t* p, int ipc) { return uv_pipe_init(loop, p, ipc); } -extern "C" int rust_SOCK_STREAM() { return SOCK_STREAM; } -extern "C" int rust_SOCK_DGRAM() { return SOCK_DGRAM; } -extern "C" int rust_SOCK_RAW() { return SOCK_RAW; } -extern "C" int rust_IPPROTO_UDP() { return IPPROTO_UDP; } -extern "C" int rust_IPPROTO_TCP() { return IPPROTO_TCP; } -extern "C" int rust_AI_ADDRCONFIG() { return AI_ADDRCONFIG; } -extern "C" int rust_AI_ALL() { return AI_ALL; } -extern "C" int rust_AI_CANONNAME() { return AI_CANONNAME; } -extern "C" int rust_AI_NUMERICHOST() { return AI_NUMERICHOST; } -extern "C" int rust_AI_NUMERICSERV() { return AI_NUMERICSERV; } -extern "C" int rust_AI_PASSIVE() { return AI_PASSIVE; } -extern "C" int rust_AI_V4MAPPED() { return AI_V4MAPPED; } - extern "C" int rust_uv_pipe_open(uv_pipe_t *pipe, int file) { return uv_pipe_open(pipe, file); diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 6c3988d6b0152..203f2e4d5f2b4 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -199,18 +199,6 @@ bufrelease bufnew rust_take_dlerror_lock rust_drop_dlerror_lock -rust_SOCK_STREAM -rust_SOCK_DGRAM -rust_SOCK_RAW -rust_IPPROTO_UDP -rust_IPPROTO_TCP -rust_AI_ADDRCONFIG -rust_AI_ALL -rust_AI_CANONNAME -rust_AI_NUMERICHOST -rust_AI_NUMERICSERV -rust_AI_PASSIVE -rust_AI_V4MAPPED rust_uv_pipe_open rust_uv_pipe_bind rust_uv_pipe_connect diff --git a/src/test/bench/shootout-fasta.rs b/src/test/bench/shootout-fasta.rs index 3d1362b2f2931..52f068b8b1cdd 100644 --- a/src/test/bench/shootout-fasta.rs +++ b/src/test/bench/shootout-fasta.rs @@ -111,6 +111,7 @@ fn acid(ch: char, prob: u32) -> AminoAcids { } fn main() { + use std::rt::io::file::FileInfo; let args = os::args(); let args = if os::getenv("RUST_BENCH").is_some() { // alioth tests k-nucleotide with this data at 25,000,000 @@ -122,7 +123,7 @@ fn main() { }; let writer = if os::getenv("RUST_BENCH").is_some() { - let file = "./shootout-fasta.data".open_writer(io::CreateOrTruncate); + let file = Path::new("./shootout-fasta.data").open_writer(io::CreateOrTruncate); @mut file as @mut io::Writer } else { @mut io::stdout() as @mut io::Writer diff --git a/src/test/bench/shootout-k-nucleotide-pipes.rs b/src/test/bench/shootout-k-nucleotide-pipes.rs index 83a0fbd42ced2..cfc78e1615ec0 100644 --- a/src/test/bench/shootout-k-nucleotide-pipes.rs +++ b/src/test/bench/shootout-k-nucleotide-pipes.rs @@ -20,6 +20,7 @@ use std::comm; use std::hashmap::HashMap; use std::option; use std::os; +use std::rt::io; use std::str; use std::task; use std::util; @@ -193,48 +194,48 @@ fn main() { let mut proc_mode = false; loop { - let line = match rdr.read_line() { - Some(ln) => ln, None => break, - }; - let line = line.trim().to_owned(); - - if line.len() == 0u { continue; } - - match (line[0] as char, proc_mode) { - - // start processing if this is the one - ('>', false) => { - match line.slice_from(1).find_str("THREE") { - option::Some(_) => { proc_mode = true; } - option::None => { } - } - } - - // break our processing - ('>', true) => { break; } - - // process the sequence for k-mers - (_, true) => { - let line_bytes = line.as_bytes(); - - for (ii, _sz) in sizes.iter().enumerate() { - let lb = line_bytes.to_owned(); - to_child[ii].send(lb); - } - } - - // whatever - _ => { } - } + let line = match io::ignore_io_error(|| rdr.read_line()) { + Some(ln) => ln, None => break, + }; + let line = line.trim().to_owned(); + + if line.len() == 0u { continue; } + + match (line[0] as char, proc_mode) { + + // start processing if this is the one + ('>', false) => { + match line.slice_from(1).find_str("THREE") { + option::Some(_) => { proc_mode = true; } + option::None => { } + } + } + + // break our processing + ('>', true) => { break; } + + // process the sequence for k-mers + (_, true) => { + let line_bytes = line.as_bytes(); + + for (ii, _sz) in sizes.iter().enumerate() { + let lb = line_bytes.to_owned(); + to_child[ii].send(lb); + } + } + + // whatever + _ => { } + } } // finish... - for (ii, _sz) in sizes.iter().enumerate() { - to_child[ii].send(~[]); + for (ii, _sz) in sizes.iter().enumerate() { + to_child[ii].send(~[]); } // now fetch and print result messages - for (ii, _sz) in sizes.iter().enumerate() { - println(from_child[ii].recv()); + for (ii, _sz) in sizes.iter().enumerate() { + println(from_child[ii].recv()); } } diff --git a/src/test/bench/sudoku.rs b/src/test/bench/sudoku.rs index 21d492d85fc33..d4f4a46af38b1 100644 --- a/src/test/bench/sudoku.rs +++ b/src/test/bench/sudoku.rs @@ -15,6 +15,8 @@ extern mod extra; use std::rt::io; +use std::rt::io::stdio::StdReader; +use std::rt::io::buffered::BufferedReader; use std::os; use std::uint; use std::unstable::intrinsics::cttz16; @@ -66,12 +68,14 @@ impl Sudoku { return true; } - pub fn read(reader: @mut io::Reader) -> Sudoku { - assert!(reader.read_line() == ~"9,9"); /* assert first line is exactly "9,9" */ + pub fn read(mut reader: BufferedReader) -> Sudoku { + assert!(reader.read_line().unwrap() == ~"9,9"); /* assert first line is exactly "9,9" */ let mut g = vec::from_fn(10u, { |_i| ~[0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8] }); - while !reader.eof() { - let line = reader.read_line(); + loop { + let line = match reader.read_line() { + Some(ln) => ln, None => break + }; let comps: ~[&str] = line.trim().split_iter(',').collect(); if comps.len() == 3u { @@ -88,11 +92,11 @@ impl Sudoku { pub fn write(&self, writer: @mut io::Writer) { for row in range(0u8, 9u8) { - writer.write_str(format!("{}", self.grid[row][0] as uint)); + write!(writer, "{}", self.grid[row][0]); for col in range(1u8, 9u8) { - writer.write_str(format!(" {}", self.grid[row][col] as uint)); + write!(writer, " {}", self.grid[row][col]); } - writer.write_char('\n'); + write!(writer, "\n"); } } @@ -277,7 +281,7 @@ fn main() { let mut sudoku = if use_default { Sudoku::from_vec(&DEFAULT_SUDOKU) } else { - Sudoku::read(@mut io::stdin() as @mut io::Reader) + Sudoku::read(BufferedReader::new(io::stdin())) }; sudoku.solve(); sudoku.write(@mut io::stdout() as @mut io::Writer); From c4907cfd14f9afa1fc26e2fdddf128f834fe5ce5 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 21 Oct 2013 17:11:42 -0700 Subject: [PATCH 17/23] Remove std::io from ebml --- src/libextra/ebml.rs | 68 ++- src/libextra/uuid.rs | 10 +- src/librustc/metadata/encoder.rs | 114 +++-- src/librustc/metadata/tyencode.rs | 452 ++++++++---------- src/librustc/middle/astencode.rs | 30 +- src/libstd/rt/io/mem.rs | 86 +++- .../run-pass/deriving-encodable-decodable.rs | 12 +- 7 files changed, 393 insertions(+), 379 deletions(-) diff --git a/src/libextra/ebml.rs b/src/libextra/ebml.rs index 34515a2b955cb..1a21150d11b59 100644 --- a/src/libextra/ebml.rs +++ b/src/libextra/ebml.rs @@ -96,17 +96,8 @@ pub mod reader { use std::cast::transmute; use std::int; - use std::io; use std::option::{None, Option, Some}; - #[cfg(target_arch = "x86")] - #[cfg(target_arch = "x86_64")] - use std::ptr::offset; - - #[cfg(target_arch = "x86")] - #[cfg(target_arch = "x86_64")] - use std::unstable::intrinsics::bswap32; - // ebml reading struct Res { @@ -144,6 +135,9 @@ pub mod reader { #[cfg(target_arch = "x86")] #[cfg(target_arch = "x86_64")] pub fn vuint_at(data: &[u8], start: uint) -> Res { + use std::ptr::offset; + use std::unstable::intrinsics::bswap32; + if data.len() - start < 4 { return vuint_at_slow(data, start); } @@ -178,8 +172,7 @@ pub mod reader { } } - #[cfg(target_arch = "arm")] - #[cfg(target_arch = "mips")] + #[cfg(not(target_arch = "x86"), not(target_arch = "x86_64"))] pub fn vuint_at(data: &[u8], start: uint) -> Res { vuint_at_slow(data, start) } @@ -265,17 +258,17 @@ pub mod reader { pub fn doc_as_u16(d: Doc) -> u16 { assert_eq!(d.end, d.start + 2u); - io::u64_from_be_bytes(*d.data, d.start, 2u) as u16 + ::std::io::u64_from_be_bytes(*d.data, d.start, 2u) as u16 } pub fn doc_as_u32(d: Doc) -> u32 { assert_eq!(d.end, d.start + 4u); - io::u64_from_be_bytes(*d.data, d.start, 4u) as u32 + ::std::io::u64_from_be_bytes(*d.data, d.start, 4u) as u32 } pub fn doc_as_u64(d: Doc) -> u64 { assert_eq!(d.end, d.start + 8u); - io::u64_from_be_bytes(*d.data, d.start, 8u) + ::std::io::u64_from_be_bytes(*d.data, d.start, 8u) } pub fn doc_as_i8(d: Doc) -> i8 { doc_as_u8(d) as i8 } @@ -614,11 +607,14 @@ pub mod writer { use std::cast; use std::clone::Clone; - use std::io; + use std::rt::io; + use std::rt::io::{Writer, Seek}; + use std::rt::io::mem::MemWriter; // ebml writing pub struct Encoder { - writer: @io::Writer, + // FIXME(#5665): this should take a trait object + writer: @mut MemWriter, priv size_positions: ~[uint], } @@ -631,7 +627,7 @@ pub mod writer { } } - fn write_sized_vuint(w: @io::Writer, n: uint, size: uint) { + fn write_sized_vuint(w: @mut MemWriter, n: uint, size: uint) { match size { 1u => w.write(&[0x80u8 | (n as u8)]), 2u => w.write(&[0x40u8 | ((n >> 8_u) as u8), n as u8]), @@ -643,7 +639,7 @@ pub mod writer { }; } - fn write_vuint(w: @io::Writer, n: uint) { + fn write_vuint(w: @mut MemWriter, n: uint) { if n < 0x7f_u { write_sized_vuint(w, n, 1u); return; } if n < 0x4000_u { write_sized_vuint(w, n, 2u); return; } if n < 0x200000_u { write_sized_vuint(w, n, 3u); return; } @@ -651,7 +647,7 @@ pub mod writer { fail!("vint to write too big: {}", n); } - pub fn Encoder(w: @io::Writer) -> Encoder { + pub fn Encoder(w: @mut MemWriter) -> Encoder { let size_positions: ~[uint] = ~[]; Encoder { writer: w, @@ -668,7 +664,7 @@ pub mod writer { write_vuint(self.writer, tag_id); // Write a placeholder four-byte size. - self.size_positions.push(self.writer.tell()); + self.size_positions.push(self.writer.tell() as uint); let zeroes: &[u8] = &[0u8, 0u8, 0u8, 0u8]; self.writer.write(zeroes); } @@ -676,10 +672,10 @@ pub mod writer { pub fn end_tag(&mut self) { let last_size_pos = self.size_positions.pop(); let cur_pos = self.writer.tell(); - self.writer.seek(last_size_pos as int, io::SeekSet); - let size = (cur_pos - last_size_pos - 4u); - write_sized_vuint(self.writer, size, 4u); - self.writer.seek(cur_pos as int, io::SeekSet); + self.writer.seek(last_size_pos as i64, io::SeekSet); + let size = (cur_pos as uint - last_size_pos - 4); + write_sized_vuint(self.writer, size as uint, 4u); + self.writer.seek(cur_pos as i64, io::SeekSet); debug!("End tag (size = {})", size); } @@ -697,19 +693,19 @@ pub mod writer { } pub fn wr_tagged_u64(&mut self, tag_id: uint, v: u64) { - do io::u64_to_be_bytes(v, 8u) |v| { + do ::std::io::u64_to_be_bytes(v, 8u) |v| { self.wr_tagged_bytes(tag_id, v); } } pub fn wr_tagged_u32(&mut self, tag_id: uint, v: u32) { - do io::u64_to_be_bytes(v as u64, 4u) |v| { + do ::std::io::u64_to_be_bytes(v as u64, 4u) |v| { self.wr_tagged_bytes(tag_id, v); } } pub fn wr_tagged_u16(&mut self, tag_id: uint, v: u16) { - do io::u64_to_be_bytes(v as u64, 2u) |v| { + do ::std::io::u64_to_be_bytes(v as u64, 2u) |v| { self.wr_tagged_bytes(tag_id, v); } } @@ -719,19 +715,19 @@ pub mod writer { } pub fn wr_tagged_i64(&mut self, tag_id: uint, v: i64) { - do io::u64_to_be_bytes(v as u64, 8u) |v| { + do ::std::io::u64_to_be_bytes(v as u64, 8u) |v| { self.wr_tagged_bytes(tag_id, v); } } pub fn wr_tagged_i32(&mut self, tag_id: uint, v: i32) { - do io::u64_to_be_bytes(v as u64, 4u) |v| { + do ::std::io::u64_to_be_bytes(v as u64, 4u) |v| { self.wr_tagged_bytes(tag_id, v); } } pub fn wr_tagged_i16(&mut self, tag_id: uint, v: i16) { - do io::u64_to_be_bytes(v as u64, 2u) |v| { + do ::std::io::u64_to_be_bytes(v as u64, 2u) |v| { self.wr_tagged_bytes(tag_id, v); } } @@ -963,18 +959,18 @@ mod tests { use serialize::Encodable; use serialize; - use std::io; + use std::rt::io::Decorator; + use std::rt::io::mem::MemWriter; use std::option::{None, Option, Some}; #[test] fn test_option_int() { fn test_v(v: Option) { debug!("v == {:?}", v); - let bytes = do io::with_bytes_writer |wr| { - let mut ebml_w = writer::Encoder(wr); - v.encode(&mut ebml_w) - }; - let ebml_doc = reader::Doc(@bytes); + let wr = @mut MemWriter::new(); + let mut ebml_w = writer::Encoder(wr); + v.encode(&mut ebml_w); + let ebml_doc = reader::Doc(@wr.inner_ref().to_owned()); let mut deser = reader::Decoder(ebml_doc); let v1 = serialize::Decodable::decode(&mut deser); debug!("v1 == {:?}", v1); diff --git a/src/libextra/uuid.rs b/src/libextra/uuid.rs index 345cf64f1281a..b94b74a696cc2 100644 --- a/src/libextra/uuid.rs +++ b/src/libextra/uuid.rs @@ -522,6 +522,8 @@ mod test { use std::str; use std::rand; use std::num::Zero; + use std::rt::io::Decorator; + use std::rt::io::mem::MemWriter; #[test] fn test_new_nil() { @@ -795,10 +797,10 @@ mod test { use serialize::{Encodable, Decodable}; let u = Uuid::new_v4(); - let bytes = do std::io::with_bytes_writer |wr| { - u.encode(&mut ebml::writer::Encoder(wr)); - }; - let u2 = Decodable::decode(&mut ebml::reader::Decoder(ebml::reader::Doc(@bytes))); + let wr = @mut MemWriter::new(); + u.encode(&mut ebml::writer::Encoder(wr)); + let doc = ebml::reader::Doc(@wr.inner_ref().to_owned()); + let u2 = Decodable::decode(&mut ebml::reader::Decoder(doc)); assert_eq!(u, u2); } } diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index e6d6b28257218..d64820332a5d9 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -22,12 +22,16 @@ use middle::typeck; use middle; use std::hashmap::{HashMap, HashSet}; -use std::io; +use std::rt::io::extensions::WriterByteConversions; +use std::rt::io::{Writer, Seek, Decorator}; +use std::rt::io::mem::MemWriter; use std::str; use std::vec; + use extra::flate; use extra::serialize::Encodable; use extra; + use syntax::abi::AbiSet; use syntax::ast::*; use syntax::ast; @@ -68,17 +72,17 @@ pub struct EncodeParams<'self> { } struct Stats { - inline_bytes: uint, - attr_bytes: uint, - dep_bytes: uint, - lang_item_bytes: uint, - link_args_bytes: uint, - impl_bytes: uint, - misc_bytes: uint, - item_bytes: uint, - index_bytes: uint, - zero_bytes: uint, - total_bytes: uint, + inline_bytes: u64, + attr_bytes: u64, + dep_bytes: u64, + lang_item_bytes: u64, + link_args_bytes: u64, + impl_bytes: u64, + misc_bytes: u64, + item_bytes: u64, + index_bytes: u64, + zero_bytes: u64, + total_bytes: u64, n_inlines: uint } @@ -133,7 +137,7 @@ fn encode_region_param(ecx: &EncodeContext, #[deriving(Clone)] struct entry { val: T, - pos: uint + pos: u64 } fn add_to_index(ebml_w: &mut writer::Encoder, @@ -1395,10 +1399,9 @@ fn create_index( fn encode_index( ebml_w: &mut writer::Encoder, buckets: ~[@~[entry]], - write_fn: &fn(@io::Writer, &T)) { - let writer = ebml_w.writer; + write_fn: &fn(@mut MemWriter, &T)) { ebml_w.start_tag(tag_index); - let mut bucket_locs: ~[uint] = ~[]; + let mut bucket_locs = ~[]; ebml_w.start_tag(tag_index_buckets); for bucket in buckets.iter() { bucket_locs.push(ebml_w.writer.tell()); @@ -1406,8 +1409,11 @@ fn encode_index( for elt in (**bucket).iter() { ebml_w.start_tag(tag_index_buckets_bucket_elt); assert!(elt.pos < 0xffff_ffff); - writer.write_be_u32(elt.pos as u32); - write_fn(writer, &elt.val); + { + let wr: &mut MemWriter = ebml_w.writer; + wr.write_be_u32_(elt.pos as u32); + } + write_fn(ebml_w.writer, &elt.val); ebml_w.end_tag(); } ebml_w.end_tag(); @@ -1416,19 +1422,21 @@ fn encode_index( ebml_w.start_tag(tag_index_table); for pos in bucket_locs.iter() { assert!(*pos < 0xffff_ffff); - writer.write_be_u32(*pos as u32); + let wr: &mut MemWriter = ebml_w.writer; + wr.write_be_u32_(*pos as u32); } ebml_w.end_tag(); ebml_w.end_tag(); } -fn write_str(writer: @io::Writer, s: ~str) { - writer.write_str(s); +fn write_str(writer: @mut MemWriter, s: ~str) { + writer.write(s.as_bytes()); } -fn write_i64(writer: @io::Writer, &n: &i64) { +fn write_i64(writer: @mut MemWriter, &n: &i64) { + let wr: &mut MemWriter = writer; assert!(n < 0x7fff_ffff); - writer.write_be_u32(n as u32); + wr.write_be_u32_(n as u32); } fn encode_meta_item(ebml_w: &mut writer::Encoder, mi: @MetaItem) { @@ -1581,11 +1589,17 @@ fn encode_lang_items(ecx: &EncodeContext, ebml_w: &mut writer::Encoder) { ebml_w.start_tag(tag_lang_items_item); ebml_w.start_tag(tag_lang_items_item_id); - ebml_w.writer.write_be_u32(i as u32); + { + let wr: &mut MemWriter = ebml_w.writer; + wr.write_be_u32_(i as u32); + } ebml_w.end_tag(); // tag_lang_items_item_id ebml_w.start_tag(tag_lang_items_item_node_id); - ebml_w.writer.write_be_u32(id.node as u32); + { + let wr: &mut MemWriter = ebml_w.writer; + wr.write_be_u32_(id.node as u32); + } ebml_w.end_tag(); // tag_lang_items_item_node_id ebml_w.end_tag(); // tag_lang_items_item @@ -1602,7 +1616,7 @@ fn encode_link_args(ecx: &EncodeContext, ebml_w: &mut writer::Encoder) { let link_args = cstore::get_used_link_args(ecx.cstore); for link_arg in link_args.iter() { ebml_w.start_tag(tag_link_args_arg); - ebml_w.writer.write_str(link_arg.to_str()); + ebml_w.writer.write(link_arg.as_bytes()); ebml_w.end_tag(); } @@ -1720,7 +1734,7 @@ pub static metadata_encoding_version : &'static [u8] = 0, 0, 0, 1 ]; pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] { - let wr = @io::BytesWriter::new(); + let wr = @mut MemWriter::new(); let stats = Stats { inline_bytes: 0, attr_bytes: 0, @@ -1765,55 +1779,55 @@ pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] { reachable: reachable, }; - let mut ebml_w = writer::Encoder(wr as @io::Writer); + let mut ebml_w = writer::Encoder(wr); encode_hash(&mut ebml_w, ecx.link_meta.extras_hash); - let mut i = *wr.pos; + let mut i = wr.tell(); let crate_attrs = synthesize_crate_attrs(&ecx, crate); encode_attributes(&mut ebml_w, crate_attrs); - ecx.stats.attr_bytes = *wr.pos - i; + ecx.stats.attr_bytes = wr.tell() - i; - i = *wr.pos; + i = wr.tell(); encode_crate_deps(&ecx, &mut ebml_w, ecx.cstore); - ecx.stats.dep_bytes = *wr.pos - i; + ecx.stats.dep_bytes = wr.tell() - i; // Encode the language items. - i = *wr.pos; + i = wr.tell(); encode_lang_items(&ecx, &mut ebml_w); - ecx.stats.lang_item_bytes = *wr.pos - i; + ecx.stats.lang_item_bytes = wr.tell() - i; // Encode the link args. - i = *wr.pos; + i = wr.tell(); encode_link_args(&ecx, &mut ebml_w); - ecx.stats.link_args_bytes = *wr.pos - i; + ecx.stats.link_args_bytes = wr.tell() - i; // Encode the def IDs of impls, for coherence checking. - i = *wr.pos; + i = wr.tell(); encode_impls(&ecx, crate, &mut ebml_w); - ecx.stats.impl_bytes = *wr.pos - i; + ecx.stats.impl_bytes = wr.tell() - i; // Encode miscellaneous info. - i = *wr.pos; + i = wr.tell(); encode_misc_info(&ecx, crate, &mut ebml_w); - ecx.stats.misc_bytes = *wr.pos - i; + ecx.stats.misc_bytes = wr.tell() - i; // Encode and index the items. ebml_w.start_tag(tag_items); - i = *wr.pos; + i = wr.tell(); let items_index = encode_info_for_items(&ecx, &mut ebml_w, crate); - ecx.stats.item_bytes = *wr.pos - i; + ecx.stats.item_bytes = wr.tell() - i; - i = *wr.pos; + i = wr.tell(); let items_buckets = create_index(items_index); encode_index(&mut ebml_w, items_buckets, write_i64); - ecx.stats.index_bytes = *wr.pos - i; + ecx.stats.index_bytes = wr.tell() - i; ebml_w.end_tag(); - ecx.stats.total_bytes = *wr.pos; + ecx.stats.total_bytes = wr.tell(); if (tcx.sess.meta_stats()) { - for e in wr.bytes.iter() { + for e in wr.inner_ref().iter() { if *e == 0 { ecx.stats.zero_bytes += 1; } @@ -1837,7 +1851,7 @@ pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] { // remaining % 4 bytes. wr.write(&[0u8, 0u8, 0u8, 0u8]); - let writer_bytes: &mut ~[u8] = wr.bytes; + let writer_bytes: &mut ~[u8] = wr.inner_mut_ref(); metadata_encoding_version.to_owned() + flate::deflate_bytes(*writer_bytes) @@ -1850,7 +1864,7 @@ pub fn encoded_ty(tcx: ty::ctxt, t: ty::t) -> ~str { ds: def_to_str, tcx: tcx, abbrevs: tyencode::ac_no_abbrevs}; - do io::with_str_writer |wr| { - tyencode::enc_ty(wr, cx, t); - } + let wr = @mut MemWriter::new(); + tyencode::enc_ty(wr, cx, t); + str::from_utf8(*wr.inner_ref()) } diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 33be1be895556..7fb33c881156b 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -10,19 +10,26 @@ // Type encoding +use std::hashmap::HashMap; +use std::rt::io; +use std::rt::io::{Decorator, Writer, Seek}; +use std::rt::io::mem::MemWriter; +use std::str; +use std::fmt; use middle::ty::param_ty; use middle::ty; -use std::hashmap::HashMap; -use std::io::WriterUtil; -use std::io; use syntax::abi::AbiSet; use syntax::ast; use syntax::ast::*; use syntax::diagnostic::span_handler; use syntax::print::pprust::*; +macro_rules! mywrite( ($wr:expr, $($arg:tt)*) => ( + format_args!(|a| { mywrite($wr, a) }, $($arg)*) +) ) + pub struct ctxt { diag: @mut span_handler, // Def -> str Callback: @@ -46,6 +53,10 @@ pub enum abbrev_ctxt { ac_use_abbrevs(@mut HashMap), } +fn mywrite(w: @mut MemWriter, fmt: &fmt::Arguments) { + fmt::write(&mut *w as &mut io::Writer, fmt); +} + fn cx_uses_abbrevs(cx: @ctxt) -> bool { match cx.abbrevs { ac_no_abbrevs => return false, @@ -53,41 +64,43 @@ fn cx_uses_abbrevs(cx: @ctxt) -> bool { } } -pub fn enc_ty(w: @io::Writer, cx: @ctxt, t: ty::t) { +pub fn enc_ty(w: @mut MemWriter, cx: @ctxt, t: ty::t) { match cx.abbrevs { ac_no_abbrevs => { let result_str = match cx.tcx.short_names_cache.find(&t) { Some(&s) => s, None => { - let s = do io::with_str_writer |wr| { - enc_sty(wr, cx, &ty::get(t).sty); - }.to_managed(); + let wr = @mut MemWriter::new(); + enc_sty(wr, cx, &ty::get(t).sty); + let s = str::from_utf8(*wr.inner_ref()).to_managed(); cx.tcx.short_names_cache.insert(t, s); s } }; - w.write_str(result_str); + w.write(result_str.as_bytes()); } ac_use_abbrevs(abbrevs) => { match abbrevs.find(&t) { - Some(a) => { w.write_str(a.s); return; } + Some(a) => { w.write(a.s.as_bytes()); return; } None => {} } let pos = w.tell(); enc_sty(w, cx, &ty::get(t).sty); let end = w.tell(); let len = end - pos; - fn estimate_sz(u: uint) -> uint { + fn estimate_sz(u: u64) -> u64 { let mut n = u; - let mut len = 0u; - while n != 0u { len += 1u; n = n >> 4u; } + let mut len = 0; + while n != 0 { len += 1; n = n >> 4; } return len; } - let abbrev_len = 3u + estimate_sz(pos) + estimate_sz(len); + let abbrev_len = 3 + estimate_sz(pos) + estimate_sz(len); if abbrev_len < len { // I.e. it's actually an abbreviation. let s = format!("\\#{:x}:{:x}\\#", pos, len).to_managed(); - let a = ty_abbrev { pos: pos, len: len, s: s }; + let a = ty_abbrev { pos: pos as uint, + len: len as uint, + s: s }; abbrevs.insert(t, a); } return; @@ -95,301 +108,253 @@ pub fn enc_ty(w: @io::Writer, cx: @ctxt, t: ty::t) { } } -fn enc_mutability(w: @io::Writer, mt: ast::Mutability) { +fn enc_mutability(w: @mut MemWriter, mt: ast::Mutability) { match mt { - MutImmutable => (), - MutMutable => w.write_char('m'), + MutImmutable => (), + MutMutable => mywrite!(w, "m"), } } -fn enc_mt(w: @io::Writer, cx: @ctxt, mt: ty::mt) { +fn enc_mt(w: @mut MemWriter, cx: @ctxt, mt: ty::mt) { enc_mutability(w, mt.mutbl); enc_ty(w, cx, mt.ty); } -fn enc_opt(w: @io::Writer, t: Option, enc_f: &fn(T)) { +fn enc_opt(w: @mut MemWriter, t: Option, enc_f: &fn(T)) { match t { - None => w.write_char('n'), - Some(v) => { - w.write_char('s'); - enc_f(v); - } + None => mywrite!(w, "n"), + Some(v) => { + mywrite!(w, "s"); + enc_f(v); + } } } -fn enc_substs(w: @io::Writer, cx: @ctxt, substs: &ty::substs) { +fn enc_substs(w: @mut MemWriter, cx: @ctxt, substs: &ty::substs) { enc_region_substs(w, cx, &substs.regions); do enc_opt(w, substs.self_ty) |t| { enc_ty(w, cx, t) } - w.write_char('['); + mywrite!(w, "["); for t in substs.tps.iter() { enc_ty(w, cx, *t); } - w.write_char(']'); + mywrite!(w, "]"); } -fn enc_region_substs(w: @io::Writer, cx: @ctxt, substs: &ty::RegionSubsts) { +fn enc_region_substs(w: @mut MemWriter, cx: @ctxt, substs: &ty::RegionSubsts) { match *substs { ty::ErasedRegions => { - w.write_char('e'); + mywrite!(w, "e"); } ty::NonerasedRegions(ref regions) => { - w.write_char('n'); + mywrite!(w, "n"); for &r in regions.iter() { enc_region(w, cx, r); } - w.write_char('.'); + mywrite!(w, "."); } } } -fn enc_region(w: @io::Writer, cx: @ctxt, r: ty::Region) { +fn enc_region(w: @mut MemWriter, cx: @ctxt, r: ty::Region) { match r { - ty::re_bound(br) => { - w.write_char('b'); - enc_bound_region(w, cx, br); - } - ty::re_free(ref fr) => { - w.write_char('f'); - w.write_char('['); - w.write_int(fr.scope_id); - w.write_char('|'); - enc_bound_region(w, cx, fr.bound_region); - w.write_char(']'); - } - ty::re_scope(nid) => { - w.write_char('s'); - w.write_int(nid); - w.write_char('|'); - } - ty::re_static => { - w.write_char('t'); - } - ty::re_empty => { - w.write_char('e'); - } - ty::re_infer(_) => { - // these should not crop up after typeck - cx.diag.handler().bug("Cannot encode region variables"); - } + ty::re_bound(br) => { + mywrite!(w, "b"); + enc_bound_region(w, cx, br); + } + ty::re_free(ref fr) => { + mywrite!(w, "f[{}|", fr.scope_id); + enc_bound_region(w, cx, fr.bound_region); + mywrite!(w, "]"); + } + ty::re_scope(nid) => mywrite!(w, "s{}|", nid), + ty::re_static => mywrite!(w, "t"), + ty::re_empty => mywrite!(w, "e"), + ty::re_infer(_) => { + // these should not crop up after typeck + cx.diag.handler().bug("Cannot encode region variables"); + } } } -fn enc_bound_region(w: @io::Writer, cx: @ctxt, br: ty::bound_region) { +fn enc_bound_region(w: @mut MemWriter, cx: @ctxt, br: ty::bound_region) { match br { - ty::br_self => w.write_char('s'), - ty::br_anon(idx) => { - w.write_char('a'); - w.write_uint(idx); - w.write_char('|'); - } - ty::br_named(s) => { - w.write_char('['); - w.write_str(cx.tcx.sess.str_of(s)); - w.write_char(']') - } - ty::br_cap_avoid(id, br) => { - w.write_char('c'); - w.write_int(id); - w.write_char('|'); - enc_bound_region(w, cx, *br); - } - ty::br_fresh(id) => { - w.write_uint(id); - } + ty::br_self => mywrite!(w, "s"), + ty::br_anon(idx) => mywrite!(w, "a{}|", idx), + ty::br_named(s) => mywrite!(w, "[{}]", cx.tcx.sess.str_of(s)), + ty::br_cap_avoid(id, br) => { + mywrite!(w, "c{}|", id); + enc_bound_region(w, cx, *br); + } + ty::br_fresh(id) => mywrite!(w, "{}", id), } } -pub fn enc_vstore(w: @io::Writer, cx: @ctxt, v: ty::vstore) { - w.write_char('/'); +pub fn enc_vstore(w: @mut MemWriter, cx: @ctxt, v: ty::vstore) { + mywrite!(w, "/"); match v { - ty::vstore_fixed(u) => { - w.write_uint(u); - w.write_char('|'); - } - ty::vstore_uniq => { - w.write_char('~'); - } - ty::vstore_box => { - w.write_char('@'); - } - ty::vstore_slice(r) => { - w.write_char('&'); - enc_region(w, cx, r); - } + ty::vstore_fixed(u) => mywrite!(w, "{}|", u), + ty::vstore_uniq => mywrite!(w, "~"), + ty::vstore_box => mywrite!(w, "@"), + ty::vstore_slice(r) => { + mywrite!(w, "&"); + enc_region(w, cx, r); + } } } -pub fn enc_trait_ref(w: @io::Writer, cx: @ctxt, s: &ty::TraitRef) { - w.write_str((cx.ds)(s.def_id)); - w.write_char('|'); +pub fn enc_trait_ref(w: @mut MemWriter, cx: @ctxt, s: &ty::TraitRef) { + mywrite!(w, "{}|", (cx.ds)(s.def_id)); enc_substs(w, cx, &s.substs); } -pub fn enc_trait_store(w: @io::Writer, cx: @ctxt, s: ty::TraitStore) { +pub fn enc_trait_store(w: @mut MemWriter, cx: @ctxt, s: ty::TraitStore) { match s { - ty::UniqTraitStore => w.write_char('~'), - ty::BoxTraitStore => w.write_char('@'), + ty::UniqTraitStore => mywrite!(w, "~"), + ty::BoxTraitStore => mywrite!(w, "@"), ty::RegionTraitStore(re) => { - w.write_char('&'); + mywrite!(w, "&"); enc_region(w, cx, re); } } } -fn enc_sty(w: @io::Writer, cx: @ctxt, st: &ty::sty) { +fn enc_sty(w: @mut MemWriter, cx: @ctxt, st: &ty::sty) { match *st { - ty::ty_nil => w.write_char('n'), - ty::ty_bot => w.write_char('z'), - ty::ty_bool => w.write_char('b'), - ty::ty_char => w.write_char('c'), - ty::ty_int(t) => { - match t { - ty_i => w.write_char('i'), - ty_i8 => w.write_str(&"MB"), - ty_i16 => w.write_str(&"MW"), - ty_i32 => w.write_str(&"ML"), - ty_i64 => w.write_str(&"MD") + ty::ty_nil => mywrite!(w, "n"), + ty::ty_bot => mywrite!(w, "z"), + ty::ty_bool => mywrite!(w, "b"), + ty::ty_char => mywrite!(w, "c"), + ty::ty_int(t) => { + match t { + ty_i => mywrite!(w, "i"), + ty_i8 => mywrite!(w, "MB"), + ty_i16 => mywrite!(w, "MW"), + ty_i32 => mywrite!(w, "ML"), + ty_i64 => mywrite!(w, "MD") + } } - } - ty::ty_uint(t) => { - match t { - ty_u => w.write_char('u'), - ty_u8 => w.write_str(&"Mb"), - ty_u16 => w.write_str(&"Mw"), - ty_u32 => w.write_str(&"Ml"), - ty_u64 => w.write_str(&"Md") + ty::ty_uint(t) => { + match t { + ty_u => mywrite!(w, "u"), + ty_u8 => mywrite!(w, "Mb"), + ty_u16 => mywrite!(w, "Mw"), + ty_u32 => mywrite!(w, "Ml"), + ty_u64 => mywrite!(w, "Md") + } } - } - ty::ty_float(t) => { - match t { - ty_f32 => w.write_str(&"Mf"), - ty_f64 => w.write_str(&"MF"), + ty::ty_float(t) => { + match t { + ty_f32 => mywrite!(w, "Mf"), + ty_f64 => mywrite!(w, "MF"), + } } - } - ty::ty_enum(def, ref substs) => { - w.write_str(&"t["); - w.write_str((cx.ds)(def)); - w.write_char('|'); - enc_substs(w, cx, substs); - w.write_char(']'); - } - ty::ty_trait(def, ref substs, store, mt, bounds) => { - w.write_str(&"x["); - w.write_str((cx.ds)(def)); - w.write_char('|'); - enc_substs(w, cx, substs); - enc_trait_store(w, cx, store); - enc_mutability(w, mt); - let bounds = ty::ParamBounds {builtin_bounds: bounds, - trait_bounds: ~[]}; - enc_bounds(w, cx, &bounds); - w.write_char(']'); - } - ty::ty_tup(ref ts) => { - w.write_str(&"T["); - for t in ts.iter() { enc_ty(w, cx, *t); } - w.write_char(']'); - } - ty::ty_box(mt) => { w.write_char('@'); enc_mt(w, cx, mt); } - ty::ty_uniq(mt) => { w.write_char('~'); enc_mt(w, cx, mt); } - ty::ty_ptr(mt) => { w.write_char('*'); enc_mt(w, cx, mt); } - ty::ty_rptr(r, mt) => { - w.write_char('&'); - enc_region(w, cx, r); - enc_mt(w, cx, mt); - } - ty::ty_evec(mt, v) => { - w.write_char('V'); - enc_mt(w, cx, mt); - enc_vstore(w, cx, v); - } - ty::ty_estr(v) => { - w.write_char('v'); - enc_vstore(w, cx, v); - } - ty::ty_unboxed_vec(mt) => { w.write_char('U'); enc_mt(w, cx, mt); } - ty::ty_closure(ref f) => { - w.write_char('f'); - enc_closure_ty(w, cx, f); - } - ty::ty_bare_fn(ref f) => { - w.write_char('F'); - enc_bare_fn_ty(w, cx, f); - } - ty::ty_infer(_) => { - cx.diag.handler().bug("Cannot encode inference variable types"); - } - ty::ty_param(param_ty {idx: id, def_id: did}) => { - w.write_char('p'); - w.write_str((cx.ds)(did)); - w.write_char('|'); - w.write_str(id.to_str()); - } - ty::ty_self(did) => { - w.write_char('s'); - w.write_str((cx.ds)(did)); - w.write_char('|'); - } - ty::ty_type => w.write_char('Y'), - ty::ty_opaque_closure_ptr(p) => { - w.write_str(&"C&"); - enc_sigil(w, p); - } - ty::ty_opaque_box => w.write_char('B'), - ty::ty_struct(def, ref substs) => { - debug!("~~~~ {}", "a["); - w.write_str(&"a["); - let s = (cx.ds)(def); - debug!("~~~~ {}", s); - w.write_str(s); - debug!("~~~~ {}", "|"); - w.write_char('|'); - enc_substs(w, cx, substs); - debug!("~~~~ {}", "]"); - w.write_char(']'); - } - ty::ty_err => fail!("Shouldn't encode error type") + ty::ty_enum(def, ref substs) => { + mywrite!(w, "t[{}|", (cx.ds)(def)); + enc_substs(w, cx, substs); + mywrite!(w, "]"); + } + ty::ty_trait(def, ref substs, store, mt, bounds) => { + mywrite!(w, "x[{}|", (cx.ds)(def)); + enc_substs(w, cx, substs); + enc_trait_store(w, cx, store); + enc_mutability(w, mt); + let bounds = ty::ParamBounds {builtin_bounds: bounds, + trait_bounds: ~[]}; + enc_bounds(w, cx, &bounds); + mywrite!(w, "]"); + } + ty::ty_tup(ref ts) => { + mywrite!(w, "T["); + for t in ts.iter() { enc_ty(w, cx, *t); } + mywrite!(w, "]"); + } + ty::ty_box(mt) => { mywrite!(w, "@"); enc_mt(w, cx, mt); } + ty::ty_uniq(mt) => { mywrite!(w, "~"); enc_mt(w, cx, mt); } + ty::ty_ptr(mt) => { mywrite!(w, "*"); enc_mt(w, cx, mt); } + ty::ty_rptr(r, mt) => { + mywrite!(w, "&"); + enc_region(w, cx, r); + enc_mt(w, cx, mt); + } + ty::ty_evec(mt, v) => { + mywrite!(w, "V"); + enc_mt(w, cx, mt); + enc_vstore(w, cx, v); + } + ty::ty_estr(v) => { + mywrite!(w, "v"); + enc_vstore(w, cx, v); + } + ty::ty_unboxed_vec(mt) => { mywrite!(w, "U"); enc_mt(w, cx, mt); } + ty::ty_closure(ref f) => { + mywrite!(w, "f"); + enc_closure_ty(w, cx, f); + } + ty::ty_bare_fn(ref f) => { + mywrite!(w, "F"); + enc_bare_fn_ty(w, cx, f); + } + ty::ty_infer(_) => { + cx.diag.handler().bug("Cannot encode inference variable types"); + } + ty::ty_param(param_ty {idx: id, def_id: did}) => { + mywrite!(w, "p{}|{}", (cx.ds)(did), id); + } + ty::ty_self(did) => { + mywrite!(w, "s{}|", (cx.ds)(did)); + } + ty::ty_type => mywrite!(w, "Y"), + ty::ty_opaque_closure_ptr(p) => { + mywrite!(w, "C&"); + enc_sigil(w, p); + } + ty::ty_opaque_box => mywrite!(w, "B"), + ty::ty_struct(def, ref substs) => { + mywrite!(w, "a[{}|", (cx.ds)(def)); + enc_substs(w, cx, substs); + mywrite!(w, "]"); + } + ty::ty_err => fail!("Shouldn't encode error type") } } -fn enc_sigil(w: @io::Writer, sigil: Sigil) { +fn enc_sigil(w: @mut MemWriter, sigil: Sigil) { match sigil { - ManagedSigil => w.write_str("@"), - OwnedSigil => w.write_str("~"), - BorrowedSigil => w.write_str("&"), + ManagedSigil => mywrite!(w, "@"), + OwnedSigil => mywrite!(w, "~"), + BorrowedSigil => mywrite!(w, "&"), } } -fn enc_purity(w: @io::Writer, p: purity) { +fn enc_purity(w: @mut MemWriter, p: purity) { match p { - impure_fn => w.write_char('i'), - unsafe_fn => w.write_char('u'), - extern_fn => w.write_char('c') + impure_fn => mywrite!(w, "i"), + unsafe_fn => mywrite!(w, "u"), + extern_fn => mywrite!(w, "c") } } -fn enc_abi_set(w: @io::Writer, abis: AbiSet) { - w.write_char('['); +fn enc_abi_set(w: @mut MemWriter, abis: AbiSet) { + mywrite!(w, "["); do abis.each |abi| { - w.write_str(abi.name()); - w.write_char(','); + mywrite!(w, "{},", abi.name()); true }; - w.write_char(']') + mywrite!(w, "]") } -fn enc_onceness(w: @io::Writer, o: Onceness) { +fn enc_onceness(w: @mut MemWriter, o: Onceness) { match o { - Once => w.write_char('o'), - Many => w.write_char('m') + Once => mywrite!(w, "o"), + Many => mywrite!(w, "m") } } -pub fn enc_bare_fn_ty(w: @io::Writer, cx: @ctxt, ft: &ty::BareFnTy) { +pub fn enc_bare_fn_ty(w: @mut MemWriter, cx: @ctxt, ft: &ty::BareFnTy) { enc_purity(w, ft.purity); enc_abi_set(w, ft.abis); enc_fn_sig(w, cx, &ft.sig); } -fn enc_closure_ty(w: @io::Writer, cx: @ctxt, ft: &ty::ClosureTy) { +fn enc_closure_ty(w: @mut MemWriter, cx: @ctxt, ft: &ty::ClosureTy) { enc_sigil(w, ft.sigil); enc_purity(w, ft.purity); enc_onceness(w, ft.onceness); @@ -400,37 +365,34 @@ fn enc_closure_ty(w: @io::Writer, cx: @ctxt, ft: &ty::ClosureTy) { enc_fn_sig(w, cx, &ft.sig); } -fn enc_fn_sig(w: @io::Writer, cx: @ctxt, fsig: &ty::FnSig) { - w.write_char('['); +fn enc_fn_sig(w: @mut MemWriter, cx: @ctxt, fsig: &ty::FnSig) { + mywrite!(w, "["); for ty in fsig.inputs.iter() { enc_ty(w, cx, *ty); } - w.write_char(']'); + mywrite!(w, "]"); enc_ty(w, cx, fsig.output); } -fn enc_bounds(w: @io::Writer, cx: @ctxt, bs: &ty::ParamBounds) { +fn enc_bounds(w: @mut MemWriter, cx: @ctxt, bs: &ty::ParamBounds) { for bound in bs.builtin_bounds.iter() { match bound { - ty::BoundSend => w.write_char('S'), - ty::BoundFreeze => w.write_char('K'), - ty::BoundStatic => w.write_char('O'), - ty::BoundSized => w.write_char('Z'), + ty::BoundSend => mywrite!(w, "S"), + ty::BoundFreeze => mywrite!(w, "K"), + ty::BoundStatic => mywrite!(w, "O"), + ty::BoundSized => mywrite!(w, "Z"), } } for &tp in bs.trait_bounds.iter() { - w.write_char('I'); + mywrite!(w, "I"); enc_trait_ref(w, cx, tp); } - w.write_char('.'); + mywrite!(w, "."); } -pub fn enc_type_param_def(w: @io::Writer, cx: @ctxt, v: &ty::TypeParameterDef) { - w.write_str(cx.tcx.sess.str_of(v.ident)); - w.write_char(':'); - w.write_str((cx.ds)(v.def_id)); - w.write_char('|'); +pub fn enc_type_param_def(w: @mut MemWriter, cx: @ctxt, v: &ty::TypeParameterDef) { + mywrite!(w, "{}:{}|", cx.tcx.sess.str_of(v.ident), (cx.ds)(v.def_id)); enc_bounds(w, cx, v.bounds); } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 3d7f28b8b30b1..cb8c7b3262fbf 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -23,13 +23,6 @@ use middle::{ty, typeck, moves}; use middle; use util::ppaux::ty_to_str; -use std::at_vec; -use std::libc; -use extra::ebml::reader; -use extra::ebml; -use extra::serialize; -use extra::serialize::{Encoder, Encodable, EncoderHelpers, DecoderHelpers}; -use extra::serialize::{Decoder, Decodable}; use syntax::ast; use syntax::ast_map; use syntax::ast_util::inlined_item_utils; @@ -40,9 +33,18 @@ use syntax::fold::*; use syntax::fold; use syntax::parse::token; use syntax; -use writer = extra::ebml::writer; +use std::at_vec; +use std::libc; use std::cast; +use std::rt::io::Seek; + +use extra::ebml::reader; +use extra::ebml; +use extra::serialize; +use extra::serialize::{Encoder, Encodable, EncoderHelpers, DecoderHelpers}; +use extra::serialize::{Decoder, Decodable}; +use writer = extra::ebml::writer; #[cfg(test)] use syntax::parse; #[cfg(test)] use syntax::print::pprust; @@ -1319,14 +1321,14 @@ fn mk_ctxt() -> @fake_ext_ctxt { #[cfg(test)] fn roundtrip(in_item: Option<@ast::item>) { - use std::io; + use std::rt::io::Decorator; + use std::rt::io::mem::MemWriter; let in_item = in_item.unwrap(); - let bytes = do io::with_bytes_writer |wr| { - let mut ebml_w = writer::Encoder(wr); - encode_item_ast(&mut ebml_w, in_item); - }; - let ebml_doc = reader::Doc(@bytes); + let wr = @mut MemWriter::new(); + let mut ebml_w = writer::Encoder(wr); + encode_item_ast(&mut ebml_w, in_item); + let ebml_doc = reader::Doc(@wr.inner_ref().to_owned()); let out_item = decode_item_ast(ebml_doc); assert_eq!(in_item, out_item); diff --git a/src/libstd/rt/io/mem.rs b/src/libstd/rt/io/mem.rs index 5f6b4398c22f7..0ec37cd3c0789 100644 --- a/src/libstd/rt/io/mem.rs +++ b/src/libstd/rt/io/mem.rs @@ -22,46 +22,66 @@ use vec; /// Writes to an owned, growable byte vector pub struct MemWriter { - priv buf: ~[u8] + priv buf: ~[u8], + priv pos: uint, } impl MemWriter { - pub fn new() -> MemWriter { MemWriter { buf: vec::with_capacity(128) } } + pub fn new() -> MemWriter { + MemWriter { buf: vec::with_capacity(128), pos: 0 } + } } impl Writer for MemWriter { fn write(&mut self, buf: &[u8]) { - self.buf.push_all(buf) + // Make sure the internal buffer is as least as big as where we + // currently are + let difference = self.pos as i64 - self.buf.len() as i64; + if difference > 0 { + self.buf.grow(difference as uint, &0); + } + + // Figure out what bytes will be used to overwrite what's currently + // there (left), and what will be appended on the end (right) + let cap = self.buf.len() - self.pos; + let (left, right) = if cap <= buf.len() { + (buf.slice_to(cap), buf.slice_from(cap)) + } else { + (buf, &[]) + }; + + // Do the necessary writes + if left.len() > 0 { + vec::bytes::copy_memory(self.buf.mut_slice_from(self.pos), + left, left.len()); + } + if right.len() > 0 { + self.buf.push_all(right); + } + + // Bump us forward + self.pos += buf.len(); } fn flush(&mut self) { /* no-op */ } } impl Seek for MemWriter { - fn tell(&self) -> u64 { self.buf.len() as u64 } - - fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } -} - -impl Decorator<~[u8]> for MemWriter { - - fn inner(self) -> ~[u8] { - match self { - MemWriter { buf: buf } => buf - } - } + fn tell(&self) -> u64 { self.pos as u64 } - fn inner_ref<'a>(&'a self) -> &'a ~[u8] { - match *self { - MemWriter { buf: ref buf } => buf + fn seek(&mut self, pos: i64, style: SeekStyle) { + match style { + SeekSet => { self.pos = pos as uint; } + SeekEnd => { self.pos = self.buf.len() + pos as uint; } + SeekCur => { self.pos += pos as uint; } } } +} - fn inner_mut_ref<'a>(&'a mut self) -> &'a mut ~[u8] { - match *self { - MemWriter { buf: ref mut buf } => buf - } - } +impl Decorator<~[u8]> for MemWriter { + fn inner(self) -> ~[u8] { self.buf } + fn inner_ref<'a>(&'a self) -> &'a ~[u8] { &self.buf } + fn inner_mut_ref<'a>(&'a mut self) -> &'a mut ~[u8] { &mut self.buf } } /// Reads from an owned byte vector @@ -208,6 +228,7 @@ pub fn with_mem_writer(writeFn:&fn(&mut MemWriter)) -> ~[u8] { mod test { use prelude::*; use super::*; + use rt::io::*; #[test] fn test_mem_writer() { @@ -218,7 +239,24 @@ mod test { writer.write([1, 2, 3]); writer.write([4, 5, 6, 7]); assert_eq!(writer.tell(), 8); - assert_eq!(writer.inner(), ~[0, 1, 2, 3, 4, 5 , 6, 7]); + assert_eq!(*writer.inner_ref(), ~[0, 1, 2, 3, 4, 5, 6, 7]); + + writer.seek(0, SeekSet); + assert_eq!(writer.tell(), 0); + writer.write([3, 4]); + assert_eq!(*writer.inner_ref(), ~[3, 4, 2, 3, 4, 5, 6, 7]); + + writer.seek(1, SeekCur); + writer.write([0, 1]); + assert_eq!(*writer.inner_ref(), ~[3, 4, 2, 0, 1, 5, 6, 7]); + + writer.seek(-1, SeekEnd); + writer.write([1, 2]); + assert_eq!(*writer.inner_ref(), ~[3, 4, 2, 0, 1, 5, 6, 1, 2]); + + writer.seek(1, SeekEnd); + writer.write([1]); + assert_eq!(*writer.inner_ref(), ~[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1]); } #[test] diff --git a/src/test/run-pass/deriving-encodable-decodable.rs b/src/test/run-pass/deriving-encodable-decodable.rs index b1c5f2f0f2d72..8d3ad26764281 100644 --- a/src/test/run-pass/deriving-encodable-decodable.rs +++ b/src/test/run-pass/deriving-encodable-decodable.rs @@ -17,7 +17,8 @@ extern mod extra; -use std::io; +use std::rt::io::mem::MemWriter; +use std::rt::io::Decorator; use std::rand::{random, Rand}; use extra::serialize::{Encodable, Decodable}; use extra::ebml; @@ -55,11 +56,10 @@ struct G { fn roundtrip + Decodable>() { let obj: T = random(); - let bytes = do io::with_bytes_writer |w| { - let mut e = Encoder(w); - obj.encode(&mut e); - }; - let doc = ebml::reader::Doc(@bytes); + let w = @mut MemWriter::new(); + let mut e = Encoder(w); + obj.encode(&mut e); + let doc = ebml::reader::Doc(@w.inner_ref().to_owned()); let mut dec = Decoder(doc); let obj2 = Decodable::decode(&mut dec); assert!(obj == obj2); From 6bb1df92511e7ecafe0554b01410f4e68d7bc66f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 21 Oct 2013 23:06:12 -0700 Subject: [PATCH 18/23] Remove std::io once and for all! --- src/libextra/ebml.rs | 20 +- src/libextra/terminfo/parser/compiled.rs | 24 +- src/libextra/terminfo/searcher.rs | 7 +- src/librustc/metadata/decoder.rs | 9 +- src/libstd/io.rs | 1817 ----------------- src/libstd/prelude.rs | 1 - src/libstd/rt/io/extensions.rs | 83 +- src/libstd/std.rs | 1 - src/libstd/to_bytes.rs | 7 +- .../borrowck-auto-mut-ref-to-immut-var.rs | 2 - src/test/run-pass/glob-std.rs | 6 +- 11 files changed, 123 insertions(+), 1854 deletions(-) delete mode 100644 src/libstd/io.rs diff --git a/src/libextra/ebml.rs b/src/libextra/ebml.rs index 1a21150d11b59..f577ed55f9750 100644 --- a/src/libextra/ebml.rs +++ b/src/libextra/ebml.rs @@ -97,6 +97,7 @@ pub mod reader { use std::cast::transmute; use std::int; use std::option::{None, Option, Some}; + use std::rt::io::extensions::u64_from_be_bytes; // ebml reading @@ -258,17 +259,17 @@ pub mod reader { pub fn doc_as_u16(d: Doc) -> u16 { assert_eq!(d.end, d.start + 2u); - ::std::io::u64_from_be_bytes(*d.data, d.start, 2u) as u16 + u64_from_be_bytes(*d.data, d.start, 2u) as u16 } pub fn doc_as_u32(d: Doc) -> u32 { assert_eq!(d.end, d.start + 4u); - ::std::io::u64_from_be_bytes(*d.data, d.start, 4u) as u32 + u64_from_be_bytes(*d.data, d.start, 4u) as u32 } pub fn doc_as_u64(d: Doc) -> u64 { assert_eq!(d.end, d.start + 8u); - ::std::io::u64_from_be_bytes(*d.data, d.start, 8u) + u64_from_be_bytes(*d.data, d.start, 8u) } pub fn doc_as_i8(d: Doc) -> i8 { doc_as_u8(d) as i8 } @@ -610,6 +611,7 @@ pub mod writer { use std::rt::io; use std::rt::io::{Writer, Seek}; use std::rt::io::mem::MemWriter; + use std::rt::io::extensions::u64_to_be_bytes; // ebml writing pub struct Encoder { @@ -693,19 +695,19 @@ pub mod writer { } pub fn wr_tagged_u64(&mut self, tag_id: uint, v: u64) { - do ::std::io::u64_to_be_bytes(v, 8u) |v| { + do u64_to_be_bytes(v, 8u) |v| { self.wr_tagged_bytes(tag_id, v); } } pub fn wr_tagged_u32(&mut self, tag_id: uint, v: u32) { - do ::std::io::u64_to_be_bytes(v as u64, 4u) |v| { + do u64_to_be_bytes(v as u64, 4u) |v| { self.wr_tagged_bytes(tag_id, v); } } pub fn wr_tagged_u16(&mut self, tag_id: uint, v: u16) { - do ::std::io::u64_to_be_bytes(v as u64, 2u) |v| { + do u64_to_be_bytes(v as u64, 2u) |v| { self.wr_tagged_bytes(tag_id, v); } } @@ -715,19 +717,19 @@ pub mod writer { } pub fn wr_tagged_i64(&mut self, tag_id: uint, v: i64) { - do ::std::io::u64_to_be_bytes(v as u64, 8u) |v| { + do u64_to_be_bytes(v as u64, 8u) |v| { self.wr_tagged_bytes(tag_id, v); } } pub fn wr_tagged_i32(&mut self, tag_id: uint, v: i32) { - do ::std::io::u64_to_be_bytes(v as u64, 4u) |v| { + do u64_to_be_bytes(v as u64, 4u) |v| { self.wr_tagged_bytes(tag_id, v); } } pub fn wr_tagged_i16(&mut self, tag_id: uint, v: i16) { - do ::std::io::u64_to_be_bytes(v as u64, 2u) |v| { + do u64_to_be_bytes(v as u64, 2u) |v| { self.wr_tagged_bytes(tag_id, v); } } diff --git a/src/libextra/terminfo/parser/compiled.rs b/src/libextra/terminfo/parser/compiled.rs index bc24c8a6e3063..0020f432114dd 100644 --- a/src/libextra/terminfo/parser/compiled.rs +++ b/src/libextra/terminfo/parser/compiled.rs @@ -14,8 +14,9 @@ use std::{vec, str}; -use std::io::Reader; use std::hashmap::HashMap; +use std::rt::io; +use std::rt::io::extensions::{ReaderByteConversions, ReaderUtil}; use super::super::TermInfo; // These are the orders ncurses uses in its compiled format (as of 5.9). Not sure if portable. @@ -160,7 +161,8 @@ pub static stringnames: &'static[&'static str] = &'static[ "cbt", "_", "cr", "cs "box1"]; /// Parse a compiled terminfo entry, using long capability names if `longnames` is true -pub fn parse(file: @Reader, longnames: bool) -> Result<~TermInfo, ~str> { +pub fn parse(mut file: &mut io::Reader, + longnames: bool) -> Result<~TermInfo, ~str> { let bnames; let snames; let nnames; @@ -176,17 +178,17 @@ pub fn parse(file: @Reader, longnames: bool) -> Result<~TermInfo, ~str> { } // Check magic number - let magic = file.read_le_u16(); + let magic = file.read_le_u16_(); if (magic != 0x011A) { return Err(format!("invalid magic number: expected {:x} but found {:x}", 0x011A, magic as uint)); } - let names_bytes = file.read_le_i16() as int; - let bools_bytes = file.read_le_i16() as int; - let numbers_count = file.read_le_i16() as int; - let string_offsets_count = file.read_le_i16() as int; - let string_table_bytes = file.read_le_i16() as int; + let names_bytes = file.read_le_i16_() as int; + let bools_bytes = file.read_le_i16_() as int; + let numbers_count = file.read_le_i16_() as int; + let string_offsets_count = file.read_le_i16_() as int; + let string_table_bytes = file.read_le_i16_() as int; assert!(names_bytes > 0); @@ -224,7 +226,7 @@ pub fn parse(file: @Reader, longnames: bool) -> Result<~TermInfo, ~str> { let mut bools_map = HashMap::new(); if bools_bytes != 0 { for i in range(0, bools_bytes) { - let b = file.read_byte(); + let b = file.read_byte().unwrap(); if b < 0 { error!("EOF reading bools after {} entries", i); return Err(~"error: expected more bools but hit EOF"); @@ -245,7 +247,7 @@ pub fn parse(file: @Reader, longnames: bool) -> Result<~TermInfo, ~str> { let mut numbers_map = HashMap::new(); if numbers_count != 0 { for i in range(0, numbers_count) { - let n = file.read_le_u16(); + let n = file.read_le_u16_(); if n != 0xFFFF { debug!("{}\\#{}", nnames[i], n); numbers_map.insert(nnames[i].to_owned(), n); @@ -260,7 +262,7 @@ pub fn parse(file: @Reader, longnames: bool) -> Result<~TermInfo, ~str> { if string_offsets_count != 0 { let mut string_offsets = vec::with_capacity(10); for _ in range(0, string_offsets_count) { - string_offsets.push(file.read_le_u16()); + string_offsets.push(file.read_le_u16_()); } debug!("offsets: {:?}", string_offsets); diff --git a/src/libextra/terminfo/searcher.rs b/src/libextra/terminfo/searcher.rs index ea7d20e096df4..8dff53f14a159 100644 --- a/src/libextra/terminfo/searcher.rs +++ b/src/libextra/terminfo/searcher.rs @@ -13,7 +13,8 @@ use std::{os, str}; use std::os::getenv; -use std::io::{file_reader, Reader}; +use std::rt::io; +use std::rt::io::file::FileInfo; /// Return path to database entry for `term` pub fn get_dbpath_for_term(term: &str) -> Option<~Path> { @@ -73,9 +74,9 @@ pub fn get_dbpath_for_term(term: &str) -> Option<~Path> { } /// Return open file for `term` -pub fn open(term: &str) -> Result<@Reader, ~str> { +pub fn open(term: &str) -> Result<@mut io::Reader, ~str> { match get_dbpath_for_term(term) { - Some(x) => file_reader(x), + Some(x) => Ok(@mut x.open_reader(io::Open).unwrap() as @mut io::Reader), None => Err(format!("could not find terminfo entry for {}", term)) } } diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index be118792f4987..aca41f5f4cbb9 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -28,6 +28,7 @@ use middle::astencode::vtable_decoder_helpers; use std::u64; use std::rt::io; +use std::rt::io::extensions::u64_from_be_bytes; use std::option; use std::str; use std::vec; @@ -55,14 +56,14 @@ fn lookup_hash(d: ebml::Doc, eq_fn: &fn(x:&[u8]) -> bool, hash: u64) -> let index = reader::get_doc(d, tag_index); let table = reader::get_doc(index, tag_index_table); let hash_pos = table.start + (hash % 256 * 4) as uint; - let pos = ::std::io::u64_from_be_bytes(*d.data, hash_pos, 4) as uint; + let pos = u64_from_be_bytes(*d.data, hash_pos, 4) as uint; let tagged_doc = reader::doc_at(d.data, pos); let belt = tag_index_buckets_bucket_elt; let mut ret = None; do reader::tagged_docs(tagged_doc.doc, belt) |elt| { - let pos = ::std::io::u64_from_be_bytes(*elt.data, elt.start, 4) as uint; + let pos = u64_from_be_bytes(*elt.data, elt.start, 4) as uint; if eq_fn(elt.data.slice(elt.start + 4, elt.end)) { ret = Some(reader::doc_at(d.data, pos).doc); false @@ -77,7 +78,7 @@ pub type GetCrateDataCb<'self> = &'self fn(ast::CrateNum) -> Cmd; pub fn maybe_find_item(item_id: int, items: ebml::Doc) -> Option { fn eq_item(bytes: &[u8], item_id: int) -> bool { - return ::std::io::u64_from_be_bytes( + return u64_from_be_bytes( bytes.slice(0u, 4u), 0u, 4u) as int == item_id; } @@ -1253,7 +1254,7 @@ fn family_names_type(fam: Family) -> bool { fn read_path(d: ebml::Doc) -> (~str, uint) { do reader::with_doc_data(d) |desc| { - let pos = ::std::io::u64_from_be_bytes(desc, 0u, 4u) as uint; + let pos = u64_from_be_bytes(desc, 0u, 4u) as uint; let pathbytes = desc.slice(4u, desc.len()); let path = str::from_utf8(pathbytes); diff --git a/src/libstd/io.rs b/src/libstd/io.rs deleted file mode 100644 index 2ffe654d3bdbc..0000000000000 --- a/src/libstd/io.rs +++ /dev/null @@ -1,1817 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! - -The `io` module contains basic input and output routines. - -A quick summary: - -## `Reader` and `Writer` traits - -These traits define the minimal set of methods that anything that can do -input and output should implement. - -## `ReaderUtil` and `WriterUtil` traits - -Richer methods that allow you to do more. `Reader` only lets you read a certain -number of bytes into a buffer, while `ReaderUtil` allows you to read a whole -line, for example. - -Generally, these richer methods are probably the ones you want to actually -use in day-to-day Rust. - -Furthermore, because there is an implementation of `ReaderUtil` for -``, when your input or output code implements `Reader`, you get -all of these methods for free. - -## `print` and `println` - -These very useful functions are defined here. You generally don't need to -import them, though, as the prelude already does. - -## `stdin`, `stdout`, and `stderr` - -These functions return references to the classic three file descriptors. They -implement `Reader` and `Writer`, where appropriate. - -*/ - -#[allow(missing_doc)]; - -use cast; -use cast::transmute; -use clone::Clone; -use c_str::ToCStr; -use container::Container; -use int; -use iter::Iterator; -use libc::consts::os::posix88::*; -use libc::{c_int, c_void, size_t}; -use libc; -use num; -use ops::Drop; -use option::{Some, None}; -use os; -use path::{Path,GenericPath}; -use ptr; -use result::{Result, Ok, Err}; -use str::{StrSlice, OwnedStr}; -use str; -use uint; -use vec::{MutableVector, ImmutableVector, OwnedVector, OwnedCopyableVector, CopyableVector}; -use vec; - -#[cfg(stage0)] -pub use rt::io::stdio::{print, println}; - -#[allow(non_camel_case_types)] // not sure what to do about this -type fd_t = c_int; - -mod rustrt { - use libc; - - #[link_name = "rustrt"] - extern { - pub fn rust_get_stdin() -> *libc::FILE; - pub fn rust_get_stdout() -> *libc::FILE; - pub fn rust_get_stderr() -> *libc::FILE; - } -} - -// Reading - -// FIXME (#2004): This is all buffered. We might need an unbuffered variant -// as well -/** -* The SeekStyle enum describes the relationship between the position -* we'd like to seek to from our current position. It's used as an argument -* to the `seek` method defined on the `Reader` trait. -* -* There are three seek styles: -* -* 1. `SeekSet` means that the new position should become our position. -* 2. `SeekCur` means that we should seek from the current position. -* 3. `SeekEnd` means that we should seek from the end. -* -* # Examples -* -* None right now. -*/ -pub enum SeekStyle { SeekSet, SeekEnd, SeekCur, } - - -/** -* The core Reader trait. All readers must implement this trait. -* -* # Examples -* -* None right now. -*/ -pub trait Reader { - // FIXME (#2004): Seekable really should be orthogonal. - - // FIXME (#2982): This should probably return an error. - /** - * Reads bytes and puts them into `bytes`, advancing the cursor. Returns the - * number of bytes read. - * - * The number of bytes to be read is `len` or the end of the file, - * whichever comes first. - * - * The buffer must be at least `len` bytes long. - * - * `read` is conceptually similar to C's `fread` function. - * - * # Examples - * - * None right now. - */ - fn read(&self, bytes: &mut [u8], len: uint) -> uint; - - /** - * Reads a single byte, advancing the cursor. - * - * In the case of an EOF or an error, returns a negative value. - * - * `read_byte` is conceptually similar to C's `getc` function. - * - * # Examples - * - * None right now. - */ - fn read_byte(&self) -> int; - - /** - * Returns a boolean value: are we currently at EOF? - * - * Note that stream position may be already at the end-of-file point, - * but `eof` returns false until an attempt to read at that position. - * - * `eof` is conceptually similar to C's `feof` function. - * - * # Examples - * - * None right now. - */ - fn eof(&self) -> bool; - - /** - * Seek to a given `position` in the stream. - * - * Takes an optional SeekStyle, which affects how we seek from the - * position. See `SeekStyle` docs for more details. - * - * `seek` is conceptually similar to C's `fseek` function. - * - * # Examples - * - * None right now. - */ - fn seek(&self, position: int, style: SeekStyle); - - /** - * Returns the current position within the stream. - * - * `tell` is conceptually similar to C's `ftell` function. - * - * # Examples - * - * None right now. - */ - fn tell(&self) -> uint; -} - -impl Reader for @Reader { - fn read(&self, bytes: &mut [u8], len: uint) -> uint { - self.read(bytes, len) - } - fn read_byte(&self) -> int { - self.read_byte() - } - fn eof(&self) -> bool { - self.eof() - } - fn seek(&self, position: int, style: SeekStyle) { - self.seek(position, style) - } - fn tell(&self) -> uint { - self.tell() - } -} - -/** -* The `ReaderUtil` trait is a home for many of the utility functions -* a particular Reader should implement. -* -* The default `Reader` trait is focused entirely on bytes. `ReaderUtil` is based -* on higher-level concepts like 'chars' and 'lines.' -* -* # Examples: -* -* None right now. -*/ -pub trait ReaderUtil { - - /** - * Reads `len` number of bytes, and gives you a new vector back. - * - * # Examples - * - * None right now. - */ - fn read_bytes(&self, len: uint) -> ~[u8]; - - /** - * Reads up until a specific byte is seen or EOF. - * - * The `include` parameter specifies if the character should be included - * in the returned string. - * - * # Examples - * - * None right now. - */ - fn read_until(&self, c: u8, include: bool) -> ~str; - - /** - * Reads up until the first '\n' or EOF. - * - * The '\n' is not included in the result. - * - * # Examples - * - * None right now. - */ - fn read_line(&self) -> ~str; - - /** - * Reads `n` chars. - * - * Assumes that those chars are UTF-8 encoded. - * - * The '\n' is not included in the result. - * - * # Examples - * - * None right now. - */ - fn read_chars(&self, n: uint) -> ~[char]; - - /** - * Reads a single UTF-8 encoded char. - * - * # Examples - * - * None right now. - */ - fn read_char(&self) -> char; - - /** - * Reads up until the first null byte or EOF. - * - * The null byte is not returned. - * - * # Examples - * - * None right now. - */ - fn read_c_str(&self) -> ~str; - - /** - * Reads all remaining data in the stream. - * - * # Examples - * - * None right now. - */ - fn read_whole_stream(&self) -> ~[u8]; - - /** - * Iterate over every byte until EOF or the iterator breaks. - * - * # Examples - * - * None right now. - */ - fn each_byte(&self, it: &fn(int) -> bool) -> bool; - - /** - * Iterate over every char until EOF or the iterator breaks. - * - * # Examples - * - * None right now. - */ - fn each_char(&self, it: &fn(char) -> bool) -> bool; - - /** - * Iterate over every line until EOF or the iterator breaks. - * - * # Examples - * - * None right now. - */ - fn each_line(&self, it: &fn(&str) -> bool) -> bool; - - /** - * Reads all of the lines in the stream. - * - * Returns a vector of those lines. - * - * # Examples - * - * None right now. - */ - fn read_lines(&self) -> ~[~str]; - - /** - * Reads `n` little-endian unsigned integer bytes. - * - * `n` must be between 1 and 8, inclusive. - * - * # Examples - * - * None right now. - */ - fn read_le_uint_n(&self, nbytes: uint) -> u64; - - /** - * Reads `n` little-endian signed integer bytes. - * - * `n` must be between 1 and 8, inclusive. - * - * # Examples - * - * None right now. - */ - fn read_le_int_n(&self, nbytes: uint) -> i64; - - /** - * Reads `n` big-endian unsigned integer bytes. - * - * `n` must be between 1 and 8, inclusive. - * - * # Examples - * - * None right now. - */ - fn read_be_uint_n(&self, nbytes: uint) -> u64; - - /** - * Reads `n` big-endian signed integer bytes. - * - * `n` must be between 1 and 8, inclusive. - * - * # Examples - * - * None right now. - */ - fn read_be_int_n(&self, nbytes: uint) -> i64; - - /** - * Reads a little-endian unsigned integer. - * - * The number of bytes returned is system-dependant. - * - * # Examples - * - * None right now. - */ - fn read_le_uint(&self) -> uint; - - /** - * Reads a little-endian integer. - * - * The number of bytes returned is system-dependant. - * - * # Examples - * - * None right now. - */ - fn read_le_int(&self) -> int; - - /** - * Reads a big-endian unsigned integer. - * - * The number of bytes returned is system-dependant. - * - * # Examples - * - * None right now. - */ - fn read_be_uint(&self) -> uint; - - /** - * Reads a big-endian integer. - * - * The number of bytes returned is system-dependant. - * - * # Examples - * - * None right now. - */ - fn read_be_int(&self) -> int; - - /** - * Reads a big-endian `u64`. - * - * `u64`s are 8 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_be_u64(&self) -> u64; - - /** - * Reads a big-endian `u32`. - * - * `u32`s are 4 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_be_u32(&self) -> u32; - - /** - * Reads a big-endian `u16`. - * - * `u16`s are 2 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_be_u16(&self) -> u16; - - /** - * Reads a big-endian `i64`. - * - * `i64`s are 8 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_be_i64(&self) -> i64; - - /** - * Reads a big-endian `i32`. - * - * `i32`s are 4 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_be_i32(&self) -> i32; - - /** - * Reads a big-endian `i16`. - * - * `i16`s are 2 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_be_i16(&self) -> i16; - - /** - * Reads a big-endian `f64`. - * - * `f64`s are 8 byte, IEEE754 double-precision floating point numbers. - * - * # Examples - * - * None right now. - */ - fn read_be_f64(&self) -> f64; - - /** - * Reads a big-endian `f32`. - * - * `f32`s are 4 byte, IEEE754 single-precision floating point numbers. - * - * # Examples - * - * None right now. - */ - fn read_be_f32(&self) -> f32; - - /** - * Reads a little-endian `u64`. - * - * `u64`s are 8 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_le_u64(&self) -> u64; - - /** - * Reads a little-endian `u32`. - * - * `u32`s are 4 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_le_u32(&self) -> u32; - - /** - * Reads a little-endian `u16`. - * - * `u16`s are 2 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_le_u16(&self) -> u16; - - /** - * Reads a little-endian `i64`. - * - * `i64`s are 8 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_le_i64(&self) -> i64; - - /** - * Reads a little-endian `i32`. - * - * `i32`s are 4 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_le_i32(&self) -> i32; - - /** - * Reads a little-endian `i16`. - * - * `i16`s are 2 bytes long. - * - * # Examples - * - * None right now. - */ - fn read_le_i16(&self) -> i16; - - /** - * Reads a little-endian `f64`. - * - * `f64`s are 8 byte, IEEE754 double-precision floating point numbers. - * - * # Examples - * - * None right now. - */ - fn read_le_f64(&self) -> f64; - - /** - * Reads a little-endian `f32`. - * - * `f32`s are 4 byte, IEEE754 single-precision floating point numbers. - * - * # Examples - * - * None right now. - */ - fn read_le_f32(&self) -> f32; - - /** - * Read a u8. - * - * `u8`s are 1 byte. - * - * # Examples - * - * None right now. - */ - fn read_u8(&self) -> u8; - - /** - * Read an i8. - * - * `i8`s are 1 byte. - * - * # Examples - * - * None right now. - */ - fn read_i8(&self) -> i8; -} - -impl ReaderUtil for T { - - fn read_bytes(&self, len: uint) -> ~[u8] { - let mut bytes = vec::with_capacity(len); - unsafe { vec::raw::set_len(&mut bytes, len); } - - let count = self.read(bytes, len); - - unsafe { vec::raw::set_len(&mut bytes, count); } - bytes - } - - fn read_until(&self, c: u8, include: bool) -> ~str { - let mut bytes = ~[]; - loop { - let ch = self.read_byte(); - if ch == -1 || ch == c as int { - if include && ch == c as int { - bytes.push(ch as u8); - } - break; - } - bytes.push(ch as u8); - } - str::from_utf8(bytes) - } - - fn read_line(&self) -> ~str { - self.read_until('\n' as u8, false) - } - - fn read_chars(&self, n: uint) -> ~[char] { - // returns the (consumed offset, n_req), appends characters to &chars - fn chars_from_utf8(bytes: &~[u8], chars: &mut ~[char]) - -> (uint, uint) { - let mut i = 0; - let bytes_len = bytes.len(); - while i < bytes_len { - let b0 = bytes[i]; - let w = str::utf8_char_width(b0); - let end = i + w; - i += 1; - assert!((w > 0)); - if w == 1 { - unsafe { - chars.push(transmute(b0 as u32)); - } - continue; - } - // can't satisfy this char with the existing data - if end > bytes_len { - return (i - 1, end - bytes_len); - } - let mut val = 0; - while i < end { - let next = bytes[i] as int; - i += 1; - assert!((next > -1)); - assert_eq!(next & 192, 128); - val <<= 6; - val += (next & 63) as uint; - } - // See str::StrSlice::char_at - val += ((b0 << ((w + 1) as u8)) as uint) - << (w - 1) * 6 - w - 1u; - unsafe { - chars.push(transmute(val as u32)); - } - } - return (i, 0); - } - let mut bytes = ~[]; - let mut chars = ~[]; - // might need more bytes, but reading n will never over-read - let mut nbread = n; - while nbread > 0 { - let data = self.read_bytes(nbread); - if data.is_empty() { - // eof - FIXME (#2004): should we do something if - // we're split in a unicode char? - break; - } - bytes.push_all(data); - let (offset, nbreq) = chars_from_utf8::(&bytes, &mut chars); - let ncreq = n - chars.len(); - // again we either know we need a certain number of bytes - // to complete a character, or we make sure we don't - // over-read by reading 1-byte per char needed - nbread = if ncreq > nbreq { ncreq } else { nbreq }; - if nbread > 0 { - bytes = bytes.slice(offset, bytes.len()).to_owned(); - } - } - chars - } - - fn read_char(&self) -> char { - let c = self.read_chars(1); - if c.len() == 0 { - return unsafe { transmute(-1u32) }; // FIXME: #8971: unsound - } - assert_eq!(c.len(), 1); - return c[0]; - } - - fn read_c_str(&self) -> ~str { - self.read_until(0u8, false) - } - - fn read_whole_stream(&self) -> ~[u8] { - let mut bytes: ~[u8] = ~[]; - while !self.eof() { bytes.push_all(self.read_bytes(2048u)); } - bytes - } - - fn each_byte(&self, it: &fn(int) -> bool) -> bool { - loop { - match self.read_byte() { - -1 => break, - ch => if !it(ch) { return false; } - } - } - return true; - } - - fn each_char(&self, it: &fn(char) -> bool) -> bool { - // FIXME: #8971: unsound - let eof: char = unsafe { transmute(-1u32) }; - loop { - match self.read_char() { - c if c == eof => break, - ch => if !it(ch) { return false; } - } - } - return true; - } - - fn each_line(&self, it: &fn(s: &str) -> bool) -> bool { - while !self.eof() { - // include the \n, so that we can distinguish an entirely empty - // line read after "...\n", and the trailing empty line in - // "...\n\n". - let mut line = self.read_until('\n' as u8, true); - - // blank line at the end of the reader is ignored - if self.eof() && line.is_empty() { break; } - - // trim the \n, so that each_line is consistent with read_line - let n = line.len(); - if line[n-1] == '\n' as u8 { - unsafe { str::raw::set_len(&mut line, n-1); } - } - - if !it(line) { return false; } - } - return true; - } - - fn read_lines(&self) -> ~[~str] { - do vec::build(None) |push| { - do self.each_line |line| { - push(line.to_owned()); - true - }; - } - } - - // FIXME int reading methods need to deal with eof - issue #2004 - - fn read_le_uint_n(&self, nbytes: uint) -> u64 { - assert!(nbytes > 0 && nbytes <= 8); - - let mut val = 0u64; - let mut pos = 0; - let mut i = nbytes; - while i > 0 { - val += (self.read_u8() as u64) << pos; - pos += 8; - i -= 1; - } - val - } - - fn read_le_int_n(&self, nbytes: uint) -> i64 { - extend_sign(self.read_le_uint_n(nbytes), nbytes) - } - - fn read_be_uint_n(&self, nbytes: uint) -> u64 { - assert!(nbytes > 0 && nbytes <= 8); - - let mut val = 0u64; - let mut i = nbytes; - while i > 0 { - i -= 1; - val += (self.read_u8() as u64) << i * 8; - } - val - } - - fn read_be_int_n(&self, nbytes: uint) -> i64 { - extend_sign(self.read_be_uint_n(nbytes), nbytes) - } - - fn read_le_uint(&self) -> uint { - self.read_le_uint_n(uint::bytes) as uint - } - - fn read_le_int(&self) -> int { - self.read_le_int_n(int::bytes) as int - } - - fn read_be_uint(&self) -> uint { - self.read_be_uint_n(uint::bytes) as uint - } - - fn read_be_int(&self) -> int { - self.read_be_int_n(int::bytes) as int - } - - fn read_be_u64(&self) -> u64 { - self.read_be_uint_n(8) as u64 - } - - fn read_be_u32(&self) -> u32 { - self.read_be_uint_n(4) as u32 - } - - fn read_be_u16(&self) -> u16 { - self.read_be_uint_n(2) as u16 - } - - fn read_be_i64(&self) -> i64 { - self.read_be_int_n(8) as i64 - } - - fn read_be_i32(&self) -> i32 { - self.read_be_int_n(4) as i32 - } - - fn read_be_i16(&self) -> i16 { - self.read_be_int_n(2) as i16 - } - - fn read_be_f64(&self) -> f64 { - unsafe { - cast::transmute::(self.read_be_u64()) - } - } - - fn read_be_f32(&self) -> f32 { - unsafe { - cast::transmute::(self.read_be_u32()) - } - } - - fn read_le_u64(&self) -> u64 { - self.read_le_uint_n(8) as u64 - } - - fn read_le_u32(&self) -> u32 { - self.read_le_uint_n(4) as u32 - } - - fn read_le_u16(&self) -> u16 { - self.read_le_uint_n(2) as u16 - } - - fn read_le_i64(&self) -> i64 { - self.read_le_int_n(8) as i64 - } - - fn read_le_i32(&self) -> i32 { - self.read_le_int_n(4) as i32 - } - - fn read_le_i16(&self) -> i16 { - self.read_le_int_n(2) as i16 - } - - fn read_le_f64(&self) -> f64 { - unsafe { - cast::transmute::(self.read_le_u64()) - } - } - - fn read_le_f32(&self) -> f32 { - unsafe { - cast::transmute::(self.read_le_u32()) - } - } - - fn read_u8(&self) -> u8 { - self.read_byte() as u8 - } - - fn read_i8(&self) -> i8 { - self.read_byte() as i8 - } -} - -fn extend_sign(val: u64, nbytes: uint) -> i64 { - let shift = (8 - nbytes) * 8; - (val << shift) as i64 >> shift -} - -// Reader implementations - -fn convert_whence(whence: SeekStyle) -> i32 { - return match whence { - SeekSet => 0i32, - SeekCur => 1i32, - SeekEnd => 2i32 - }; -} - -impl Reader for *libc::FILE { - fn read(&self, bytes: &mut [u8], len: uint) -> uint { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - do bytes.as_mut_buf |buf_p, buf_len| { - assert!(buf_len >= len); - - let count = libc::fread(buf_p as *mut c_void, 1u as size_t, - len as size_t, *self) as uint; - if count < len { - match libc::ferror(*self) { - 0 => (), - _ => { - error!("error reading buffer: {}", os::last_os_error()); - fail!(); - } - } - } - - count - } - } - } - fn read_byte(&self) -> int { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - libc::fgetc(*self) as int - } - } - fn eof(&self) -> bool { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - return libc::feof(*self) != 0 as c_int; - } - } - fn seek(&self, offset: int, whence: SeekStyle) { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - assert!(libc::fseek(*self, - offset as libc::c_long, - convert_whence(whence)) == 0 as c_int); - } - } - fn tell(&self) -> uint { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - return libc::ftell(*self) as uint; - } - } -} - -struct Wrapper { - base: T, - cleanup: C, -} - -// A forwarding impl of reader that also holds on to a resource for the -// duration of its lifetime. -// FIXME there really should be a better way to do this // #2004 -impl Reader for Wrapper { - fn read(&self, bytes: &mut [u8], len: uint) -> uint { - self.base.read(bytes, len) - } - fn read_byte(&self) -> int { self.base.read_byte() } - fn eof(&self) -> bool { self.base.eof() } - fn seek(&self, off: int, whence: SeekStyle) { - self.base.seek(off, whence) - } - fn tell(&self) -> uint { self.base.tell() } -} - -pub struct FILERes { - priv f: *libc::FILE, -} - -impl FILERes { - fn new(f: *libc::FILE) -> FILERes { - FILERes { f: f } - } -} - -impl Drop for FILERes { - fn drop(&mut self) { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - libc::fclose(self.f); - } - } -} - -pub fn file_reader(path: &Path) -> Result<@Reader, ~str> { - #[fixed_stack_segment]; #[inline(never)]; - - let f = do path.with_c_str |pathbuf| { - do "rb".with_c_str |modebuf| { - unsafe { libc::fopen(pathbuf, modebuf as *libc::c_char) } - } - }; - - if f as uint == 0u { - do path.display().with_str |p| { - Err(~"error opening " + p) - } - } else { - Ok(@Wrapper { base: f, cleanup: FILERes::new(f) } as @Reader) - } -} - -// Writing -pub enum FileFlag { Append, Create, Truncate, NoFlag, } - -// What type of writer are we? -#[deriving(Eq)] -pub enum WriterType { Screen, File } - -// FIXME (#2004): Seekable really should be orthogonal. -// FIXME (#2004): eventually u64 -/// The raw underlying writer trait. All writers must implement this. -pub trait Writer { - - /// Write all of the given bytes. - fn write(&self, v: &[u8]); - - /// Move the current position within the stream. The second parameter - /// determines the position that the first parameter is relative to. - fn seek(&self, int, SeekStyle); - - /// Return the current position within the stream. - fn tell(&self) -> uint; - - /// Flush the output buffer for this stream (if there is one). - fn flush(&self) -> int; - - /// Determine if this Writer is writing to a file or not. - fn get_type(&self) -> WriterType; -} - -impl Writer for @Writer { - fn write(&self, v: &[u8]) { self.write(v) } - fn seek(&self, a: int, b: SeekStyle) { self.seek(a, b) } - fn tell(&self) -> uint { self.tell() } - fn flush(&self) -> int { self.flush() } - fn get_type(&self) -> WriterType { self.get_type() } -} - -impl Writer for Wrapper { - fn write(&self, bs: &[u8]) { self.base.write(bs); } - fn seek(&self, off: int, style: SeekStyle) { self.base.seek(off, style); } - fn tell(&self) -> uint { self.base.tell() } - fn flush(&self) -> int { self.base.flush() } - fn get_type(&self) -> WriterType { File } -} - -impl Writer for *libc::FILE { - fn write(&self, v: &[u8]) { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - do v.as_imm_buf |vbuf, len| { - let nout = libc::fwrite(vbuf as *c_void, - 1, - len as size_t, - *self); - if nout != len as size_t { - error!("error writing buffer: {}", os::last_os_error()); - fail!(); - } - } - } - } - fn seek(&self, offset: int, whence: SeekStyle) { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - assert!(libc::fseek(*self, - offset as libc::c_long, - convert_whence(whence)) == 0 as c_int); - } - } - fn tell(&self) -> uint { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - libc::ftell(*self) as uint - } - } - fn flush(&self) -> int { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - libc::fflush(*self) as int - } - } - fn get_type(&self) -> WriterType { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - let fd = libc::fileno(*self); - if libc::isatty(fd) == 0 { File } - else { Screen } - } - } -} - -impl Writer for fd_t { - fn write(&self, v: &[u8]) { - #[fixed_stack_segment]; #[inline(never)]; - - #[cfg(windows)] - type IoSize = libc::c_uint; - #[cfg(windows)] - type IoRet = c_int; - - #[cfg(unix)] - type IoSize = size_t; - #[cfg(unix)] - type IoRet = libc::ssize_t; - - unsafe { - let mut count = 0u; - do v.as_imm_buf |vbuf, len| { - while count < len { - let vb = ptr::offset(vbuf, count as int) as *c_void; - let nout = libc::write(*self, vb, len as IoSize); - if nout < 0 as IoRet { - error!("error writing buffer: {}", os::last_os_error()); - fail!(); - } - count += nout as uint; - } - } - } - } - fn seek(&self, _offset: int, _whence: SeekStyle) { - error!("need 64-bit foreign calls for seek, sorry"); - fail!(); - } - fn tell(&self) -> uint { - error!("need 64-bit foreign calls for tell, sorry"); - fail!(); - } - fn flush(&self) -> int { 0 } - fn get_type(&self) -> WriterType { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - if libc::isatty(*self) == 0 { File } else { Screen } - } - } -} - -pub struct FdRes { - priv fd: fd_t, -} - -impl FdRes { - fn new(fd: fd_t) -> FdRes { - FdRes { fd: fd } - } -} - -impl Drop for FdRes { - fn drop(&mut self) { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - libc::close(self.fd); - } - } -} - -pub fn mk_file_writer(path: &Path, flags: &[FileFlag]) - -> Result<@Writer, ~str> { - #[fixed_stack_segment]; #[inline(never)]; - - #[cfg(windows)] - fn wb() -> c_int { - (O_WRONLY | libc::consts::os::extra::O_BINARY) as c_int - } - - #[cfg(unix)] - fn wb() -> c_int { O_WRONLY as c_int } - - let mut fflags: c_int = wb(); - for f in flags.iter() { - match *f { - Append => fflags |= O_APPEND as c_int, - Create => fflags |= O_CREAT as c_int, - Truncate => fflags |= O_TRUNC as c_int, - NoFlag => () - } - } - let fd = unsafe { - do path.with_c_str |pathbuf| { - libc::open(pathbuf, fflags, (S_IRUSR | S_IWUSR) as c_int) - } - }; - if fd < (0 as c_int) { - Err(format!("error opening {}: {}", path.display(), os::last_os_error())) - } else { - Ok(@Wrapper { base: fd, cleanup: FdRes::new(fd) } as @Writer) - } -} - -pub fn u64_to_le_bytes(n: u64, size: uint, - f: &fn(v: &[u8]) -> T) -> T { - assert!(size <= 8u); - match size { - 1u => f(&[n as u8]), - 2u => f(&[n as u8, - (n >> 8) as u8]), - 4u => f(&[n as u8, - (n >> 8) as u8, - (n >> 16) as u8, - (n >> 24) as u8]), - 8u => f(&[n as u8, - (n >> 8) as u8, - (n >> 16) as u8, - (n >> 24) as u8, - (n >> 32) as u8, - (n >> 40) as u8, - (n >> 48) as u8, - (n >> 56) as u8]), - _ => { - - let mut bytes: ~[u8] = ~[]; - let mut i = size; - let mut n = n; - while i > 0u { - bytes.push((n & 255_u64) as u8); - n >>= 8_u64; - i -= 1u; - } - f(bytes) - } - } -} - -pub fn u64_to_be_bytes(n: u64, size: uint, - f: &fn(v: &[u8]) -> T) -> T { - assert!(size <= 8u); - match size { - 1u => f(&[n as u8]), - 2u => f(&[(n >> 8) as u8, - n as u8]), - 4u => f(&[(n >> 24) as u8, - (n >> 16) as u8, - (n >> 8) as u8, - n as u8]), - 8u => f(&[(n >> 56) as u8, - (n >> 48) as u8, - (n >> 40) as u8, - (n >> 32) as u8, - (n >> 24) as u8, - (n >> 16) as u8, - (n >> 8) as u8, - n as u8]), - _ => { - let mut bytes: ~[u8] = ~[]; - let mut i = size; - while i > 0u { - let shift = ((i - 1u) * 8u) as u64; - bytes.push((n >> shift) as u8); - i -= 1u; - } - f(bytes) - } - } -} - -pub fn u64_from_be_bytes(data: &[u8], - start: uint, - size: uint) - -> u64 { - let mut sz = size; - assert!((sz <= 8u)); - let mut val = 0_u64; - let mut pos = start; - while sz > 0u { - sz -= 1u; - val += (data[pos] as u64) << ((sz * 8u) as u64); - pos += 1u; - } - return val; -} - -// FIXME: #3048 combine trait+impl (or just move these to -// default methods on writer) -/// Generic utility functions defined on writers. -pub trait WriterUtil { - - /// Write a single utf-8 encoded char. - fn write_char(&self, ch: char); - - /// Write every char in the given str, encoded as utf-8. - fn write_str(&self, s: &str); - - /// Write the given str, as utf-8, followed by '\n'. - fn write_line(&self, s: &str); - - /// Write the result of passing n through `int::to_str_bytes`. - fn write_int(&self, n: int); - - /// Write the result of passing n through `uint::to_str_bytes`. - fn write_uint(&self, n: uint); - - /// Write a little-endian uint (number of bytes depends on system). - fn write_le_uint(&self, n: uint); - - /// Write a little-endian int (number of bytes depends on system). - fn write_le_int(&self, n: int); - - /// Write a big-endian uint (number of bytes depends on system). - fn write_be_uint(&self, n: uint); - - /// Write a big-endian int (number of bytes depends on system). - fn write_be_int(&self, n: int); - - /// Write a big-endian u64 (8 bytes). - fn write_be_u64(&self, n: u64); - - /// Write a big-endian u32 (4 bytes). - fn write_be_u32(&self, n: u32); - - /// Write a big-endian u16 (2 bytes). - fn write_be_u16(&self, n: u16); - - /// Write a big-endian i64 (8 bytes). - fn write_be_i64(&self, n: i64); - - /// Write a big-endian i32 (4 bytes). - fn write_be_i32(&self, n: i32); - - /// Write a big-endian i16 (2 bytes). - fn write_be_i16(&self, n: i16); - - /// Write a big-endian IEEE754 double-precision floating-point (8 bytes). - fn write_be_f64(&self, f: f64); - - /// Write a big-endian IEEE754 single-precision floating-point (4 bytes). - fn write_be_f32(&self, f: f32); - - /// Write a little-endian u64 (8 bytes). - fn write_le_u64(&self, n: u64); - - /// Write a little-endian u32 (4 bytes). - fn write_le_u32(&self, n: u32); - - /// Write a little-endian u16 (2 bytes). - fn write_le_u16(&self, n: u16); - - /// Write a little-endian i64 (8 bytes). - fn write_le_i64(&self, n: i64); - - /// Write a little-endian i32 (4 bytes). - fn write_le_i32(&self, n: i32); - - /// Write a little-endian i16 (2 bytes). - fn write_le_i16(&self, n: i16); - - /// Write a little-endian IEEE754 double-precision floating-point - /// (8 bytes). - fn write_le_f64(&self, f: f64); - - /// Write a little-endian IEEE754 single-precision floating-point - /// (4 bytes). - fn write_le_f32(&self, f: f32); - - /// Write a u8 (1 byte). - fn write_u8(&self, n: u8); - - /// Write a i8 (1 byte). - fn write_i8(&self, n: i8); -} - -impl WriterUtil for T { - fn write_char(&self, ch: char) { - if (ch as uint) < 128u { - self.write(&[ch as u8]); - } else { - self.write_str(str::from_char(ch)); - } - } - fn write_str(&self, s: &str) { self.write(s.as_bytes()) } - fn write_line(&self, s: &str) { - self.write_str(s); - self.write_str(&"\n"); - } - fn write_int(&self, n: int) { - int::to_str_bytes(n, 10u, |bytes| self.write(bytes)) - } - fn write_uint(&self, n: uint) { - uint::to_str_bytes(n, 10u, |bytes| self.write(bytes)) - } - fn write_le_uint(&self, n: uint) { - u64_to_le_bytes(n as u64, uint::bytes, |v| self.write(v)) - } - fn write_le_int(&self, n: int) { - u64_to_le_bytes(n as u64, int::bytes, |v| self.write(v)) - } - fn write_be_uint(&self, n: uint) { - u64_to_be_bytes(n as u64, uint::bytes, |v| self.write(v)) - } - fn write_be_int(&self, n: int) { - u64_to_be_bytes(n as u64, int::bytes, |v| self.write(v)) - } - fn write_be_u64(&self, n: u64) { - u64_to_be_bytes(n, 8u, |v| self.write(v)) - } - fn write_be_u32(&self, n: u32) { - u64_to_be_bytes(n as u64, 4u, |v| self.write(v)) - } - fn write_be_u16(&self, n: u16) { - u64_to_be_bytes(n as u64, 2u, |v| self.write(v)) - } - fn write_be_i64(&self, n: i64) { - u64_to_be_bytes(n as u64, 8u, |v| self.write(v)) - } - fn write_be_i32(&self, n: i32) { - u64_to_be_bytes(n as u64, 4u, |v| self.write(v)) - } - fn write_be_i16(&self, n: i16) { - u64_to_be_bytes(n as u64, 2u, |v| self.write(v)) - } - fn write_be_f64(&self, f:f64) { - unsafe { - self.write_be_u64(cast::transmute(f)) - } - } - fn write_be_f32(&self, f:f32) { - unsafe { - self.write_be_u32(cast::transmute(f)) - } - } - fn write_le_u64(&self, n: u64) { - u64_to_le_bytes(n, 8u, |v| self.write(v)) - } - fn write_le_u32(&self, n: u32) { - u64_to_le_bytes(n as u64, 4u, |v| self.write(v)) - } - fn write_le_u16(&self, n: u16) { - u64_to_le_bytes(n as u64, 2u, |v| self.write(v)) - } - fn write_le_i64(&self, n: i64) { - u64_to_le_bytes(n as u64, 8u, |v| self.write(v)) - } - fn write_le_i32(&self, n: i32) { - u64_to_le_bytes(n as u64, 4u, |v| self.write(v)) - } - fn write_le_i16(&self, n: i16) { - u64_to_le_bytes(n as u64, 2u, |v| self.write(v)) - } - fn write_le_f64(&self, f:f64) { - unsafe { - self.write_le_u64(cast::transmute(f)) - } - } - fn write_le_f32(&self, f:f32) { - unsafe { - self.write_le_u32(cast::transmute(f)) - } - } - - fn write_u8(&self, n: u8) { self.write([n]) } - fn write_i8(&self, n: i8) { self.write([n as u8]) } - -} - -pub fn file_writer(path: &Path, flags: &[FileFlag]) -> Result<@Writer, ~str> { - mk_file_writer(path, flags).and_then(|w| Ok(w)) -} - -// FIXME (#2004) it would be great if this could be a const -// FIXME (#2004) why are these different from the way stdin() is -// implemented? - -pub struct BytesWriter { - bytes: @mut ~[u8], - pos: @mut uint, -} - -impl BytesWriter { - pub fn new() -> BytesWriter { - BytesWriter { - bytes: @mut ~[], - pos: @mut 0 - } - } -} - -impl Writer for BytesWriter { - fn write(&self, v: &[u8]) { - let v_len = v.len(); - - let bytes = &mut *self.bytes; - let count = num::max(bytes.len(), *self.pos + v_len); - bytes.reserve(count); - - unsafe { - vec::raw::set_len(bytes, count); - - let view = bytes.mut_slice(*self.pos, count); - vec::bytes::copy_memory(view, v, v_len); - } - - *self.pos += v_len; - } - - fn seek(&self, offset: int, whence: SeekStyle) { - let pos = *self.pos; - let len = self.bytes.len(); - *self.pos = seek_in_buf(offset, pos, len, whence); - } - - fn tell(&self) -> uint { - *self.pos - } - - fn flush(&self) -> int { - 0 - } - - fn get_type(&self) -> WriterType { - File - } -} - -pub fn with_bytes_writer(f: &fn(@Writer)) -> ~[u8] { - let wr = @BytesWriter::new(); - f(wr as @Writer); - let @BytesWriter { bytes, _ } = wr; - (*bytes).clone() -} - -pub fn with_str_writer(f: &fn(@Writer)) -> ~str { - str::from_utf8(with_bytes_writer(f)) -} - -// Utility functions -fn seek_in_buf(offset: int, pos: uint, len: uint, whence: SeekStyle) -> - uint { - let mut bpos = pos as int; - let blen = len as int; - match whence { - SeekSet => bpos = offset, - SeekCur => bpos += offset, - SeekEnd => bpos = blen + offset - } - if bpos < 0 { bpos = 0; } else if bpos > blen { bpos = blen; } - return bpos as uint; -} - -#[cfg(test)] -mod tests { - use prelude::*; - use i32; - use io::{BytesWriter, SeekCur, SeekEnd, SeekSet}; - use io; - use path::Path; - use result::{Ok, Err}; - use u64; - use vec; - use cast::transmute; - - #[test] - fn test_simple() { - let tmpfile = &Path::new("tmp/lib-io-test-simple.tmp"); - debug!("{}", tmpfile.display()); - let frood: ~str = - ~"A hoopy frood who really knows where his towel is."; - debug!("{}", frood.clone()); - { - let out = io::file_writer(tmpfile, [io::Create, io::Truncate]).unwrap(); - out.write_str(frood); - } - let inp = io::file_reader(tmpfile).unwrap(); - let frood2: ~str = inp.read_c_str(); - debug!("{}", frood2.clone()); - assert_eq!(frood, frood2); - } - - #[test] - fn test_each_byte_each_char_file() { - // Issue #5056 -- shouldn't include trailing EOF. - let path = Path::new("tmp/lib-io-test-each-byte-each-char-file.tmp"); - - { - // create empty, enough to reproduce a problem - io::file_writer(&path, [io::Create]).unwrap(); - } - - { - let file = io::file_reader(&path).unwrap(); - do file.each_byte() |_| { - fail!("must be empty") - }; - } - - { - let file = io::file_reader(&path).unwrap(); - do file.each_char() |_| { - fail!("must be empty") - }; - } - } - - #[test] - fn file_reader_not_exist() { - match io::file_reader(&Path::new("not a file")) { - Err(e) => { - assert_eq!(e, ~"error opening not a file"); - } - Ok(_) => fail!() - } - } - - #[test] - #[should_fail] - fn test_read_buffer_too_small() { - let path = &Path::new("tmp/lib-io-test-read-buffer-too-small.tmp"); - // ensure the file exists - io::file_writer(path, [io::Create]).unwrap(); - - let file = io::file_reader(path).unwrap(); - let mut buf = vec::from_elem(5, 0u8); - file.read(buf, 6); // this should fail because buf is too small - } - - #[test] - fn test_read_buffer_big_enough() { - let path = &Path::new("tmp/lib-io-test-read-buffer-big-enough.tmp"); - // ensure the file exists - io::file_writer(path, [io::Create]).unwrap(); - - let file = io::file_reader(path).unwrap(); - let mut buf = vec::from_elem(5, 0u8); - file.read(buf, 4); // this should succeed because buf is big enough - } - - #[test] - fn test_write_empty() { - let file = io::file_writer(&Path::new("tmp/lib-io-test-write-empty.tmp"), - [io::Create]).unwrap(); - file.write([]); - } - - #[test] - fn file_writer_bad_name() { - match io::file_writer(&Path::new("?/?"), []) { - Err(e) => { - assert!(e.starts_with("error opening")); - } - Ok(_) => fail!() - } - } - - #[test] - fn bytes_buffer_overwrite() { - let wr = BytesWriter::new(); - wr.write([0u8, 1u8, 2u8, 3u8]); - assert!(*wr.bytes == ~[0u8, 1u8, 2u8, 3u8]); - wr.seek(-2, SeekCur); - wr.write([4u8, 5u8, 6u8, 7u8]); - assert!(*wr.bytes == ~[0u8, 1u8, 4u8, 5u8, 6u8, 7u8]); - wr.seek(-2, SeekEnd); - wr.write([8u8]); - wr.seek(1, SeekSet); - wr.write([9u8]); - assert!(*wr.bytes == ~[0u8, 9u8, 4u8, 5u8, 8u8, 7u8]); - } - - #[test] - fn test_read_write_le() { - let path = Path::new("tmp/lib-io-test-read-write-le.tmp"); - let uints = [0, 1, 2, 42, 10_123, 100_123_456, u64::max_value]; - - // write the ints to the file - { - let file = io::file_writer(&path, [io::Create]).unwrap(); - for i in uints.iter() { - file.write_le_u64(*i); - } - } - - // then read them back and check that they are the same - { - let file = io::file_reader(&path).unwrap(); - for i in uints.iter() { - assert_eq!(file.read_le_u64(), *i); - } - } - } - - #[test] - fn test_read_write_be() { - let path = Path::new("tmp/lib-io-test-read-write-be.tmp"); - let uints = [0, 1, 2, 42, 10_123, 100_123_456, u64::max_value]; - - // write the ints to the file - { - let file = io::file_writer(&path, [io::Create]).unwrap(); - for i in uints.iter() { - file.write_be_u64(*i); - } - } - - // then read them back and check that they are the same - { - let file = io::file_reader(&path).unwrap(); - for i in uints.iter() { - assert_eq!(file.read_be_u64(), *i); - } - } - } - - #[test] - fn test_read_be_int_n() { - let path = Path::new("tmp/lib-io-test-read-be-int-n.tmp"); - let ints = [i32::min_value, -123456, -42, -5, 0, 1, i32::max_value]; - - // write the ints to the file - { - let file = io::file_writer(&path, [io::Create]).unwrap(); - for i in ints.iter() { - file.write_be_i32(*i); - } - } - - // then read them back and check that they are the same - { - let file = io::file_reader(&path).unwrap(); - for i in ints.iter() { - // this tests that the sign extension is working - // (comparing the values as i32 would not test this) - assert_eq!(file.read_be_int_n(4), *i as i64); - } - } - } - - #[test] - fn test_read_f32() { - let path = Path::new("tmp/lib-io-test-read-f32.tmp"); - //big-endian floating-point 8.1250 - let buf = ~[0x41, 0x02, 0x00, 0x00]; - - { - let file = io::file_writer(&path, [io::Create]).unwrap(); - file.write(buf); - } - - { - let file = io::file_reader(&path).unwrap(); - let f = file.read_be_f32(); - assert_eq!(f, 8.1250); - } - } - - #[test] - fn test_read_write_f32() { - let path = Path::new("tmp/lib-io-test-read-write-f32.tmp"); - let f:f32 = 8.1250; - - { - let file = io::file_writer(&path, [io::Create]).unwrap(); - file.write_be_f32(f); - file.write_le_f32(f); - } - - { - let file = io::file_reader(&path).unwrap(); - assert_eq!(file.read_be_f32(), 8.1250); - assert_eq!(file.read_le_f32(), 8.1250); - } - } -} diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index 886ad9995a150..bb8e6674b464b 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -53,7 +53,6 @@ pub use container::{Container, Mutable, Map, MutableMap, Set, MutableSet}; pub use default::Default; pub use from_str::FromStr; pub use hash::Hash; -pub use io::{Reader, ReaderUtil, Writer, WriterUtil}; pub use iter::{FromIterator, Extendable}; pub use iter::{Iterator, DoubleEndedIterator, RandomAccessIterator, ClonableIterator}; pub use iter::{OrdIterator, MutableDoubleEndedIterator, ExactSize}; diff --git a/src/libstd/rt/io/extensions.rs b/src/libstd/rt/io/extensions.rs index c77e3b9160990..4b16f0bc0e183 100644 --- a/src/libstd/rt/io/extensions.rs +++ b/src/libstd/rt/io/extensions.rs @@ -22,7 +22,6 @@ use rt::io::{io_error, standard_error, EndOfFile, DEFAULT_BUF_SIZE}; use option::{Option, Some, None}; use unstable::finally::Finally; use cast; -use io::{u64_to_le_bytes, u64_to_be_bytes}; pub trait ReaderUtil { @@ -634,6 +633,88 @@ fn extend_sign(val: u64, nbytes: uint) -> i64 { (val << shift) as i64 >> shift } +pub fn u64_to_le_bytes(n: u64, size: uint, + f: &fn(v: &[u8]) -> T) -> T { + assert!(size <= 8u); + match size { + 1u => f(&[n as u8]), + 2u => f(&[n as u8, + (n >> 8) as u8]), + 4u => f(&[n as u8, + (n >> 8) as u8, + (n >> 16) as u8, + (n >> 24) as u8]), + 8u => f(&[n as u8, + (n >> 8) as u8, + (n >> 16) as u8, + (n >> 24) as u8, + (n >> 32) as u8, + (n >> 40) as u8, + (n >> 48) as u8, + (n >> 56) as u8]), + _ => { + + let mut bytes: ~[u8] = ~[]; + let mut i = size; + let mut n = n; + while i > 0u { + bytes.push((n & 255_u64) as u8); + n >>= 8_u64; + i -= 1u; + } + f(bytes) + } + } +} + +pub fn u64_to_be_bytes(n: u64, size: uint, + f: &fn(v: &[u8]) -> T) -> T { + assert!(size <= 8u); + match size { + 1u => f(&[n as u8]), + 2u => f(&[(n >> 8) as u8, + n as u8]), + 4u => f(&[(n >> 24) as u8, + (n >> 16) as u8, + (n >> 8) as u8, + n as u8]), + 8u => f(&[(n >> 56) as u8, + (n >> 48) as u8, + (n >> 40) as u8, + (n >> 32) as u8, + (n >> 24) as u8, + (n >> 16) as u8, + (n >> 8) as u8, + n as u8]), + _ => { + let mut bytes: ~[u8] = ~[]; + let mut i = size; + while i > 0u { + let shift = ((i - 1u) * 8u) as u64; + bytes.push((n >> shift) as u8); + i -= 1u; + } + f(bytes) + } + } +} + +pub fn u64_from_be_bytes(data: &[u8], + start: uint, + size: uint) + -> u64 { + let mut sz = size; + assert!((sz <= 8u)); + let mut val = 0_u64; + let mut pos = start; + while sz > 0u { + sz -= 1u; + val += (data[pos] as u64) << ((sz * 8u) as u64); + pos += 1u; + } + return val; +} + #[cfg(test)] mod test { use super::ReaderUtil; diff --git a/src/libstd/std.rs b/src/libstd/std.rs index 8c72e083f882f..12316cb5ead2a 100644 --- a/src/libstd/std.rs +++ b/src/libstd/std.rs @@ -148,7 +148,6 @@ pub mod iter; pub mod to_str; pub mod to_bytes; pub mod clone; -pub mod io; pub mod hash; pub mod container; pub mod default; diff --git a/src/libstd/to_bytes.rs b/src/libstd/to_bytes.rs index 4d5da19dafda9..8c78e34528bde 100644 --- a/src/libstd/to_bytes.rs +++ b/src/libstd/to_bytes.rs @@ -16,8 +16,6 @@ The `ToBytes` and `IterBytes` traits use cast; use container::Container; -use io; -use io::Writer; use iter::Iterator; use option::{None, Option, Some}; use str::{Str, StrSlice}; @@ -360,7 +358,10 @@ pub trait ToBytes { impl ToBytes for A { fn to_bytes(&self, lsb0: bool) -> ~[u8] { - do io::with_bytes_writer |wr| { + use rt::io::mem; + use rt::io::Writer; + + do mem::with_mem_writer |wr| { do self.iter_bytes(lsb0) |bytes| { wr.write(bytes); true diff --git a/src/test/compile-fail/borrowck-auto-mut-ref-to-immut-var.rs b/src/test/compile-fail/borrowck-auto-mut-ref-to-immut-var.rs index 76e700609291e..dcfef4e1d9c85 100644 --- a/src/test/compile-fail/borrowck-auto-mut-ref-to-immut-var.rs +++ b/src/test/compile-fail/borrowck-auto-mut-ref-to-immut-var.rs @@ -10,8 +10,6 @@ // Tests that auto-ref can't create mutable aliases to immutable memory. -use std::io; - struct Foo { x: int } diff --git a/src/test/run-pass/glob-std.rs b/src/test/run-pass/glob-std.rs index acb2dde99adf6..8cd2d9edbd7c0 100644 --- a/src/test/run-pass/glob-std.rs +++ b/src/test/run-pass/glob-std.rs @@ -15,14 +15,16 @@ extern mod extra; use extra::glob::glob; use extra::tempfile::TempDir; use std::unstable::finally::Finally; -use std::{io, os, unstable}; +use std::{os, unstable}; +use std::rt::io; +use std::rt::io::file::FileInfo; pub fn main() { fn mk_file(path: &str, directory: bool) { if directory { os::make_dir(&Path::new(path), 0xFFFF); } else { - io::mk_file_writer(&Path::new(path), [io::Create]); + Path::new(path).open_writer(io::Create); } } From 262b958a4bedf419335069c95f054a22da48a88a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 21 Oct 2013 23:44:11 -0700 Subject: [PATCH 19/23] Migrate std::run to libuv processes --- src/libstd/rt/io/process.rs | 2 +- src/libstd/rt/uv/process.rs | 11 ++++----- src/libstd/run.rs | 46 +++++++++++++++++++++++++++---------- 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/libstd/rt/io/process.rs b/src/libstd/rt/io/process.rs index a5750211b492c..ae087099d1fa5 100644 --- a/src/libstd/rt/io/process.rs +++ b/src/libstd/rt/io/process.rs @@ -57,7 +57,7 @@ pub struct ProcessConfig<'self> { /// 0 - stdin /// 1 - stdout /// 2 - stderr - io: ~[StdioContainer] + io: &'self [StdioContainer] } /// Describes what to do with a standard io stream for a child process. diff --git a/src/libstd/rt/uv/process.rs b/src/libstd/rt/uv/process.rs index a039bbc9fc029..f0d0afeb6aa40 100644 --- a/src/libstd/rt/uv/process.rs +++ b/src/libstd/rt/uv/process.rs @@ -12,7 +12,6 @@ use prelude::*; use cell::Cell; use libc; use ptr; -use util; use vec; use rt::io::process::*; @@ -42,7 +41,7 @@ impl Process { /// /// Returns either the corresponding process object or an error which /// occurred. - pub fn spawn(&mut self, loop_: &uv::Loop, mut config: ProcessConfig, + pub fn spawn(&mut self, loop_: &uv::Loop, config: ProcessConfig, exit_cb: uv::ExitCallback) -> Result<~[Option<~UvPipeStream>], uv::UvError> { @@ -62,12 +61,12 @@ impl Process { err); } - let io = util::replace(&mut config.io, ~[]); + let io = config.io; let mut stdio = vec::with_capacity::(io.len()); let mut ret_io = vec::with_capacity(io.len()); unsafe { vec::raw::set_len(&mut stdio, io.len()); - for (slot, other) in stdio.iter().zip(io.move_iter()) { + for (slot, other) in stdio.iter().zip(io.iter()) { let io = set_stdio(slot as *uvll::uv_stdio_container_t, other, loop_); ret_io.push(io); @@ -126,9 +125,9 @@ impl Process { } unsafe fn set_stdio(dst: *uvll::uv_stdio_container_t, - io: StdioContainer, + io: &StdioContainer, loop_: &uv::Loop) -> Option<~UvPipeStream> { - match io { + match *io { Ignored => { uvll::set_stdio_container_flags(dst, uvll::STDIO_IGNORE); None diff --git a/src/libstd/run.rs b/src/libstd/run.rs index d5f8e82b90fc5..40b509c4bc862 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -17,7 +17,7 @@ use comm::{stream, SharedChan}; use libc::{pid_t, c_int}; use libc; use prelude::*; -use rt::io::native::process; +use rt::io::process; use rt::io; use rt::io::extensions::ReaderUtil; use task; @@ -122,8 +122,24 @@ impl Process { */ pub fn new(prog: &str, args: &[~str], options: ProcessOptions) -> Process { let ProcessOptions { env, dir, in_fd, out_fd, err_fd } = options; - let inner = process::Process::new(prog, args, env, dir, - in_fd, out_fd, err_fd); + let env = env.as_ref().map(|a| a.as_slice()); + let cwd = dir.as_ref().map(|a| a.as_str().unwrap()); + fn rtify(fd: Option, input: bool) -> process::StdioContainer { + match fd { + Some(fd) => process::InheritFd(fd), + None => process::CreatePipe(input, !input), + } + } + let rtio = [rtify(in_fd, true), rtify(out_fd, false), + rtify(err_fd, false)]; + let rtconfig = process::ProcessConfig { + program: prog, + args: args, + env: env, + cwd: cwd, + io: rtio, + }; + let inner = process::Process::new(rtconfig).unwrap(); Process { inner: inner } } @@ -136,7 +152,9 @@ impl Process { * Fails if there is no stdin available (it's already been removed by * take_input) */ - pub fn input<'a>(&'a mut self) -> &'a mut io::Writer { self.inner.input() } + pub fn input<'a>(&'a mut self) -> &'a mut io::Writer { + self.inner.io[0].get_mut_ref() as &mut io::Writer + } /** * Returns an io::Reader that can be used to read from this Process's stdout. @@ -144,7 +162,9 @@ impl Process { * Fails if there is no stdout available (it's already been removed by * take_output) */ - pub fn output<'a>(&'a mut self) -> &'a mut io::Reader { self.inner.output() } + pub fn output<'a>(&'a mut self) -> &'a mut io::Reader { + self.inner.io[1].get_mut_ref() as &mut io::Reader + } /** * Returns an io::Reader that can be used to read from this Process's stderr. @@ -152,18 +172,20 @@ impl Process { * Fails if there is no stderr available (it's already been removed by * take_error) */ - pub fn error<'a>(&'a mut self) -> &'a mut io::Reader { self.inner.error() } + pub fn error<'a>(&'a mut self) -> &'a mut io::Reader { + self.inner.io[2].get_mut_ref() as &mut io::Reader + } /** * Closes the handle to the child process's stdin. */ pub fn close_input(&mut self) { - self.inner.take_input(); + self.inner.io[0].take(); } fn close_outputs(&mut self) { - self.inner.take_output(); - self.inner.take_error(); + self.inner.io[1].take(); + self.inner.io[2].take(); } /** @@ -186,9 +208,9 @@ impl Process { * were redirected to existing file descriptors. */ pub fn finish_with_output(&mut self) -> ProcessOutput { - self.inner.take_input(); // close stdin - let output = Cell::new(self.inner.take_output()); - let error = Cell::new(self.inner.take_error()); + self.close_input(); + let output = Cell::new(self.inner.io[1].take()); + let error = Cell::new(self.inner.io[2].take()); // Spawn two entire schedulers to read both stdout and sterr // in parallel so we don't deadlock while blocking on one From 816e46dd633cf4cc5741dde6ce3bffd4a9ba67a7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 22 Oct 2013 08:41:05 -0700 Subject: [PATCH 20/23] Fixing some tests, adding some pipes This adds constructors to pipe streams in the new runtime to take ownership of file descriptors, and also fixes a few tests relating to the std::run changes (new errors are raised on io_error and one test is xfail'd). --- src/libstd/rt/io/pipe.rs | 34 ++++++++++++++++++++++++++- src/libstd/run.rs | 9 ++++--- src/test/run-pass/core-run-destroy.rs | 5 +++- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/libstd/rt/io/pipe.rs b/src/libstd/rt/io/pipe.rs index 979a1dfc65e33..ec9a4a0101fee 100644 --- a/src/libstd/rt/io/pipe.rs +++ b/src/libstd/rt/io/pipe.rs @@ -16,13 +16,45 @@ use prelude::*; use super::{Reader, Writer}; use rt::io::{io_error, EndOfFile}; -use rt::rtio::RtioPipe; +use rt::io::native::file; +use rt::rtio::{RtioPipe, with_local_io}; pub struct PipeStream { priv obj: ~RtioPipe, } impl PipeStream { + /// Consumes a file descriptor to return a pipe stream that will have + /// synchronous, but non-blocking reads/writes. This is useful if the file + /// descriptor is acquired via means other than the standard methods. + /// + /// This operation consumes ownership of the file descriptor and it will be + /// closed once the object is deallocated. + /// + /// # Example + /// + /// use std::libc; + /// use std::rt::io::pipe; + /// + /// let mut pipe = PipeStream::open(libc::STDERR_FILENO); + /// pipe.write(bytes!("Hello, stderr!")); + /// + /// # Failure + /// + /// If the pipe cannot be created, an error will be raised on the + /// `io_error` condition. + pub fn open(fd: file::fd_t) -> Option { + do with_local_io |io| { + match io.pipe_open(fd) { + Ok(obj) => Some(PipeStream { obj: obj }), + Err(e) => { + io_error::cond.raise(e); + None + } + } + } + } + pub fn new(inner: ~RtioPipe) -> PipeStream { PipeStream { obj: inner } } diff --git a/src/libstd/run.rs b/src/libstd/run.rs index 40b509c4bc862..650ef491a3bff 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -322,6 +322,7 @@ mod tests { use path::Path; use run; use str; + use task::spawn; use unstable::running_on_valgrind; use rt::io::native::file; use rt::io::{Writer, Reader}; @@ -394,6 +395,7 @@ mod tests { } #[test] + #[ignore] // FIXME(#10016) cat never sees stdin close fn test_pipes() { let pipe_in = os::pipe(); @@ -412,13 +414,14 @@ mod tests { os::close(pipe_out.out); os::close(pipe_err.out); - let expected = ~"test"; - writeclose(pipe_in.out, expected); + do spawn { + writeclose(pipe_in.out, ~"test"); + } let actual = readclose(pipe_out.input); readclose(pipe_err.input); proc.finish(); - assert_eq!(expected, actual); + assert_eq!(~"test", actual); } fn writeclose(fd: c_int, s: &str) { diff --git a/src/test/run-pass/core-run-destroy.rs b/src/test/run-pass/core-run-destroy.rs index 0e0e52c62737a..4ff184b44831e 100644 --- a/src/test/run-pass/core-run-destroy.rs +++ b/src/test/run-pass/core-run-destroy.rs @@ -18,6 +18,7 @@ use std::libc; use std::run; use std::str; +use std::rt::io; #[test] fn test_destroy_once() { @@ -29,7 +30,9 @@ fn test_destroy_once() { fn test_destroy_twice() { let mut p = run::Process::new("echo", [], run::ProcessOptions::new()); p.destroy(); // this shouldnt crash... - p.destroy(); // ...and nor should this (and nor should the destructor) + do io::io_error::cond.trap(|_| {}).inside { + p.destroy(); // ...and nor should this (and nor should the destructor) + } } fn test_destroy_actually_kills(force: bool) { From b5a02e07845b9fb4bc9b09909bd996c874fa3eed Mon Sep 17 00:00:00 2001 From: Do Nhat Minh Date: Thu, 19 Sep 2013 12:03:50 +0800 Subject: [PATCH 21/23] wrapping libuv signal for use in Rust descriptive names easier-to-use api reorganize and document --- src/libstd/rt/io/mod.rs | 3 + src/libstd/rt/io/signal.rs | 190 +++++++++++++++++++++++++++++++++++++ src/libstd/rt/rtio.rs | 6 ++ src/libstd/rt/uv/mod.rs | 6 ++ src/libstd/rt/uv/signal.rs | 100 +++++++++++++++++++ src/libstd/rt/uv/uvio.rs | 45 +++++++++ src/libstd/rt/uv/uvll.rs | 24 +++++ src/rt/rust_uv.cpp | 15 +++ src/rt/rustrt.def.in | 3 + 9 files changed, 392 insertions(+) create mode 100644 src/libstd/rt/io/signal.rs create mode 100644 src/libstd/rt/uv/signal.rs diff --git a/src/libstd/rt/io/mod.rs b/src/libstd/rt/io/mod.rs index 7f5b01bb1ece9..758c97791658f 100644 --- a/src/libstd/rt/io/mod.rs +++ b/src/libstd/rt/io/mod.rs @@ -326,6 +326,9 @@ pub mod native { /// Mock implementations for testing mod mock; +/// Signal handling +pub mod signal; + /// The default buffer size for various I/O operations static DEFAULT_BUF_SIZE: uint = 1024 * 64; diff --git a/src/libstd/rt/io/signal.rs b/src/libstd/rt/io/signal.rs new file mode 100644 index 0000000000000..d3c260d361c63 --- /dev/null +++ b/src/libstd/rt/io/signal.rs @@ -0,0 +1,190 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use comm::{Port, SharedChan, stream}; +use hashmap; +use option::{Some, None}; +use result::{Err, Ok}; +use rt::io::io_error; +use rt::local::Local; +use rt::rtio::{EventLoop, RtioSignalObject}; +use rt::sched::Scheduler; + +#[deriving(Eq, IterBytes)] +pub enum Signum { + /// Equivalent to SIGBREAK, delivered when the user presses Ctrl-Break. + Break = 21i, + /// Equivalent to SIGHUP, delivered when the user closes the terminal + /// window. On delivery of HangUp, the program is given approximately + /// 10 seconds to perfom any cleanup. After that, Windows will + /// unconditionally terminate it. + HangUp = 1i, + /// Equivalent to SIGINT, delivered when the user presses Ctrl-c. + Interrupt = 2i, + /// Equivalent to SIGQUIT, delivered when the user presses Ctrl-\. + Quit = 3i, + /// Equivalent to SIGTSTP, delivered when the user presses Ctrl-z. + StopTemporarily = 20i, + /// Equivalent to SIGUSR1. + User1 = 10i, + /// Equivalent to SIGUSR2. + User2 = 12i, + /// Equivalent to SIGWINCH, delivered when the console has been resized. + /// WindowSizeChange may not be delivered in a timely manner; size change + /// will only be detected when the cursor is being moved. + WindowSizeChange = 28i, +} + +/// Listener provides a port to listen for registered signals. +/// +/// Listener automatically unregisters its handles once it is out of scope. +/// However, clients can still unregister signums manually. +/// +/// Example usage: +/// +/// ```rust +/// use std::rt::io::signal; +/// use std::task; +/// +/// let mut listener = signal::Listener(); +/// listener.register(signal::Interrupt); +/// +/// do task::spawn { +/// loop { +/// match listener.recv() { +/// signal::Interrupt => println("Got Interrupt'ed"), +/// _ => (), +/// } +/// } +/// } +/// +/// ``` +pub struct Listener { + /// A map from signums to handles to keep the handles in memory + priv handles: hashmap::HashMap, + /// chan is where all the handles send signums, which are received by + /// the clients from port. + priv chan: SharedChan, + /// Clients of Listener can `recv()` from this port + port: Port, +} + +impl Listener { + pub fn new() -> Listener { + let (port, chan) = stream(); + Listener { + chan: SharedChan::new(chan), + port: port, + handles: hashmap::HashMap::new(), + } + } + + /// Listen for a signal, returning true when successfully registered for + /// signum. Signals can be received using `recv()`. + pub fn register(&mut self, signum: Signum) -> bool { + match self.handles.find(&signum) { + Some(_) => true, // self is already listening to signum, so succeed + None => { + let chan = self.chan.clone(); + let handle = unsafe { + rtdebug!("Listener::register: borrowing io to init UvSignal"); + let sched: *mut Scheduler = Local::unsafe_borrow(); + rtdebug!("about to init handle"); + (*sched).event_loop.signal(signum, chan) + }; + match handle { + Ok(w) => { + self.handles.insert(signum, w); + true + }, + Err(ioerr) => { + rtdebug!("Listener::register: failed to init: {:?}", ioerr); + io_error::cond.raise(ioerr); + false + }, + } + }, + } + } + + /// Unregister a signal. + pub fn unregister(&mut self, signum: Signum) { + self.handles.pop(&signum); + } +} + +#[cfg(test)] +mod test { + use libc; + use rt::io::timer; + use super::*; + + // kill is only available on Unixes + #[cfg(unix)] + #[fixed_stack_segment] + fn sigint() { + unsafe { + libc::funcs::posix88::signal::kill(libc::getpid(), libc::SIGINT); + } + } + + #[test] + fn test_io_signal_smoketest() { + let mut signal = Listener::new(); + signal.register(Interrupt); + sigint(); + timer::sleep(10); + match signal.port.recv() { + Interrupt => (), + s => fail2!("Expected Interrupt, got {:?}", s), + } + } + + #[test] + fn test_io_signal_two_signal_one_signum() { + let mut s1 = Listener::new(); + let mut s2 = Listener::new(); + s1.register(Interrupt); + s2.register(Interrupt); + sigint(); + timer::sleep(10); + match s1.port.recv() { + Interrupt => (), + s => fail2!("Expected Interrupt, got {:?}", s), + } + match s1.port.recv() { + Interrupt => (), + s => fail2!("Expected Interrupt, got {:?}", s), + } + } + + #[test] + fn test_io_signal_unregister() { + let mut s1 = Listener::new(); + let mut s2 = Listener::new(); + s1.register(Interrupt); + s2.register(Interrupt); + s2.unregister(Interrupt); + sigint(); + timer::sleep(10); + if s2.port.peek() { + fail2!("Unexpected {:?}", s2.port.recv()); + } + } + + #[cfg(windows)] + #[test] + fn test_io_signal_invalid_signum() { + let mut s = Listener::new(); + if s.register(User1) { + fail2!("Unexpected successful registry of signum {:?}", User1); + } + } +} diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index 45c720a89b34c..528be59c54fc7 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -11,11 +11,13 @@ use libc; use option::*; use result::*; +use comm::SharedChan; use libc::c_int; use c_str::CString; use ai = rt::io::net::addrinfo; use rt::io::IoError; +use rt::io::signal::Signum; use super::io::process::ProcessConfig; use super::io::net::ip::{IpAddr, SocketAddr}; use path::Path; @@ -100,6 +102,8 @@ pub trait IoFactory { fn unix_connect(&mut self, path: &CString) -> Result<~RtioPipe, IoError>; fn tty_open(&mut self, fd: c_int, readable: bool) -> Result<~RtioTTY, IoError>; + fn signal(&mut self, signal: Signum, channel: SharedChan) + -> Result<~RtioSignal, IoError>; } pub trait RtioTcpListener : RtioSocket { @@ -192,3 +196,5 @@ pub trait PausibleIdleCallback { fn resume(&mut self); fn close(&mut self); } + +pub trait RtioSignal {} diff --git a/src/libstd/rt/uv/mod.rs b/src/libstd/rt/uv/mod.rs index 88bb28d3763f0..c92a54425bf4f 100644 --- a/src/libstd/rt/uv/mod.rs +++ b/src/libstd/rt/uv/mod.rs @@ -48,6 +48,7 @@ use cast::transmute; use ptr::null; use unstable::finally::Finally; use rt::io::net::ip::SocketAddr; +use rt::io::signal::Signum; use rt::io::IoError; @@ -60,6 +61,7 @@ pub use self::timer::TimerWatcher; pub use self::async::AsyncWatcher; pub use self::process::Process; pub use self::pipe::Pipe; +pub use self::signal::SignalWatcher; /// The implementation of `rtio` for libuv pub mod uvio; @@ -76,6 +78,7 @@ pub mod addrinfo; pub mod process; pub mod pipe; pub mod tty; +pub mod signal; /// XXX: Loop(*handle) is buggy with destructors. Normal structs /// with dtors may not be destructured, but tuple structs can, @@ -146,6 +149,7 @@ pub type TimerCallback = ~fn(TimerWatcher, Option); pub type AsyncCallback = ~fn(AsyncWatcher, Option); pub type UdpReceiveCallback = ~fn(UdpWatcher, int, Buf, SocketAddr, uint, Option); pub type UdpSendCallback = ~fn(UdpWatcher, Option); +pub type SignalCallback = ~fn(SignalWatcher, Signum); /// Callbacks used by StreamWatchers, set as custom data on the foreign handle. @@ -162,6 +166,7 @@ struct WatcherData { udp_recv_cb: Option, udp_send_cb: Option, exit_cb: Option, + signal_cb: Option, } pub trait WatcherInterop { @@ -197,6 +202,7 @@ impl> WatcherInterop for W { udp_recv_cb: None, udp_send_cb: None, exit_cb: None, + signal_cb: None, }; let data = transmute::<~WatcherData, *c_void>(data); uvll::set_data_for_uv_handle(self.native_handle(), data); diff --git a/src/libstd/rt/uv/signal.rs b/src/libstd/rt/uv/signal.rs new file mode 100644 index 0000000000000..70ea8e399d587 --- /dev/null +++ b/src/libstd/rt/uv/signal.rs @@ -0,0 +1,100 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use cast; +use option::Some; +use libc::{c_int, c_void}; +use result::{Err, Ok, Result}; +use rt::io::IoError; +use rt::io::signal::Signum; +use rt::uv::{Loop, NativeHandle, NullCallback, SignalCallback, UvError, Watcher}; +use rt::uv::uv_error_to_io_error; +use rt::uv::uvll; + +pub struct SignalWatcher(*uvll::uv_signal_t); + +impl Watcher for SignalWatcher { } + +impl SignalWatcher { + pub fn new(loop_: &mut Loop) -> SignalWatcher { + unsafe { + let handle = uvll::malloc_handle(uvll::UV_SIGNAL); + assert!(handle.is_not_null()); + assert!(0 == uvll::signal_init(loop_.native_handle(), handle)); + let mut watcher: SignalWatcher = NativeHandle::from_native_handle(handle); + watcher.install_watcher_data(); + return watcher; + } + } + + pub fn start(&mut self, signum: Signum, callback: SignalCallback) -> Result<(), IoError> { + { + let data = self.get_watcher_data(); + data.signal_cb = Some(callback); + } + + let ret = unsafe { + uvll::signal_start(self.native_handle(), signal_cb, signum as c_int) + }; + + return match ret { + 0 => Ok(()), + _ => Err(uv_error_to_io_error(UvError(ret))), + }; + + extern fn signal_cb(handle: *uvll::uv_signal_t, signum: c_int) { + let mut watcher: SignalWatcher = NativeHandle::from_native_handle(handle); + let data = watcher.get_watcher_data(); + let cb = data.signal_cb.get_ref(); + (*cb)(watcher, unsafe { cast::transmute(signum as i64) }); + } + } + + pub fn stop(&mut self) { + unsafe { + uvll::signal_stop(self.native_handle()); + } + } + + pub fn close(self, cb: NullCallback) { + let mut watcher = self; + { + let data = watcher.get_watcher_data(); + assert!(data.close_cb.is_none()); + data.close_cb = Some(cb); + } + + unsafe { + uvll::close(watcher.native_handle(), close_cb); + } + + extern fn close_cb(handle: *uvll::uv_signal_t) { + let mut watcher: SignalWatcher = NativeHandle::from_native_handle(handle); + { + let data = watcher.get_watcher_data(); + data.close_cb.take_unwrap()(); + } + watcher.drop_watcher_data(); + unsafe { + uvll::free_handle(handle as *c_void); + } + } + } +} + +impl NativeHandle<*uvll::uv_signal_t> for SignalWatcher { + fn from_native_handle(handle: *uvll::uv_signal_t) -> SignalWatcher { + SignalWatcher(handle) + } + + fn native_handle(&self) -> *uvll::uv_signal_t { + match self { &SignalWatcher(ptr) => ptr } + } +} diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index f12b1bce9e67d..48f4dbe43d6f4 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -13,6 +13,7 @@ use cast::transmute; use cast; use cell::Cell; use clone::Clone; +use comm::{SendDeferred, SharedChan}; use libc::{c_int, c_uint, c_void, pid_t}; use ops::Drop; use option::*; @@ -40,6 +41,7 @@ use libc::{lseek, off_t, O_CREAT, O_APPEND, O_TRUNC, O_RDWR, O_RDONLY, O_WRONLY, use rt::io::{FileMode, FileAccess, OpenOrCreate, Open, Create, CreateOrTruncate, Append, Truncate, Read, Write, ReadWrite, FileStat}; +use rt::io::signal::Signum; use task; use ai = rt::io::net::addrinfo; @@ -861,6 +863,17 @@ impl IoFactory for UvIoFactory { Err(e) => Err(uv_error_to_io_error(e)) } } + + fn signal(&mut self, signum: Signum, channel: SharedChan) + -> Result<~RtioSignalObject, IoError> { + let watcher = SignalWatcher::new(self.uv_loop()); + let home = get_handle_to_current_scheduler!(); + let mut signal = ~UvSignal::new(watcher, home); + match signal.watcher.start(signum, |_, _| channel.send_deferred(signum)) { + Ok(()) => Ok(signal), + Err(e) => Err(uv_error_to_io_error(e)), + } + } } pub struct UvTcpListener { @@ -1811,6 +1824,38 @@ impl RtioUnixAcceptor for UvUnixAcceptor { } } +pub struct UvSignal { + watcher: signal::SignalWatcher, + home: SchedHandle, +} + +impl HomingIO for UvSignal { + fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home } +} + +impl UvSignal { + fn new(w: signal::SignalWatcher, home: SchedHandle) -> UvSignal { + UvSignal { watcher: w, home: home } + } +} + +impl RtioSignal for UvSignal {} + +impl Drop for UvSignal { + fn drop(&mut self) { + do self.home_for_io_with_sched |self_, scheduler| { + rtdebug!("closing UvSignal"); + do scheduler.deschedule_running_task_and_then |_, task| { + let task_cell = Cell::new(task); + do self_.watcher.close { + let scheduler: ~Scheduler = Local::take(); + scheduler.resume_blocked_task_immediately(task_cell.take()); + } + } + } + } +} + // this function is full of lies unsafe fn local_io() -> &'static mut IoFactory { do Local::borrow |sched: &mut Scheduler| { diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index f3e14dc314b70..fa4083657d591 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -132,6 +132,7 @@ pub type uv_getaddrinfo_t = c_void; pub type uv_process_t = c_void; pub type uv_pipe_t = c_void; pub type uv_tty_t = c_void; +pub type uv_signal_t = c_void; pub struct uv_timespec_t { tv_sec: libc::c_long, @@ -219,6 +220,8 @@ pub type uv_getaddrinfo_cb = extern "C" fn(req: *uv_getaddrinfo_t, pub type uv_exit_cb = extern "C" fn(handle: *uv_process_t, exit_status: c_int, term_signal: c_int); +pub type uv_signal_cb = extern "C" fn(handle: *uv_signal_t, + signum: c_int); pub type sockaddr = c_void; pub type sockaddr_in = c_void; @@ -991,6 +994,21 @@ pub unsafe fn guess_handle(fd: c_int) -> uv_handle_type { rust_uv_guess_handle(fd) } +pub unsafe fn signal_init(loop_: *uv_loop_t, handle: *uv_signal_t) -> c_int { + #[fixed_stack_segment]; #[inline(never)]; + return rust_uv_signal_init(loop_, handle); +} +pub unsafe fn signal_start(handle: *uv_signal_t, + signal_cb: uv_signal_cb, + signum: c_int) -> c_int { + #[fixed_stack_segment]; #[inline(never)]; + return rust_uv_signal_start(handle, signal_cb, signum); +} +pub unsafe fn signal_stop(handle: *uv_signal_t) -> c_int { + #[fixed_stack_segment]; #[inline(never)]; + return rust_uv_signal_stop(handle); +} + pub struct uv_err_data { priv err_name: ~str, priv err_msg: ~str, @@ -1160,4 +1178,10 @@ extern { //#[rust_stack] pub fn rust_AI_NUMERICSERV() -> c_int; //#[rust_stack] pub fn rust_AI_PASSIVE() -> c_int; //#[rust_stack] pub fn rust_AI_V4MAPPED() -> c_int; + + fn rust_uv_signal_init(loop_: *uv_loop_t, handle: *uv_signal_t) -> c_int; + fn rust_uv_signal_start(handle: *uv_signal_t, + signal_cb: uv_signal_cb, + signum: c_int) -> c_int; + fn rust_uv_signal_stop(handle: *uv_signal_t) -> c_int; } diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index 55fa09c38183d..c463cf039d306 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -673,3 +673,18 @@ extern "C" uv_handle_type rust_uv_guess_handle(int fd) { return uv_guess_handle(fd); } + +extern "C" int +rust_uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) { + return uv_signal_init(loop, handle); +} + +extern "C" int +rust_uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) { + return uv_signal_start(handle, signal_cb, signum); +} + +extern "C" int +rust_uv_signal_stop(uv_signal_t* handle) { + return uv_signal_stop(handle); +} diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 203f2e4d5f2b4..3c10e42f74384 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -191,6 +191,9 @@ rust_set_stdio_container_fd rust_set_stdio_container_stream rust_uv_process_pid rust_uv_pipe_init +rust_uv_signal_init +rust_uv_signal_start +rust_uv_signal_stop sdhtml_renderer sd_markdown_new sd_markdown_render From d425218395b4a4dd7c6e4f3d680447efd2a3abc6 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 22 Oct 2013 08:51:44 -0700 Subject: [PATCH 22/23] Bring io::signal up to date with changes to rt::rtio --- src/libstd/rt/io/signal.rs | 93 ++++++++++++++++++++++++-------------- src/libstd/rt/uv/signal.rs | 57 ++++++----------------- src/libstd/rt/uv/uvio.rs | 4 +- 3 files changed, 75 insertions(+), 79 deletions(-) diff --git a/src/libstd/rt/io/signal.rs b/src/libstd/rt/io/signal.rs index d3c260d361c63..07fe91f57a0d9 100644 --- a/src/libstd/rt/io/signal.rs +++ b/src/libstd/rt/io/signal.rs @@ -8,14 +8,23 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +/*! + +Signal handling + +This modules provides bindings to receive signals safely, built on top of the +local I/O factory. There are a number of defined signals which can be caught, +but not all signals will work across all platforms (windows doesn't have +definitions for a number of signals. + +*/ + use comm::{Port, SharedChan, stream}; use hashmap; use option::{Some, None}; use result::{Err, Ok}; use rt::io::io_error; -use rt::local::Local; -use rt::rtio::{EventLoop, RtioSignalObject}; -use rt::sched::Scheduler; +use rt::rtio::{IoFactory, RtioSignal, with_local_io}; #[deriving(Eq, IterBytes)] pub enum Signum { @@ -47,19 +56,18 @@ pub enum Signum { /// Listener automatically unregisters its handles once it is out of scope. /// However, clients can still unregister signums manually. /// -/// Example usage: +/// # Example /// /// ```rust -/// use std::rt::io::signal; -/// use std::task; +/// use std::rt::io::signal::{Listener, Interrupt}; /// -/// let mut listener = signal::Listener(); +/// let mut listener = Listener::new(); /// listener.register(signal::Interrupt); /// -/// do task::spawn { +/// do spawn { /// loop { -/// match listener.recv() { -/// signal::Interrupt => println("Got Interrupt'ed"), +/// match listener.port.recv() { +/// Interrupt => println("Got Interrupt'ed"), /// _ => (), /// } /// } @@ -68,15 +76,20 @@ pub enum Signum { /// ``` pub struct Listener { /// A map from signums to handles to keep the handles in memory - priv handles: hashmap::HashMap, + priv handles: hashmap::HashMap, /// chan is where all the handles send signums, which are received by /// the clients from port. priv chan: SharedChan, - /// Clients of Listener can `recv()` from this port + + /// Clients of Listener can `recv()` from this port. This is exposed to + /// allow selection over this port as well as manipulation of the port + /// directly. port: Port, } impl Listener { + /// Creates a new listener for signals. Once created, signals are bound via + /// the `register` method (otherwise nothing will ever be received) pub fn new() -> Listener { let (port, chan) = stream(); Listener { @@ -88,33 +101,43 @@ impl Listener { /// Listen for a signal, returning true when successfully registered for /// signum. Signals can be received using `recv()`. + /// + /// Once a signal is registered, this listener will continue to receive + /// notifications of signals until it is unregistered. This occurs + /// regardless of the number of other listeners registered in other tasks + /// (or on this task). + /// + /// Signals are still received if there is no task actively waiting for + /// a signal, and a later call to `recv` will return the signal that was + /// received while no task was waiting on it. + /// + /// # Failure + /// + /// If this function fails to register a signal handler, then an error will + /// be raised on the `io_error` condition and the function will return + /// false. pub fn register(&mut self, signum: Signum) -> bool { - match self.handles.find(&signum) { - Some(_) => true, // self is already listening to signum, so succeed - None => { - let chan = self.chan.clone(); - let handle = unsafe { - rtdebug!("Listener::register: borrowing io to init UvSignal"); - let sched: *mut Scheduler = Local::unsafe_borrow(); - rtdebug!("about to init handle"); - (*sched).event_loop.signal(signum, chan) - }; - match handle { - Ok(w) => { - self.handles.insert(signum, w); - true - }, - Err(ioerr) => { - rtdebug!("Listener::register: failed to init: {:?}", ioerr); - io_error::cond.raise(ioerr); - false - }, - } - }, + if self.handles.contains_key(&signum) { + return true; // self is already listening to signum, so succeed } + do with_local_io |io| { + match io.signal(signum, self.chan.clone()) { + Ok(w) => { + self.handles.insert(signum, w); + Some(()) + }, + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } + } + }.is_some() } - /// Unregister a signal. + /// Unregisters a signal. If this listener currently had a handler + /// registered for the signal, then it will stop receiving any more + /// notification about the signal. If the signal has already been received, + /// it may still be returned by `recv`. pub fn unregister(&mut self, signum: Signum) { self.handles.pop(&signum); } diff --git a/src/libstd/rt/uv/signal.rs b/src/libstd/rt/uv/signal.rs index 70ea8e399d587..e51b7d90d9550 100644 --- a/src/libstd/rt/uv/signal.rs +++ b/src/libstd/rt/uv/signal.rs @@ -10,12 +10,10 @@ use cast; use option::Some; -use libc::{c_int, c_void}; +use libc::c_int; use result::{Err, Ok, Result}; -use rt::io::IoError; use rt::io::signal::Signum; -use rt::uv::{Loop, NativeHandle, NullCallback, SignalCallback, UvError, Watcher}; -use rt::uv::uv_error_to_io_error; +use rt::uv::{Loop, NativeHandle, SignalCallback, UvError, Watcher}; use rt::uv::uvll; pub struct SignalWatcher(*uvll::uv_signal_t); @@ -34,19 +32,19 @@ impl SignalWatcher { } } - pub fn start(&mut self, signum: Signum, callback: SignalCallback) -> Result<(), IoError> { - { - let data = self.get_watcher_data(); - data.signal_cb = Some(callback); - } - - let ret = unsafe { - uvll::signal_start(self.native_handle(), signal_cb, signum as c_int) - }; - - return match ret { - 0 => Ok(()), - _ => Err(uv_error_to_io_error(UvError(ret))), + pub fn start(&mut self, signum: Signum, callback: SignalCallback) + -> Result<(), UvError> + { + return unsafe { + match uvll::signal_start(self.native_handle(), signal_cb, + signum as c_int) { + 0 => { + let data = self.get_watcher_data(); + data.signal_cb = Some(callback); + Ok(()) + } + n => Err(UvError(n)), + } }; extern fn signal_cb(handle: *uvll::uv_signal_t, signum: c_int) { @@ -62,31 +60,6 @@ impl SignalWatcher { uvll::signal_stop(self.native_handle()); } } - - pub fn close(self, cb: NullCallback) { - let mut watcher = self; - { - let data = watcher.get_watcher_data(); - assert!(data.close_cb.is_none()); - data.close_cb = Some(cb); - } - - unsafe { - uvll::close(watcher.native_handle(), close_cb); - } - - extern fn close_cb(handle: *uvll::uv_signal_t) { - let mut watcher: SignalWatcher = NativeHandle::from_native_handle(handle); - { - let data = watcher.get_watcher_data(); - data.close_cb.take_unwrap()(); - } - watcher.drop_watcher_data(); - unsafe { - uvll::free_handle(handle as *c_void); - } - } - } } impl NativeHandle<*uvll::uv_signal_t> for SignalWatcher { diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 48f4dbe43d6f4..473eec32c67eb 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -865,12 +865,12 @@ impl IoFactory for UvIoFactory { } fn signal(&mut self, signum: Signum, channel: SharedChan) - -> Result<~RtioSignalObject, IoError> { + -> Result<~RtioSignal, IoError> { let watcher = SignalWatcher::new(self.uv_loop()); let home = get_handle_to_current_scheduler!(); let mut signal = ~UvSignal::new(watcher, home); match signal.watcher.start(signum, |_, _| channel.send_deferred(signum)) { - Ok(()) => Ok(signal), + Ok(()) => Ok(signal as ~RtioSignal), Err(e) => Err(uv_error_to_io_error(e)), } } From 188e471339dfe652b8ff9f3bbe4cc262a040c584 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 22 Oct 2013 09:36:30 -0700 Subject: [PATCH 23/23] Another round of test fixes and merge conflicts --- src/libextra/url.rs | 4 +- src/librustpkg/tests.rs | 19 ++- .../testsuite/pass/src/c-dependencies/pkg.rs | 4 +- .../testsuite/pass/src/fancy-lib/pkg.rs | 11 +- src/libstd/rt/io/signal.rs | 25 ++-- src/libstd/rt/io/stdio.rs | 133 +++++++++++++----- src/libstd/rt/rtio.rs | 16 ++- src/libstd/rt/task.rs | 9 +- src/libstd/rt/uv/file.rs | 33 +++-- src/libstd/rt/uv/idle.rs | 35 ++--- src/libstd/rt/uv/signal.rs | 2 +- src/libstd/rt/uv/uvio.rs | 58 ++++---- src/libstd/rt/uv/uvll.rs | 50 +++---- src/libstd/run.rs | 27 ++-- src/rt/rust_uv.cpp | 10 -- src/rt/rustrt.def.in | 2 - 16 files changed, 264 insertions(+), 174 deletions(-) diff --git a/src/libextra/url.rs b/src/libextra/url.rs index bfa3934700a51..d268b106e5cb6 100644 --- a/src/libextra/url.rs +++ b/src/libextra/url.rs @@ -145,7 +145,7 @@ fn decode_inner(s: &str, full_url: bool) -> ~str { let mut bytes = [0, 0]; match rdr.read(bytes) { Some(2) => {} - _ => fail2!() // XXX: malformed url? + _ => fail!() // XXX: malformed url? } let ch = uint::parse_bytes(bytes, 16u).unwrap() as u8 as char; @@ -279,7 +279,7 @@ pub fn decode_form_urlencoded(s: &[u8]) -> HashMap<~str, ~[~str]> { let mut bytes = [0, 0]; match rdr.read(bytes) { Some(2) => {} - _ => fail2!() // XXX: malformed? + _ => fail!() // XXX: malformed? } uint::parse_bytes(bytes, 16u).unwrap() as u8 as char } diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index 16e13f7009212..ce5e81d410923 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -11,7 +11,10 @@ // rustpkg unit tests use context::{BuildContext, Context, RustcFlags}; -use std::{io, os, run, str, task}; +use std::{os, run, str, task}; +use std::rt::io; +use std::rt::io::Writer; +use std::rt::io::file::FileInfo; use extra::arc::Arc; use extra::arc::RWArc; use extra::tempfile::TempDir; @@ -81,8 +84,9 @@ fn git_repo_pkg_with_tag(a_tag: ~str) -> PkgId { } fn writeFile(file_path: &Path, contents: &str) { - let out = io::file_writer(file_path, [io::Create, io::Truncate]).unwrap(); - out.write_line(contents); + let mut out = file_path.open_writer(io::CreateOrTruncate); + out.write(contents.as_bytes()); + out.write(['\n' as u8]); } fn mk_emptier_workspace(tag: &str) -> TempDir { @@ -550,10 +554,11 @@ fn frob_source_file(workspace: &Path, pkgid: &PkgId, filename: &str) { debug!("Frobbed? {:?}", maybe_p); match maybe_p { Some(ref p) => { - let w = io::file_writer(p, &[io::Append]); - match w { - Err(s) => { let _ = cond.raise((p.clone(), format!("Bad path: {}", s))); } - Ok(w) => w.write_line("/* hi */") + do io::io_error::cond.trap(|e| { + cond.raise((p.clone(), format!("Bad path: {}", e.desc))); + }).inside { + let mut w = p.open_writer(io::Append); + w.write(bytes!("/* hi */\n")); } } None => fail!("frob_source_file failed to find a source file in {}", diff --git a/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs b/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs index b667dc0a576fd..016635339a9d9 100644 --- a/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs +++ b/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs @@ -11,7 +11,7 @@ extern mod rustpkg; extern mod rustc; -use std::{io, os, task}; +use std::{os, task}; use rustpkg::api; use rustpkg::version::NoVersion; use rustpkg::workcache_support::digest_file_with_date; @@ -36,7 +36,7 @@ pub fn main() { } if args[2] != ~"install" { - io::println(format!("Warning: I don't know how to {}", args[2])); + println(format!("Warning: I don't know how to {}", args[2])); return; } diff --git a/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs b/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs index 0b838b3e0f9e3..f82c585b1d156 100644 --- a/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs +++ b/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs @@ -11,7 +11,10 @@ extern mod rustpkg; extern mod rustc; -use std::{io, os}; +use std::os; +use std::rt::io; +use std::rt::io::Writer; +use std::rt::io::file::FileInfo; use rustpkg::api; use rustpkg::version::NoVersion; @@ -42,9 +45,9 @@ pub fn main() { let out_path = os::self_exe_path().expect("Couldn't get self_exe path"); debug!("Writing file"); - let file = io::file_writer(&out_path.join("generated.rs"), [io::Create]).unwrap(); - file.write_str("pub fn wheeeee() { let xs = [1, 2, 3]; \ - for _ in xs.iter() { assert!(true); } }"); + let mut file = out_path.join("generated.rs").open_writer(io::Create); + file.write("pub fn wheeeee() { let xs = [1, 2, 3]; \ + for _ in xs.iter() { assert!(true); } }".as_bytes()); let context = api::default_context(sysroot, api::default_workspace()); api::install_pkg(&context, os::getcwd(), ~"fancy-lib", NoVersion, ~[]); diff --git a/src/libstd/rt/io/signal.rs b/src/libstd/rt/io/signal.rs index 07fe91f57a0d9..a13fc19d000a8 100644 --- a/src/libstd/rt/io/signal.rs +++ b/src/libstd/rt/io/signal.rs @@ -147,6 +147,7 @@ impl Listener { mod test { use libc; use rt::io::timer; + use rt::io; use super::*; // kill is only available on Unixes @@ -158,7 +159,7 @@ mod test { } } - #[test] + #[test] #[cfg(unix)] fn test_io_signal_smoketest() { let mut signal = Listener::new(); signal.register(Interrupt); @@ -166,11 +167,11 @@ mod test { timer::sleep(10); match signal.port.recv() { Interrupt => (), - s => fail2!("Expected Interrupt, got {:?}", s), + s => fail!("Expected Interrupt, got {:?}", s), } } - #[test] + #[test] #[cfg(unix)] fn test_io_signal_two_signal_one_signum() { let mut s1 = Listener::new(); let mut s2 = Listener::new(); @@ -180,15 +181,15 @@ mod test { timer::sleep(10); match s1.port.recv() { Interrupt => (), - s => fail2!("Expected Interrupt, got {:?}", s), + s => fail!("Expected Interrupt, got {:?}", s), } match s1.port.recv() { Interrupt => (), - s => fail2!("Expected Interrupt, got {:?}", s), + s => fail!("Expected Interrupt, got {:?}", s), } } - #[test] + #[test] #[cfg(unix)] fn test_io_signal_unregister() { let mut s1 = Listener::new(); let mut s2 = Listener::new(); @@ -198,7 +199,7 @@ mod test { sigint(); timer::sleep(10); if s2.port.peek() { - fail2!("Unexpected {:?}", s2.port.recv()); + fail!("Unexpected {:?}", s2.port.recv()); } } @@ -206,8 +207,14 @@ mod test { #[test] fn test_io_signal_invalid_signum() { let mut s = Listener::new(); - if s.register(User1) { - fail2!("Unexpected successful registry of signum {:?}", User1); + let mut called = false; + do io::io_error::cond.trap(|_| { + called = true; + }).inside { + if s.register(User1) { + fail!("Unexpected successful registry of signum {:?}", User1); + } } + assert!(called); } } diff --git a/src/libstd/rt/io/stdio.rs b/src/libstd/rt/io/stdio.rs index e601ece88bb5f..b922e6400cc50 100644 --- a/src/libstd/rt/io/stdio.rs +++ b/src/libstd/rt/io/stdio.rs @@ -30,20 +30,57 @@ use fmt; use libc; use option::{Option, Some, None}; use result::{Ok, Err}; -use rt::rtio::{IoFactory, RtioTTY, with_local_io, RtioPipe}; -use super::{Reader, Writer, io_error}; +use rt::rtio::{IoFactory, RtioTTY, RtioFileStream, with_local_io, + CloseAsynchronously}; +use super::{Reader, Writer, io_error, IoError, OtherIoError}; + +// And so begins the tale of acquiring a uv handle to a stdio stream on all +// platforms in all situations. Our story begins by splitting the world into two +// categories, windows and unix. Then one day the creators of unix said let +// there be redirection! And henceforth there was redirection away from the +// console for standard I/O streams. +// +// After this day, the world split into four factions: +// +// 1. Unix with stdout on a terminal. +// 2. Unix with stdout redirected. +// 3. Windows with stdout on a terminal. +// 4. Windows with stdout redirected. +// +// Many years passed, and then one day the nation of libuv decided to unify this +// world. After months of toiling, uv created three ideas: TTY, Pipe, File. +// These three ideas propagated throughout the lands and the four great factions +// decided to settle among them. +// +// The groups of 1, 2, and 3 all worked very hard towards the idea of TTY. Upon +// doing so, they even enhanced themselves further then their Pipe/File +// brethren, becoming the dominant powers. +// +// The group of 4, however, decided to work independently. They abandoned the +// common TTY belief throughout, and even abandoned the fledgling Pipe belief. +// The members of the 4th faction decided to only align themselves with File. +// +// tl;dr; TTY works on everything but when windows stdout is redirected, in that +// case pipe also doesn't work, but magically file does! +enum StdSource { + TTY(~RtioTTY), + File(~RtioFileStream), +} #[fixed_stack_segment] #[inline(never)] -fn tty(fd: libc::c_int, f: &fn(~RtioTTY) -> T) -> T { +fn src(fd: libc::c_int, readable: bool, f: &fn(StdSource) -> T) -> T { do with_local_io |io| { - // Always pass in readable as true, otherwise libuv turns our writes - // into blocking writes. We also need to dup the file descriptor because - // the tty will be closed when it's dropped. - match io.tty_open(unsafe { libc::dup(fd) }, true) { - Ok(tty) => Some(f(tty)), - Err(e) => { - io_error::cond.raise(e); - None + let fd = unsafe { libc::dup(fd) }; + match io.tty_open(fd, readable) { + Ok(tty) => Some(f(TTY(tty))), + Err(_) => { + // It's not really that desirable if these handles are closed + // synchronously, and because they're squirreled away in a task + // structure the destructors will be run when the task is + // attempted to get destroyed. This means that if we run a + // synchronous destructor we'll attempt to do some scheduling + // operations which will just result in sadness. + Some(f(File(io.fs_from_raw_fd(fd, CloseAsynchronously)))) } } }.unwrap() @@ -54,15 +91,7 @@ fn tty(fd: libc::c_int, f: &fn(~RtioTTY) -> T) -> T { /// See `stdout()` for notes about this function. #[fixed_stack_segment] #[inline(never)] pub fn stdin() -> StdReader { - do with_local_io |io| { - match io.pipe_open(unsafe { libc::dup(libc::STDIN_FILENO) }) { - Ok(stream) => Some(StdReader { inner: stream }), - Err(e) => { - io_error::cond.raise(e); - None - } - } - }.unwrap() + do src(libc::STDIN_FILENO, true) |src| { StdReader { inner: src } } } /// Creates a new non-blocking handle to the stdout of the current process. @@ -72,14 +101,14 @@ pub fn stdin() -> StdReader { /// task context because the stream returned will be a non-blocking object using /// the local scheduler to perform the I/O. pub fn stdout() -> StdWriter { - do tty(libc::STDOUT_FILENO) |tty| { StdWriter { inner: tty } } + do src(libc::STDOUT_FILENO, false) |src| { StdWriter { inner: src } } } /// Creates a new non-blocking handle to the stderr of the current process. /// /// See `stdout()` for notes about this function. pub fn stderr() -> StdWriter { - do tty(libc::STDERR_FILENO) |tty| { StdWriter { inner: tty } } + do src(libc::STDERR_FILENO, false) |src| { StdWriter { inner: src } } } /// Prints a string to the stdout of the current process. No newline is emitted @@ -117,12 +146,16 @@ pub fn println_args(fmt: &fmt::Arguments) { /// Representation of a reader of a standard input stream pub struct StdReader { - priv inner: ~RtioPipe + priv inner: StdSource } impl Reader for StdReader { fn read(&mut self, buf: &mut [u8]) -> Option { - match self.inner.read(buf) { + let ret = match self.inner { + TTY(ref mut tty) => tty.read(buf), + File(ref mut file) => file.read(buf).map_move(|i| i as uint), + }; + match ret { Ok(amt) => Some(amt as uint), Err(e) => { io_error::cond.raise(e); @@ -136,7 +169,7 @@ impl Reader for StdReader { /// Representation of a writer to a standard output stream pub struct StdWriter { - priv inner: ~RtioTTY + priv inner: StdSource } impl StdWriter { @@ -151,10 +184,22 @@ impl StdWriter { /// This function will raise on the `io_error` condition if an error /// happens. pub fn winsize(&mut self) -> Option<(int, int)> { - match self.inner.get_winsize() { - Ok(p) => Some(p), - Err(e) => { - io_error::cond.raise(e); + match self.inner { + TTY(ref mut tty) => { + match tty.get_winsize() { + Ok(p) => Some(p), + Err(e) => { + io_error::cond.raise(e); + None + } + } + } + File(*) => { + io_error::cond.raise(IoError { + kind: OtherIoError, + desc: "stream is not a tty", + detail: None, + }); None } } @@ -168,21 +213,41 @@ impl StdWriter { /// This function will raise on the `io_error` condition if an error /// happens. pub fn set_raw(&mut self, raw: bool) { - match self.inner.set_raw(raw) { - Ok(()) => {}, - Err(e) => io_error::cond.raise(e), + match self.inner { + TTY(ref mut tty) => { + match tty.set_raw(raw) { + Ok(()) => {}, + Err(e) => io_error::cond.raise(e), + } + } + File(*) => { + io_error::cond.raise(IoError { + kind: OtherIoError, + desc: "stream is not a tty", + detail: None, + }); + } } } /// Returns whether this tream is attached to a TTY instance or not. /// /// This is similar to libc's isatty() function - pub fn isatty(&self) -> bool { self.inner.isatty() } + pub fn isatty(&self) -> bool { + match self.inner { + TTY(ref tty) => tty.isatty(), + File(*) => false, + } + } } impl Writer for StdWriter { fn write(&mut self, buf: &[u8]) { - match self.inner.write(buf) { + let ret = match self.inner { + TTY(ref mut tty) => tty.write(buf), + File(ref mut file) => file.write(buf), + }; + match ret { Ok(()) => {} Err(e) => io_error::cond.raise(e) } diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index 528be59c54fc7..66a0676a2f410 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -58,6 +58,20 @@ pub struct FileOpenConfig { priv mode: int } +/// Description of what to do when a file handle is closed +pub enum CloseBehavior { + /// Do not close this handle when the object is destroyed + DontClose, + /// Synchronously close the handle, meaning that the task will block when + /// the handle is destroyed until it has been fully closed. + CloseSynchronously, + /// Asynchronously closes a handle, meaning that the task will *not* block + /// when the handle is destroyed, but the handle will still get deallocated + /// and cleaned up (but this will happen asynchronously on the local event + /// loop). + CloseAsynchronously, +} + pub fn with_local_io(f: &fn(&mut IoFactory) -> Option) -> Option { use rt::sched::Scheduler; use rt::local::Local; @@ -84,7 +98,7 @@ pub trait IoFactory { fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>, hint: Option) -> Result<~[ai::Info], IoError>; fn timer_init(&mut self) -> Result<~RtioTimer, IoError>; - fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileStream; + fn fs_from_raw_fd(&mut self, fd: c_int, close: CloseBehavior) -> ~RtioFileStream; fn fs_open(&mut self, path: &CString, fm: FileMode, fa: FileAccess) -> Result<~RtioFileStream, IoError>; fn fs_unlink(&mut self, path: &CString) -> Result<(), IoError>; diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index b3c65ce4749de..1ea68bb52d7e0 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -479,7 +479,6 @@ pub extern "C" fn rust_stack_exhausted() { use rt::in_green_task_context; use rt::task::Task; use rt::local::Local; - use rt::logging::Logger; use unstable::intrinsics; unsafe { @@ -529,8 +528,12 @@ pub extern "C" fn rust_stack_exhausted() { do Local::borrow |task: &mut Task| { let n = task.name.as_ref().map(|n| n.as_slice()).unwrap_or(""); - format_args!(|args| { task.logger.log(args) }, - "task '{}' has overflowed its stack", n); + // See the message below for why this is not emitted to the + // task's logger. This has the additional conundrum of the + // logger may not be initialized just yet, meaning that an FFI + // call would happen to initialized it (calling out to libuv), + // and the FFI call needs 2MB of stack when we just ran out. + rterrln!("task '{}' has overflowed its stack", n); } } else { rterrln!("stack overflow in non-task context"); diff --git a/src/libstd/rt/uv/file.rs b/src/libstd/rt/uv/file.rs index 78b3a88f5f1ba..d2ca15959b025 100644 --- a/src/libstd/rt/uv/file.rs +++ b/src/libstd/rt/uv/file.rs @@ -43,10 +43,11 @@ impl FsRequest { let mut me = self; me.req_boilerplate(Some(cb)) }; - path.with_ref(|p| unsafe { + let ret = path.with_ref(|p| unsafe { uvll::fs_open(loop_.native_handle(), self.native_handle(), p, flags, mode, complete_cb_ptr) }); + assert_eq!(ret, 0); } pub fn open_sync(self, loop_: &Loop, path: &CString, @@ -67,10 +68,11 @@ impl FsRequest { let mut me = self; me.req_boilerplate(Some(cb)) }; - path.with_ref(|p| unsafe { + let ret = path.with_ref(|p| unsafe { uvll::fs_unlink(loop_.native_handle(), self.native_handle(), p, complete_cb_ptr) }); + assert_eq!(ret, 0); } pub fn unlink_sync(self, loop_: &Loop, path: &CString) @@ -91,10 +93,11 @@ impl FsRequest { let mut me = self; me.req_boilerplate(Some(cb)) }; - path.with_ref(|p| unsafe { + let ret = path.with_ref(|p| unsafe { uvll::fs_stat(loop_.native_handle(), self.native_handle(), p, complete_cb_ptr) }); + assert_eq!(ret, 0); } pub fn write(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64, cb: FsCallback) { @@ -104,11 +107,12 @@ impl FsRequest { }; let base_ptr = buf.base as *c_void; let len = buf.len as uint; - unsafe { + let ret = unsafe { uvll::fs_write(loop_.native_handle(), self.native_handle(), fd, base_ptr, len, offset, complete_cb_ptr) }; + assert_eq!(ret, 0); } pub fn write_sync(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64) -> Result { @@ -133,11 +137,12 @@ impl FsRequest { }; let buf_ptr = buf.base as *c_void; let len = buf.len as uint; - unsafe { + let ret = unsafe { uvll::fs_read(loop_.native_handle(), self.native_handle(), fd, buf_ptr, len, offset, complete_cb_ptr) }; + assert_eq!(ret, 0); } pub fn read_sync(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64) -> Result { @@ -160,10 +165,11 @@ impl FsRequest { let mut me = self; me.req_boilerplate(Some(cb)) }; - unsafe { + let ret = unsafe { uvll::fs_close(loop_.native_handle(), self.native_handle(), fd, complete_cb_ptr) }; + assert_eq!(ret, 0); } pub fn close_sync(self, loop_: &Loop, fd: c_int) -> Result { let complete_cb_ptr = { @@ -182,10 +188,11 @@ impl FsRequest { let mut me = self; me.req_boilerplate(Some(cb)) }; - path.with_ref(|p| unsafe { + let ret = path.with_ref(|p| unsafe { uvll::fs_mkdir(loop_.native_handle(), - self.native_handle(), p, mode, complete_cb_ptr) + self.native_handle(), p, mode, complete_cb_ptr) }); + assert_eq!(ret, 0); } pub fn rmdir(self, loop_: &Loop, path: &CString, cb: FsCallback) { @@ -193,10 +200,11 @@ impl FsRequest { let mut me = self; me.req_boilerplate(Some(cb)) }; - path.with_ref(|p| unsafe { + let ret = path.with_ref(|p| unsafe { uvll::fs_rmdir(loop_.native_handle(), - self.native_handle(), p, complete_cb_ptr) + self.native_handle(), p, complete_cb_ptr) }); + assert_eq!(ret, 0); } pub fn readdir(self, loop_: &Loop, path: &CString, @@ -205,10 +213,11 @@ impl FsRequest { let mut me = self; me.req_boilerplate(Some(cb)) }; - path.with_ref(|p| unsafe { + let ret = path.with_ref(|p| unsafe { uvll::fs_readdir(loop_.native_handle(), - self.native_handle(), p, flags, complete_cb_ptr) + self.native_handle(), p, flags, complete_cb_ptr) }); + assert_eq!(ret, 0); } // accessors/utility funcs diff --git a/src/libstd/rt/uv/idle.rs b/src/libstd/rt/uv/idle.rs index 9d392583b9e12..40f0750b2d074 100644 --- a/src/libstd/rt/uv/idle.rs +++ b/src/libstd/rt/uv/idle.rs @@ -20,9 +20,9 @@ impl Watcher for IdleWatcher { } impl IdleWatcher { pub fn new(loop_: &mut Loop) -> IdleWatcher { unsafe { - let handle = uvll::idle_new(); + let handle = uvll::malloc_handle(uvll::UV_IDLE); assert!(handle.is_not_null()); - assert!(0 == uvll::idle_init(loop_.native_handle(), handle)); + assert_eq!(uvll::idle_init(loop_.native_handle(), handle), 0); let mut watcher: IdleWatcher = NativeHandle::from_native_handle(handle); watcher.install_watcher_data(); return watcher @@ -36,29 +36,14 @@ impl IdleWatcher { } unsafe { - assert!(0 == uvll::idle_start(self.native_handle(), idle_cb)) - }; - - extern fn idle_cb(handle: *uvll::uv_idle_t, status: c_int) { - let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle); - let data = idle_watcher.get_watcher_data(); - let cb: &IdleCallback = data.idle_cb.get_ref(); - let status = status_to_maybe_uv_error(status); - (*cb)(idle_watcher, status); + assert_eq!(uvll::idle_start(self.native_handle(), idle_cb), 0) } } pub fn restart(&mut self) { unsafe { - assert!(0 == uvll::idle_start(self.native_handle(), idle_cb)) - }; - - extern fn idle_cb(handle: *uvll::uv_idle_t, status: c_int) { - let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle); - let data = idle_watcher.get_watcher_data(); - let cb: &IdleCallback = data.idle_cb.get_ref(); - let status = status_to_maybe_uv_error(status); - (*cb)(idle_watcher, status); + assert!(self.get_watcher_data().idle_cb.is_some()); + assert_eq!(uvll::idle_start(self.native_handle(), idle_cb), 0) } } @@ -68,7 +53,7 @@ impl IdleWatcher { // free unsafe { - assert!(0 == uvll::idle_stop(self.native_handle())); + assert_eq!(uvll::idle_stop(self.native_handle()), 0); } } } @@ -82,6 +67,14 @@ impl NativeHandle<*uvll::uv_idle_t> for IdleWatcher { } } +extern fn idle_cb(handle: *uvll::uv_idle_t, status: c_int) { + let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle); + let data = idle_watcher.get_watcher_data(); + let cb: &IdleCallback = data.idle_cb.get_ref(); + let status = status_to_maybe_uv_error(status); + (*cb)(idle_watcher, status); +} + #[cfg(test)] mod test { diff --git a/src/libstd/rt/uv/signal.rs b/src/libstd/rt/uv/signal.rs index e51b7d90d9550..3252c89673d6b 100644 --- a/src/libstd/rt/uv/signal.rs +++ b/src/libstd/rt/uv/signal.rs @@ -51,7 +51,7 @@ impl SignalWatcher { let mut watcher: SignalWatcher = NativeHandle::from_native_handle(handle); let data = watcher.get_watcher_data(); let cb = data.signal_cb.get_ref(); - (*cb)(watcher, unsafe { cast::transmute(signum as i64) }); + (*cb)(watcher, unsafe { cast::transmute(signum as int) }); } } diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 473eec32c67eb..29370c484eb5a 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -547,10 +547,10 @@ impl IoFactory for UvIoFactory { Ok(~UvTimer::new(watcher, home) as ~RtioTimer) } - fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileStream { + fn fs_from_raw_fd(&mut self, fd: c_int, close: CloseBehavior) -> ~RtioFileStream { let loop_ = Loop {handle: self.uv_loop().native_handle()}; let home = get_handle_to_current_scheduler!(); - ~UvFileStream::new(loop_, fd, close_on_drop, home) as ~RtioFileStream + ~UvFileStream::new(loop_, fd, close, home) as ~RtioFileStream } fn fs_open(&mut self, path: &CString, fm: FileMode, fa: FileAccess) @@ -590,7 +590,7 @@ impl IoFactory for UvIoFactory { let home = get_handle_to_current_scheduler!(); let fd = req.get_result() as c_int; let fs = ~UvFileStream::new( - loop_, fd, true, home) as ~RtioFileStream; + loop_, fd, CloseSynchronously, home) as ~RtioFileStream; let res = Ok(fs); unsafe { (*result_cell_ptr).put_back(res); } let scheduler: ~Scheduler = Local::take(); @@ -1482,8 +1482,8 @@ impl RtioTimer for UvTimer { pub struct UvFileStream { priv loop_: Loop, priv fd: c_int, - priv close_on_drop: bool, - priv home: SchedHandle + priv close: CloseBehavior, + priv home: SchedHandle, } impl HomingIO for UvFileStream { @@ -1491,13 +1491,13 @@ impl HomingIO for UvFileStream { } impl UvFileStream { - fn new(loop_: Loop, fd: c_int, close_on_drop: bool, + fn new(loop_: Loop, fd: c_int, close: CloseBehavior, home: SchedHandle) -> UvFileStream { UvFileStream { loop_: loop_, fd: fd, - close_on_drop: close_on_drop, - home: home + close: close, + home: home, } } fn base_read(&mut self, buf: &mut [u8], offset: i64) -> Result { @@ -1517,9 +1517,9 @@ impl UvFileStream { unsafe { (*result_cell_ptr).put_back(res); } let scheduler: ~Scheduler = Local::take(); scheduler.resume_blocked_task_immediately(task_cell.take()); - }; - }; - }; + } + } + } result_cell.take() } fn base_write(&mut self, buf: &[u8], offset: i64) -> Result<(), IoError> { @@ -1539,9 +1539,9 @@ impl UvFileStream { unsafe { (*result_cell_ptr).put_back(res); } let scheduler: ~Scheduler = Local::take(); scheduler.resume_blocked_task_immediately(task_cell.take()); - }; - }; - }; + } + } + } result_cell.take() } fn seek_common(&mut self, pos: i64, whence: c_int) -> @@ -1564,16 +1564,23 @@ impl UvFileStream { impl Drop for UvFileStream { fn drop(&mut self) { - if self.close_on_drop { - do self.home_for_io_with_sched |self_, scheduler| { - do scheduler.deschedule_running_task_and_then |_, task| { - let task_cell = Cell::new(task); - let close_req = file::FsRequest::new(); - do close_req.close(&self_.loop_, self_.fd) |_,_| { - let scheduler: ~Scheduler = Local::take(); - scheduler.resume_blocked_task_immediately(task_cell.take()); - }; - }; + match self.close { + DontClose => {} + CloseAsynchronously => { + let close_req = file::FsRequest::new(); + do close_req.close(&self.loop_, self.fd) |_,_| {} + } + CloseSynchronously => { + do self.home_for_io_with_sched |self_, scheduler| { + do scheduler.deschedule_running_task_and_then |_, task| { + let task_cell = Cell::new(task); + let close_req = file::FsRequest::new(); + do close_req.close(&self_.loop_, self_.fd) |_,_| { + let scheduler: ~Scheduler = Local::take(); + scheduler.resume_blocked_task_immediately(task_cell.take()); + } + } + } } } } @@ -1750,7 +1757,6 @@ impl Drop for UvTTY { // scheduler isn't available, so we can't do the normal "take the // scheduler and resume once close is done". Instead close operations on // a TTY are asynchronous. - self.tty.close_async(); } } @@ -2465,7 +2471,7 @@ fn uvio_naive_print(input: &str) { use libc::{STDOUT_FILENO}; let io = local_io(); { - let mut fd = io.fs_from_raw_fd(STDOUT_FILENO, false); + let mut fd = io.fs_from_raw_fd(STDOUT_FILENO, DontClose); let write_buf = input.as_bytes(); fd.write(write_buf); } diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index fa4083657d591..75e6a0c6ca552 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -235,37 +235,37 @@ pub type socklen_t = c_int; #[cfg(target_os = "android")] #[cfg(target_os = "linux")] pub struct addrinfo { - priv ai_flags: c_int, - priv ai_family: c_int, - priv ai_socktype: c_int, - priv ai_protocol: c_int, - priv ai_addrlen: socklen_t, + ai_flags: c_int, + ai_family: c_int, + ai_socktype: c_int, + ai_protocol: c_int, + ai_addrlen: socklen_t, ai_addr: *sockaddr, - priv ai_canonname: *char, + ai_canonname: *char, ai_next: *addrinfo } #[cfg(target_os = "macos")] #[cfg(target_os = "freebsd")] pub struct addrinfo { - priv ai_flags: c_int, - priv ai_family: c_int, - priv ai_socktype: c_int, - priv ai_protocol: c_int, - priv ai_addrlen: socklen_t, - priv ai_canonname: *char, + ai_flags: c_int, + ai_family: c_int, + ai_socktype: c_int, + ai_protocol: c_int, + ai_addrlen: socklen_t, + ai_canonname: *char, ai_addr: *sockaddr, ai_next: *addrinfo } #[cfg(windows)] pub struct addrinfo { - priv ai_flags: c_int, - priv ai_family: c_int, - priv ai_socktype: c_int, - priv ai_protocol: c_int, - priv ai_addrlen: size_t, - priv ai_canonname: *char, + ai_flags: c_int, + ai_family: c_int, + ai_socktype: c_int, + ai_protocol: c_int, + ai_addrlen: size_t, + ai_canonname: *char, ai_addr: *sockaddr, ai_next: *addrinfo } @@ -423,18 +423,6 @@ pub unsafe fn walk(loop_handle: *c_void, cb: uv_walk_cb, arg: *c_void) { rust_uv_walk(loop_handle, cb, arg); } -pub unsafe fn idle_new() -> *uv_idle_t { - #[fixed_stack_segment]; #[inline(never)]; - - rust_uv_idle_new() -} - -pub unsafe fn idle_delete(handle: *uv_idle_t) { - #[fixed_stack_segment]; #[inline(never)]; - - rust_uv_idle_delete(handle) -} - pub unsafe fn idle_init(loop_handle: *uv_loop_t, handle: *uv_idle_t) -> c_int { #[fixed_stack_segment]; #[inline(never)]; @@ -1028,8 +1016,6 @@ extern { fn rust_uv_close(handle: *c_void, cb: uv_close_cb); fn rust_uv_walk(loop_handle: *c_void, cb: uv_walk_cb, arg: *c_void); - fn rust_uv_idle_new() -> *uv_idle_t; - fn rust_uv_idle_delete(handle: *uv_idle_t); fn rust_uv_idle_init(loop_handle: *uv_loop_t, handle: *uv_idle_t) -> c_int; fn rust_uv_idle_start(handle: *uv_idle_t, cb: uv_idle_cb) -> c_int; fn rust_uv_idle_stop(handle: *uv_idle_t) -> c_int; diff --git a/src/libstd/run.rs b/src/libstd/run.rs index 650ef491a3bff..615ba60e066c0 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -219,16 +219,27 @@ impl Process { let (p, ch) = stream(); let ch = SharedChan::new(ch); let ch_clone = ch.clone(); - do task::spawn_sched(task::SingleThreaded) { - match error.take() { - Some(ref mut e) => ch.send((2, e.read_to_end())), - None => ch.send((2, ~[])) + + // FIXME(#910, #8674): right now I/O is incredibly brittle when it comes + // to linked failure, so these tasks must be spawn so they're not + // affected by linked failure. If these are removed, then the + // runtime may never exit because linked failure will cause some + // SchedHandle structures to not get destroyed, meaning that + // there's always an async watcher available. + do task::spawn_unlinked { + do io::ignore_io_error { + match error.take() { + Some(ref mut e) => ch.send((2, e.read_to_end())), + None => ch.send((2, ~[])) + } } } - do task::spawn_sched(task::SingleThreaded) { - match output.take() { - Some(ref mut e) => ch_clone.send((1, e.read_to_end())), - None => ch_clone.send((1, ~[])) + do task::spawn_unlinked { + do io::ignore_io_error { + match output.take() { + Some(ref mut e) => ch_clone.send((1, e.read_to_end())), + None => ch_clone.send((1, ~[])) + } } } diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index c463cf039d306..0cbbb58d02c66 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -466,16 +466,6 @@ rust_uv_addrinfo_as_sockaddr_in6(addrinfo* input) { return (sockaddr_in6*)input->ai_addr; } -extern "C" uv_idle_t* -rust_uv_idle_new() { - return new uv_idle_t; -} - -extern "C" void -rust_uv_idle_delete(uv_idle_t* handle) { - delete handle; -} - extern "C" int rust_uv_idle_init(uv_loop_t* loop, uv_idle_t* idle) { return uv_idle_init(loop, idle); diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 3c10e42f74384..269da8e7882ac 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -98,8 +98,6 @@ rust_uv_get_base_from_buf rust_uv_get_len_from_buf rust_uv_getaddrinfo rust_uv_freeaddrinfo -rust_uv_idle_new -rust_uv_idle_delete rust_uv_idle_init rust_uv_idle_start rust_uv_idle_stop