diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2014-01-29 16:33:57 -0800 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2014-02-03 09:32:33 -0800 |
| commit | ece8a8f520697be50cbe543bebe065c5198dae4d (patch) | |
| tree | fa1bf049d3b5d781c8c56e0d0491a655ece485a2 /src/libstd/io | |
| parent | be4fc638092bf896c5c6c0672136b83b71e491ee (diff) | |
| download | rust-ece8a8f520697be50cbe543bebe065c5198dae4d.tar.gz rust-ece8a8f520697be50cbe543bebe065c5198dae4d.zip | |
std: Remove io::io_error
* All I/O now returns IoResult<T> = Result<T, IoError> * All formatting traits now return fmt::Result = IoResult<()> * The if_ok!() macro was added to libstd
Diffstat (limited to 'src/libstd/io')
| -rw-r--r-- | src/libstd/io/buffered.rs | 80 | ||||
| -rw-r--r-- | src/libstd/io/comm_adapters.rs | 17 | ||||
| -rw-r--r-- | src/libstd/io/extensions.rs | 2 | ||||
| -rw-r--r-- | src/libstd/io/fs.rs | 359 | ||||
| -rw-r--r-- | src/libstd/io/mem.rs | 61 | ||||
| -rw-r--r-- | src/libstd/io/mod.rs | 440 | ||||
| -rw-r--r-- | src/libstd/io/net/addrinfo.rs | 7 | ||||
| -rw-r--r-- | src/libstd/io/net/tcp.rs | 82 | ||||
| -rw-r--r-- | src/libstd/io/net/udp.rs | 49 | ||||
| -rw-r--r-- | src/libstd/io/net/unix.rs | 60 | ||||
| -rw-r--r-- | src/libstd/io/pipe.rs | 26 | ||||
| -rw-r--r-- | src/libstd/io/process.rs | 15 | ||||
| -rw-r--r-- | src/libstd/io/result.rs (renamed from src/libstd/io/option.rs) | 74 | ||||
| -rw-r--r-- | src/libstd/io/signal.rs | 13 | ||||
| -rw-r--r-- | src/libstd/io/stdio.rs | 76 | ||||
| -rw-r--r-- | src/libstd/io/timer.rs | 7 | ||||
| -rw-r--r-- | src/libstd/io/util.rs | 64 |
17 files changed, 630 insertions, 802 deletions
diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 64e42c5480f..5e64862cbec 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -11,10 +11,11 @@ //! Buffering wrappers for I/O traits use container::Container; -use io::{Reader, Writer, Stream, Buffer, DEFAULT_BUF_SIZE}; +use io::{Reader, Writer, Stream, Buffer, DEFAULT_BUF_SIZE, IoResult}; use iter::ExactSize; use num; -use option::{Option, Some, None}; +use option::{Some, None}; +use result::{Ok, Err}; use vec::{OwnedVector, ImmutableVector, MutableVector}; use vec; @@ -86,17 +87,12 @@ impl<R: Reader> BufferedReader<R> { } impl<R: Reader> Buffer for BufferedReader<R> { - fn fill<'a>(&'a mut self) -> &'a [u8] { - if self.pos == self.cap { - match self.inner.read(self.buf) { - Some(cap) => { - self.pos = 0; - self.cap = cap; - } - None => { self.eof = true; } - } + fn fill<'a>(&'a mut self) -> IoResult<&'a [u8]> { + while self.pos == self.cap { + self.cap = if_ok!(self.inner.read(self.buf)); + self.pos = 0; } - return self.buf.slice(self.pos, self.cap); + Ok(self.buf.slice(self.pos, self.cap)) } fn consume(&mut self, amt: uint) { @@ -106,18 +102,15 @@ impl<R: Reader> Buffer for BufferedReader<R> { } impl<R: Reader> Reader for BufferedReader<R> { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { let nread = { - let available = self.fill(); + let available = if_ok!(self.fill()); let nread = num::min(available.len(), buf.len()); vec::bytes::copy_memory(buf, available.slice_to(nread)); nread }; self.pos += nread; - if nread == 0 && buf.len() != 0 && self.eof { - return None; - } - Some(nread) + Ok(nread) } } @@ -161,10 +154,13 @@ impl<W: Writer> BufferedWriter<W> { BufferedWriter::with_capacity(DEFAULT_BUF_SIZE, inner) } - fn flush_buf(&mut self) { + fn flush_buf(&mut self) -> IoResult<()> { if self.pos != 0 { - self.inner.write(self.buf.slice_to(self.pos)); + let ret = self.inner.write(self.buf.slice_to(self.pos)); self.pos = 0; + ret + } else { + Ok(()) } } @@ -178,29 +174,30 @@ impl<W: Writer> BufferedWriter<W> { /// /// The buffer is flushed before returning the writer. pub fn unwrap(mut self) -> W { - self.flush_buf(); + // FIXME: is failing the right thing to do if flushing fails? + self.flush_buf().unwrap(); self.inner } } impl<W: Writer> Writer for BufferedWriter<W> { - fn write(&mut self, buf: &[u8]) { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { if self.pos + buf.len() > self.buf.len() { - self.flush_buf(); + if_ok!(self.flush_buf()); } if buf.len() > self.buf.len() { - self.inner.write(buf); + self.inner.write(buf) } else { let dst = self.buf.mut_slice_from(self.pos); vec::bytes::copy_memory(dst, buf); self.pos += buf.len(); + Ok(()) } } - fn flush(&mut self) { - self.flush_buf(); - self.inner.flush(); + fn flush(&mut self) -> IoResult<()> { + self.flush_buf().and_then(|()| self.inner.flush()) } } @@ -234,18 +231,19 @@ impl<W: Writer> LineBufferedWriter<W> { } impl<W: Writer> Writer for LineBufferedWriter<W> { - fn write(&mut self, buf: &[u8]) { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { match buf.iter().rposition(|&b| b == '\n' as u8) { Some(i) => { - self.inner.write(buf.slice_to(i + 1)); - self.inner.flush(); - self.inner.write(buf.slice_from(i + 1)); + if_ok!(self.inner.write(buf.slice_to(i + 1))); + if_ok!(self.inner.flush()); + if_ok!(self.inner.write(buf.slice_from(i + 1))); + Ok(()) } None => self.inner.write(buf), } } - fn flush(&mut self) { self.inner.flush() } + fn flush(&mut self) -> IoResult<()> { self.inner.flush() } } struct InternalBufferedWriter<W>(BufferedWriter<W>); @@ -258,7 +256,9 @@ impl<W> InternalBufferedWriter<W> { } impl<W: Reader> Reader for InternalBufferedWriter<W> { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.get_mut_ref().inner.read(buf) } + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { + self.get_mut_ref().inner.read(buf) + } } /// Wraps a Stream and buffers input and output to and from it @@ -326,17 +326,23 @@ impl<S: Stream> BufferedStream<S> { } impl<S: Stream> Buffer for BufferedStream<S> { - fn fill<'a>(&'a mut self) -> &'a [u8] { self.inner.fill() } + fn fill<'a>(&'a mut self) -> IoResult<&'a [u8]> { self.inner.fill() } fn consume(&mut self, amt: uint) { self.inner.consume(amt) } } impl<S: Stream> Reader for BufferedStream<S> { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.inner.read(buf) } + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { + self.inner.read(buf) + } } impl<S: Stream> Writer for BufferedStream<S> { - fn write(&mut self, buf: &[u8]) { self.inner.inner.get_mut_ref().write(buf) } - fn flush(&mut self) { self.inner.inner.get_mut_ref().flush() } + fn write(&mut self, buf: &[u8]) -> IoResult<()> { + self.inner.inner.get_mut_ref().write(buf) + } + fn flush(&mut self) -> IoResult<()> { + self.inner.inner.get_mut_ref().flush() + } } #[cfg(test)] diff --git a/src/libstd/io/comm_adapters.rs b/src/libstd/io/comm_adapters.rs index 1eaa752d2a3..e86ad50d690 100644 --- a/src/libstd/io/comm_adapters.rs +++ b/src/libstd/io/comm_adapters.rs @@ -14,7 +14,7 @@ use comm::{Port, Chan}; use cmp; use io; use option::{None, Option, Some}; -use super::{Reader, Writer}; +use super::{Reader, Writer, IoResult}; use vec::{bytes, CloneableVector, MutableVector, ImmutableVector}; /// Allows reading from a port. @@ -49,7 +49,7 @@ impl PortReader { } impl Reader for PortReader { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { let mut num_read = 0; loop { match self.buf { @@ -71,10 +71,9 @@ impl Reader for PortReader { self.closed = self.buf.is_none(); } if self.closed && num_read == 0 { - io::io_error::cond.raise(io::standard_error(io::EndOfFile)); - None + Err(io::standard_error(io::EndOfFile)) } else { - Some(num_read) + Ok(num_read) } } } @@ -98,13 +97,15 @@ impl ChanWriter { } impl Writer for ChanWriter { - fn write(&mut self, buf: &[u8]) { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { if !self.chan.try_send(buf.to_owned()) { - io::io_error::cond.raise(io::IoError { + Err(io::IoError { kind: io::BrokenPipe, desc: "Pipe closed", detail: None - }); + }) + } else { + Ok(()) } } } diff --git a/src/libstd/io/extensions.rs b/src/libstd/io/extensions.rs index 548dc3efe92..7e1dbcaeade 100644 --- a/src/libstd/io/extensions.rs +++ b/src/libstd/io/extensions.rs @@ -46,7 +46,7 @@ impl<'r, R: Reader> Bytes<'r, R> { impl<'r, R: Reader> Iterator<u8> for Bytes<'r, R> { #[inline] fn next(&mut self) -> Option<u8> { - self.reader.read_byte() + self.reader.read_byte().ok() } } diff --git a/src/libstd/io/fs.rs b/src/libstd/io/fs.rs index 8904101dd05..867e0ebd6ee 100644 --- a/src/libstd/io/fs.rs +++ b/src/libstd/io/fs.rs @@ -27,21 +27,25 @@ particular bits of it, etc. # Example - use std::io::{File, fs}; +```rust +# #[allow(unused_must_use)]; +use std::io::{File, fs}; - let path = Path::new("foo.txt"); +let path = Path::new("foo.txt"); - // create the file, whether it exists or not - let mut file = File::create(&path); - file.write(bytes!("foobar")); +// create the file, whether it exists or not +let mut file = File::create(&path); +file.write(bytes!("foobar")); +# drop(file); - // open the file in read-only mode - let mut file = File::open(&path); - file.read_to_end(); +// open the file in read-only mode +let mut file = File::open(&path); +file.read_to_end(); - println!("{}", path.stat().size); - fs::symlink(&path, &Path::new("bar.txt")); - fs::unlink(&path); +println!("{}", path.stat().size); +# drop(file); +fs::unlink(&path); +``` */ @@ -50,7 +54,7 @@ use clone::Clone; use iter::Iterator; use super::{Reader, Writer, Seek}; use super::{SeekStyle, Read, Write, Open, IoError, Truncate, - FileMode, FileAccess, FileStat, io_error, FilePermission}; + FileMode, FileAccess, FileStat, IoResult, FilePermission}; use rt::rtio::{RtioFileStream, IoFactory, LocalIo}; use io; use option::{Some, None, Option}; @@ -81,22 +85,19 @@ impl File { /// /// # Example /// - /// use std::io::{File, io_error, Open, ReadWrite}; + /// ```rust + /// use std::io::{File, Open, ReadWrite}; /// - /// let p = Path::new("/some/file/path.txt"); + /// let p = Path::new("/some/file/path.txt"); /// - /// io_error::cond.trap(|_| { - /// // hoo-boy... - /// }).inside(|| { - /// let file = match File::open_mode(&p, Open, ReadWrite) { - /// Some(s) => s, - /// None => fail!("whoops! I'm sure this raised, anyways..") - /// }; - /// // do some stuff with that file + /// let file = match File::open_mode(&p, Open, ReadWrite) { + /// Ok(f) => f, + /// Err(e) => fail!("file error: {}", e), + /// }; + /// // do some stuff with that file /// - /// // the file will be closed at the end of this block - /// }) - /// // .. + /// // the file will be closed at the end of this block + /// ``` /// /// `FileMode` and `FileAccess` provide information about the permissions /// context in which a given stream is created. More information about them @@ -119,7 +120,7 @@ impl File { /// * Filesystem-level errors (full disk, etc) pub fn open_mode(path: &Path, mode: FileMode, - access: FileAccess) -> Option<File> { + access: FileAccess) -> IoResult<File> { LocalIo::maybe_raise(|io| { io.fs_open(&path.to_c_str(), mode, access).map(|fd| { File { @@ -139,10 +140,12 @@ impl File { /// /// # Example /// - /// use std::io::File; + /// ```rust + /// use std::io::File; /// - /// let contents = File::open(&Path::new("foo.txt")).read_to_end(); - pub fn open(path: &Path) -> Option<File> { + /// let contents = File::open(&Path::new("foo.txt")).read_to_end(); + /// ``` + pub fn open(path: &Path) -> IoResult<File> { File::open_mode(path, Open, Read) } @@ -154,11 +157,16 @@ impl File { /// /// # Example /// - /// use std::io::File; + /// ```rust + /// # #[allow(unused_must_use)]; + /// use std::io::File; /// - /// let mut f = File::create(&Path::new("foo.txt")); - /// f.write(bytes!("This is a sample file")); - pub fn create(path: &Path) -> Option<File> { + /// let mut f = File::create(&Path::new("foo.txt")); + /// f.write(bytes!("This is a sample file")); + /// # drop(f); + /// # ::std::io::fs::unlnk(&Path::new("foo.txt")); + /// ``` + pub fn create(path: &Path) -> IoResult<File> { File::open_mode(path, Truncate, Write) } @@ -174,8 +182,8 @@ impl File { /// # Errors /// /// This function will raise on the `io_error` condition on failure. - pub fn fsync(&mut self) { - let _ = self.fd.fsync().map_err(|e| io_error::cond.raise(e)); + pub fn fsync(&mut self) -> IoResult<()> { + self.fd.fsync() } /// This function is similar to `fsync`, except that it may not synchronize @@ -186,8 +194,8 @@ impl File { /// # Errors /// /// This function will raise on the `io_error` condition on failure. - pub fn datasync(&mut self) { - let _ = self.fd.datasync().map_err(|e| io_error::cond.raise(e)); + pub fn datasync(&mut self) -> IoResult<()> { + self.fd.datasync() } /// Either truncates or extends the underlying file, updating the size of @@ -202,8 +210,8 @@ impl File { /// # Errors /// /// On error, this function will raise on the `io_error` condition. - pub fn truncate(&mut self, size: i64) { - let _ = self.fd.truncate(size).map_err(|e| io_error::cond.raise(e)); + pub fn truncate(&mut self, size: i64) -> IoResult<()> { + self.fd.truncate(size) } /// Tests whether this stream has reached EOF. @@ -219,12 +227,13 @@ impl File { /// /// # Example /// -/// use std::io::fs; +/// ```rust +/// # #[allow(unused_must_use)]; +/// use std::io::fs; /// -/// let p = Path::new("/some/file/path.txt"); -/// fs::unlink(&p); -/// // if we made it here without failing, then the -/// // unlink operation was successful +/// let p = Path::new("/some/file/path.txt"); +/// fs::unlink(&p); +/// ``` /// /// Note that, just because an unlink call was successful, it is not /// guaranteed that a file is immediately deleted (e.g. depending on @@ -235,8 +244,8 @@ impl File { /// This function will raise an `io_error` condition if the path points to a /// directory, the user lacks permissions to remove the file, or if some /// other filesystem-level error occurs. -pub fn unlink(path: &Path) { - LocalIo::maybe_raise(|io| io.fs_unlink(&path.to_c_str())); +pub fn unlink(path: &Path) -> IoResult<()> { + LocalIo::maybe_raise(|io| io.fs_unlink(&path.to_c_str())) } /// Given a path, query the file system to get information about a file, @@ -249,48 +258,26 @@ pub fn unlink(path: &Path) { /// /// # Example /// -/// use std::io; -/// use std::io::fs; +/// ```rust +/// use std::io; +/// use std::io::fs; /// -/// let p = Path::new("/some/file/path.txt"); -/// match io::result(|| fs::stat(&p)) { -/// Ok(stat) => { /* ... */ } -/// Err(e) => { /* handle error */ } -/// } +/// let p = Path::new("/some/file/path.txt"); +/// match fs::stat(&p) { +/// Ok(stat) => { /* ... */ } +/// Err(e) => { /* handle error */ } +/// } +/// ``` /// /// # Errors /// /// 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: &Path) -> FileStat { +pub fn stat(path: &Path) -> IoResult<FileStat> { LocalIo::maybe_raise(|io| { io.fs_stat(&path.to_c_str()) - }).unwrap_or_else(dummystat) -} - -fn dummystat() -> FileStat { - FileStat { - path: Path::new(""), - size: 0, - kind: io::TypeFile, - perm: 0, - created: 0, - modified: 0, - accessed: 0, - unstable: io::UnstableFileStat { - device: 0, - inode: 0, - rdev: 0, - nlink: 0, - uid: 0, - gid: 0, - blksize: 0, - blocks: 0, - flags: 0, - gen: 0, - } - } + }) } /// Perform the same operation as the `stat` function, except that this @@ -301,28 +288,30 @@ fn dummystat() -> FileStat { /// # Errors /// /// See `stat` -pub fn lstat(path: &Path) -> FileStat { +pub fn lstat(path: &Path) -> IoResult<FileStat> { LocalIo::maybe_raise(|io| { io.fs_lstat(&path.to_c_str()) - }).unwrap_or_else(dummystat) + }) } /// Rename a file or directory to a new name. /// /// # Example /// -/// use std::io::fs; +/// ```rust +/// # #[allow(unused_must_use)]; +/// use std::io::fs; /// -/// fs::rename(&Path::new("foo"), &Path::new("bar")); -/// // Oh boy, nothing was raised! +/// fs::rename(&Path::new("foo"), &Path::new("bar")); +/// ``` /// /// # Errors /// /// Will raise an `io_error` condition if the provided `path` doesn't exist, /// the process lacks permissions to view the contents, or if some other /// intermittent I/O error occurs. -pub fn rename(from: &Path, to: &Path) { - LocalIo::maybe_raise(|io| io.fs_rename(&from.to_c_str(), &to.to_c_str())); +pub fn rename(from: &Path, to: &Path) -> IoResult<()> { + LocalIo::maybe_raise(|io| io.fs_rename(&from.to_c_str(), &to.to_c_str())) } /// Copies the contents of one file to another. This function will also @@ -333,10 +322,12 @@ pub fn rename(from: &Path, to: &Path) { /// /// # Example /// -/// use std::io::fs; +/// ```rust +/// # #[allow(unused_must_use)]; +/// use std::io::fs; /// -/// fs::copy(&Path::new("foo.txt"), &Path::new("bar.txt")); -/// // Oh boy, nothing was raised! +/// fs::copy(&Path::new("foo.txt"), &Path::new("bar.txt")); +/// ``` /// /// # Errors /// @@ -351,27 +342,29 @@ pub fn rename(from: &Path, to: &Path) { /// Note that this copy is not atomic in that once the destination is /// ensured to not exist, there is nothing preventing the destination from /// being created and then destroyed by this operation. -pub fn copy(from: &Path, to: &Path) { +pub fn copy(from: &Path, to: &Path) -> IoResult<()> { if !from.is_file() { - return io_error::cond.raise(IoError { + return Err(IoError { kind: io::MismatchedFileTypeForOperation, desc: "the source path is not an existing file", detail: None, - }); + }) } - let mut reader = match File::open(from) { Some(f) => f, None => return }; - let mut writer = match File::create(to) { Some(f) => f, None => return }; + let mut reader = if_ok!(File::open(from)); + let mut writer = if_ok!(File::create(to)); let mut buf = [0, ..io::DEFAULT_BUF_SIZE]; loop { - match reader.read(buf) { - Some(amt) => writer.write(buf.slice_to(amt)), - None => break - } + let amt = match reader.read(buf) { + Ok(n) => n, + Err(ref e) if e.kind == io::EndOfFile => { break } + Err(e) => return Err(e) + }; + if_ok!(writer.write(buf.slice_to(amt))); } - chmod(to, from.stat().perm) + chmod(to, if_ok!(from.stat()).perm) } /// Changes the permission mode bits found on a file or a directory. This @@ -379,21 +372,24 @@ pub fn copy(from: &Path, to: &Path) { /// /// # Example /// -/// use std::io; -/// use std::io::fs; +/// ```rust +/// # #[allow(unused_must_use)] +/// use std::io; +/// use std::io::fs; /// -/// fs::chmod(&Path::new("file.txt"), io::UserFile); -/// fs::chmod(&Path::new("file.txt"), io::UserRead | io::UserWrite); -/// fs::chmod(&Path::new("dir"), io::UserDir); -/// fs::chmod(&Path::new("file.exe"), io::UserExec); +/// fs::chmod(&Path::new("file.txt"), io::UserFile); +/// fs::chmod(&Path::new("file.txt"), io::UserRead | io::UserWrite); +/// fs::chmod(&Path::new("dir"), io::UserDir); +/// fs::chmod(&Path::new("file.exe"), io::UserExec); +/// ``` /// /// # Errors /// /// If this function encounters an I/O error, it will raise on the `io_error` /// condition. Some possible error situations are not having the permission to /// change the attributes of a file or the file not existing. -pub fn chmod(path: &Path, mode: io::FilePermission) { - LocalIo::maybe_raise(|io| io.fs_chmod(&path.to_c_str(), mode)); +pub fn chmod(path: &Path, mode: io::FilePermission) -> IoResult<()> { + LocalIo::maybe_raise(|io| io.fs_chmod(&path.to_c_str(), mode)) } /// Change the user and group owners of a file at the specified path. @@ -401,8 +397,8 @@ pub fn chmod(path: &Path, mode: io::FilePermission) { /// # Errors /// /// This function will raise on the `io_error` condition on failure. -pub fn chown(path: &Path, uid: int, gid: int) { - LocalIo::maybe_raise(|io| io.fs_chown(&path.to_c_str(), uid, gid)); +pub fn chown(path: &Path, uid: int, gid: int) -> IoResult<()> { + LocalIo::maybe_raise(|io| io.fs_chown(&path.to_c_str(), uid, gid)) } /// Creates a new hard link on the filesystem. The `dst` path will be a @@ -412,8 +408,8 @@ pub fn chown(path: &Path, uid: int, gid: int) { /// # Errors /// /// This function will raise on the `io_error` condition on failure. -pub fn link(src: &Path, dst: &Path) { - LocalIo::maybe_raise(|io| io.fs_link(&src.to_c_str(), &dst.to_c_str())); +pub fn link(src: &Path, dst: &Path) -> IoResult<()> { + LocalIo::maybe_raise(|io| io.fs_link(&src.to_c_str(), &dst.to_c_str())) } /// Creates a new symbolic link on the filesystem. The `dst` path will be a @@ -422,8 +418,8 @@ pub fn link(src: &Path, dst: &Path) { /// # Errors /// /// This function will raise on the `io_error` condition on failure. -pub fn symlink(src: &Path, dst: &Path) { - LocalIo::maybe_raise(|io| io.fs_symlink(&src.to_c_str(), &dst.to_c_str())); +pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> { + LocalIo::maybe_raise(|io| io.fs_symlink(&src.to_c_str(), &dst.to_c_str())) } /// Reads a symlink, returning the file that the symlink points to. @@ -433,7 +429,7 @@ pub fn symlink(src: &Path, dst: &Path) { /// This function will raise on the `io_error` condition on failure. Failure /// conditions include reading a file that does not exist or reading a file /// which is not a symlink. -pub fn readlink(path: &Path) -> Option<Path> { +pub fn readlink(path: &Path) -> IoResult<Path> { LocalIo::maybe_raise(|io| io.fs_readlink(&path.to_c_str())) } @@ -441,75 +437,81 @@ pub fn readlink(path: &Path) -> Option<Path> { /// /// # Example /// -/// use std::libc::S_IRWXU; -/// use std::io::fs; +/// ```rust +/// # #[allow(unused_must_use)]; +/// use std::io; +/// use std::io::fs; /// -/// let p = Path::new("/some/dir"); -/// fs::mkdir(&p, S_IRWXU as int); -/// // If we got here, our directory exists! Hooray! +/// let p = Path::new("/some/dir"); +/// fs::mkdir(&p, io::UserRWX); +/// ``` /// /// # Errors /// /// 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: &Path, mode: FilePermission) { - LocalIo::maybe_raise(|io| io.fs_mkdir(&path.to_c_str(), mode)); +pub fn mkdir(path: &Path, mode: FilePermission) -> IoResult<()> { + LocalIo::maybe_raise(|io| io.fs_mkdir(&path.to_c_str(), mode)) } /// Remove an existing, empty directory /// /// # Example /// -/// use std::io::fs; +/// ```rust +/// # #[allow(unused_must_use)]; +/// use std::io::fs; /// -/// let p = Path::new("/some/dir"); -/// fs::rmdir(&p); -/// // good riddance, you mean ol' directory +/// let p = Path::new("/some/dir"); +/// fs::rmdir(&p); +/// ``` /// /// # Errors /// /// 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: &Path) { - LocalIo::maybe_raise(|io| io.fs_rmdir(&path.to_c_str())); +pub fn rmdir(path: &Path) -> IoResult<()> { + LocalIo::maybe_raise(|io| io.fs_rmdir(&path.to_c_str())) } /// Retrieve a vector containing all entries within a provided directory /// /// # Example /// -/// use std::io::fs; +/// ```rust +/// use std::io::fs; /// -/// // one possible implementation of fs::walk_dir only visiting files -/// fn visit_dirs(dir: &Path, cb: |&Path|) { -/// if dir.is_dir() { -/// let contents = fs::readdir(dir).unwrap(); -/// for entry in contents.iter() { -/// if entry.is_dir() { visit_dirs(entry, cb); } -/// else { cb(entry); } -/// } +/// // one possible implementation of fs::walk_dir only visiting files +/// fn visit_dirs(dir: &Path, cb: |&Path|) { +/// if dir.is_dir() { +/// let contents = fs::readdir(dir).unwrap(); +/// for entry in contents.iter() { +/// if entry.is_dir() { visit_dirs(entry, cb); } +/// else { cb(entry); } /// } -/// else { fail!("nope"); } /// } +/// else { fail!("nope"); } +/// } +/// ``` /// /// # Errors /// /// Will raise an `io_error` condition if the provided `from` 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: &Path) -> ~[Path] { +pub fn readdir(path: &Path) -> IoResult<~[Path]> { LocalIo::maybe_raise(|io| { io.fs_readdir(&path.to_c_str(), 0) - }).unwrap_or_else(|| ~[]) + }) } /// Returns an iterator which will recursively walk the directory structure /// rooted at `path`. The path given will not be iterated over, and this will /// perform iteration in a top-down order. -pub fn walk_dir(path: &Path) -> Directories { - Directories { stack: readdir(path) } +pub fn walk_dir(path: &Path) -> IoResult<Directories> { + Ok(Directories { stack: if_ok!(readdir(path)) }) } /// An iterator which walks over a directory @@ -522,7 +524,10 @@ impl Iterator<Path> for Directories { match self.stack.shift() { Some(path) => { if path.is_dir() { - self.stack.push_all_move(readdir(&path)); + match readdir(&path) { + Ok(dirs) => { self.stack.push_all_move(dirs); } + Err(..) => {} + } } Some(path) } @@ -539,14 +544,14 @@ impl Iterator<Path> for Directories { /// This function will raise on the `io_error` condition if an error /// happens, see `fs::mkdir` for more information about error conditions /// and performance. -pub fn mkdir_recursive(path: &Path, mode: FilePermission) { +pub fn mkdir_recursive(path: &Path, mode: FilePermission) -> IoResult<()> { // tjc: if directory exists but with different permissions, // should we return false? if path.is_dir() { - return + return Ok(()) } if path.filename().is_some() { - mkdir_recursive(&path.dir_path(), mode); + if_ok!(mkdir_recursive(&path.dir_path(), mode)); } mkdir(path, mode) } @@ -559,17 +564,17 @@ pub fn mkdir_recursive(path: &Path, mode: FilePermission) { /// This function will raise on the `io_error` condition if an error /// happens. See `file::unlink` and `fs::readdir` for possible error /// conditions. -pub fn rmdir_recursive(path: &Path) { - let children = readdir(path); +pub fn rmdir_recursive(path: &Path) -> IoResult<()> { + let children = if_ok!(readdir(path)); for child in children.iter() { if child.is_dir() { - rmdir_recursive(child); + if_ok!(rmdir_recursive(child)); } else { - unlink(child); + if_ok!(unlink(child)); } } // Directory should now be empty - rmdir(path); + rmdir(path) } /// Changes the timestamps for a file's last modification and access time. @@ -582,64 +587,42 @@ pub fn rmdir_recursive(path: &Path) { /// This function will raise on the `io_error` condition if an error /// happens. // FIXME(#10301) these arguments should not be u64 -pub fn change_file_times(path: &Path, atime: u64, mtime: u64) { - LocalIo::maybe_raise(|io| io.fs_utime(&path.to_c_str(), atime, mtime)); +pub fn change_file_times(path: &Path, atime: u64, mtime: u64) -> IoResult<()> { + LocalIo::maybe_raise(|io| io.fs_utime(&path.to_c_str(), atime, mtime)) } impl Reader for File { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { match self.fd.read(buf) { Ok(read) => { self.last_nread = read; match read { - 0 => None, - _ => Some(read as uint) + 0 => Err(io::standard_error(io::EndOfFile)), + _ => Ok(read as uint) } }, - Err(ioerr) => { - // EOF is indicated by returning None - if ioerr.kind != io::EndOfFile { - io_error::cond.raise(ioerr); - } - return None; - } + Err(e) => Err(e), } } } impl Writer for File { - fn write(&mut self, buf: &[u8]) { - match self.fd.write(buf) { - Ok(()) => (), - Err(ioerr) => { - io_error::cond.raise(ioerr); - } - } - } + fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.fd.write(buf) } } impl Seek for File { - fn tell(&self) -> u64 { - let res = self.fd.tell(); - match res { - Ok(cursor) => cursor, - Err(ioerr) => { - io_error::cond.raise(ioerr); - return -1; - } - } + fn tell(&self) -> IoResult<u64> { + self.fd.tell() } - fn seek(&mut self, pos: i64, style: SeekStyle) { + fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> { match self.fd.seek(pos, style) { Ok(_) => { // successful seek resets EOF indicator self.last_nread = -1; - () - }, - Err(ioerr) => { - io_error::cond.raise(ioerr); + Ok(()) } + Err(e) => Err(e), } } } @@ -650,7 +633,7 @@ impl path::Path { /// Consult the `file::stat` documentation for more info. /// /// This call preserves identical runtime/error semantics with `file::stat`. - pub fn stat(&self) -> FileStat { stat(self) } + pub fn stat(&self) -> IoResult<FileStat> { stat(self) } /// Boolean value indicator whether the underlying file exists on the local /// filesystem. This will return true if the path points to either a @@ -660,7 +643,7 @@ impl path::Path { /// /// Will not raise a condition pub fn exists(&self) -> bool { - io::result(|| self.stat()).is_ok() + self.stat().is_ok() } /// Whether the underlying implementation (be it a file path, or something @@ -672,7 +655,7 @@ impl path::Path { /// /// Will not raise a condition pub fn is_file(&self) -> bool { - match io::result(|| self.stat()) { + match self.stat() { Ok(s) => s.kind == io::TypeFile, Err(..) => false } @@ -687,7 +670,7 @@ impl path::Path { /// /// Will not raise a condition pub fn is_dir(&self) -> bool { - match io::result(|| self.stat()) { + match self.stat() { Ok(s) => s.kind == io::TypeDirectory, Err(..) => false } diff --git a/src/libstd/io/mem.rs b/src/libstd/io/mem.rs index c185951feca..f3535df5c5e 100644 --- a/src/libstd/io/mem.rs +++ b/src/libstd/io/mem.rs @@ -13,9 +13,10 @@ use cmp::max; use cmp::min; use container::Container; -use option::{Option, Some, None}; -use super::{Reader, Writer, Seek, Buffer, IoError, SeekStyle, io_error, - OtherIoError}; +use option::None; +use result::{Err, Ok}; +use io; +use io::{Reader, Writer, Seek, Buffer, IoError, SeekStyle, IoResult}; use vec; use vec::{Vector, ImmutableVector, MutableVector, OwnedCloneableVector}; @@ -59,7 +60,7 @@ impl MemWriter { } impl Writer for MemWriter { - fn write(&mut self, buf: &[u8]) { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { // 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; @@ -86,14 +87,15 @@ impl Writer for MemWriter { // Bump us forward self.pos += buf.len(); + Ok(()) } } // FIXME(#10432) impl Seek for MemWriter { - fn tell(&self) -> u64 { self.pos as u64 } + fn tell(&self) -> IoResult<u64> { Ok(self.pos as u64) } - fn seek(&mut self, pos: i64, style: SeekStyle) { + fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> { // compute offset as signed and clamp to prevent overflow let offset = match style { SeekSet => { 0 } @@ -102,6 +104,7 @@ impl Seek for MemWriter { } as i64; self.pos = max(0, offset+pos) as uint; + Ok(()) } } @@ -148,8 +151,8 @@ impl MemReader { } impl Reader for MemReader { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { - if self.eof() { return None } + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { + if self.eof() { return Err(io::standard_error(io::EndOfFile)) } let write_len = min(buf.len(), self.buf.len() - self.pos); { @@ -161,17 +164,19 @@ impl Reader for MemReader { self.pos += write_len; assert!(self.pos <= self.buf.len()); - return Some(write_len); + return Ok(write_len); } } impl Seek for MemReader { - fn tell(&self) -> u64 { self.pos as u64 } - fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } + fn tell(&self) -> IoResult<u64> { Ok(self.pos as u64) } + fn seek(&mut self, _pos: i64, _style: SeekStyle) -> IoResult<()> { fail!() } } impl Buffer for MemReader { - fn fill<'a>(&'a mut self) -> &'a [u8] { self.buf.slice_from(self.pos) } + fn fill<'a>(&'a mut self) -> IoResult<&'a [u8]> { + Ok(self.buf.slice_from(self.pos)) + } fn consume(&mut self, amt: uint) { self.pos += amt; } } @@ -207,28 +212,28 @@ impl<'a> BufWriter<'a> { } impl<'a> Writer for BufWriter<'a> { - fn write(&mut self, buf: &[u8]) { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { // raises a condition if the entire write does not fit in the buffer let max_size = self.buf.len(); if self.pos >= max_size || (self.pos + buf.len()) > max_size { - io_error::cond.raise(IoError { - kind: OtherIoError, + return Err(IoError { + kind: io::OtherIoError, desc: "Trying to write past end of buffer", detail: None - }); - return; + }) } vec::bytes::copy_memory(self.buf.mut_slice_from(self.pos), buf); self.pos += buf.len(); + Ok(()) } } // FIXME(#10432) impl<'a> Seek for BufWriter<'a> { - fn tell(&self) -> u64 { self.pos as u64 } + fn tell(&self) -> IoResult<u64> { Ok(self.pos as u64) } - fn seek(&mut self, pos: i64, style: SeekStyle) { + fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> { // compute offset as signed and clamp to prevent overflow let offset = match style { SeekSet => { 0 } @@ -237,6 +242,7 @@ impl<'a> Seek for BufWriter<'a> { } as i64; self.pos = max(0, offset+pos) as uint; + Ok(()) } } @@ -274,8 +280,8 @@ impl<'a> BufReader<'a> { } impl<'a> Reader for BufReader<'a> { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { - if self.eof() { return None } + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { + if self.eof() { return Err(io::standard_error(io::EndOfFile)) } let write_len = min(buf.len(), self.buf.len() - self.pos); { @@ -287,18 +293,19 @@ impl<'a> Reader for BufReader<'a> { self.pos += write_len; assert!(self.pos <= self.buf.len()); - return Some(write_len); + return Ok(write_len); } } impl<'a> Seek for BufReader<'a> { - fn tell(&self) -> u64 { self.pos as u64 } - - fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } + fn tell(&self) -> IoResult<u64> { Ok(self.pos as u64) } + fn seek(&mut self, _pos: i64, _style: SeekStyle) -> IoResult<()> { fail!() } } impl<'a> Buffer for BufReader<'a> { - fn fill<'a>(&'a mut self) -> &'a [u8] { self.buf.slice_from(self.pos) } + fn fill<'a>(&'a mut self) -> IoResult<&'a [u8]> { + Ok(self.buf.slice_from(self.pos)) + } fn consume(&mut self, amt: uint) { self.pos += amt; } } @@ -388,7 +395,7 @@ mod test { let mut called = false; io_error::cond.trap(|err| { - assert_eq!(err.kind, OtherIoError); + assert_eq!(err.kind, io::OtherIoError); called = true; }).inside(|| { writer.write([0, 0]); diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 69f0cf96ffc..1cf137279c4 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -290,15 +290,15 @@ Out of scope use cast; use char::Char; -use condition::Guard; use container::Container; +use fmt; use int; use iter::Iterator; use option::{Option, Some, None}; use path::Path; use result::{Ok, Err, Result}; -use str; use str::{StrSlice, OwnedStr}; +use str; use to_str::ToStr; use uint; use unstable::finally::Finally; @@ -347,8 +347,8 @@ mod mem; /// Non-blocking access to stdin, stdout, stderr pub mod stdio; -/// Implementations for Option -mod option; +/// Implementations for Result +mod result; /// Extension traits pub mod extensions; @@ -373,17 +373,30 @@ mod comm_adapters; // https://groups.google.com/forum/#!topic/libuv/oQO1HJAIDdA static DEFAULT_BUF_SIZE: uint = 1024 * 64; +pub type IoResult<T> = Result<T, IoError>; + /// The type passed to I/O condition handlers to indicate error /// /// # FIXME /// /// Is something like this sufficient? It's kind of archaic +#[deriving(Eq, Clone)] pub struct IoError { kind: IoErrorKind, desc: &'static str, detail: Option<~str> } +impl fmt::Default for IoError { + fn fmt(err: &IoError, fmt: &mut fmt::Formatter) -> fmt::Result { + if_ok!(fmt.buf.write_str(err.desc)); + match err.detail { + Some(ref s) => write!(fmt.buf, " ({})", *s), + None => Ok(()) + } + } +} + // FIXME: #8242 implementing manually because deriving doesn't work for some reason impl ToStr for IoError { fn to_str(&self) -> ~str { @@ -398,9 +411,8 @@ impl ToStr for IoError { } } -#[deriving(Eq)] +#[deriving(Eq, Clone)] pub enum IoErrorKind { - PreviousIoError, OtherIoError, EndOfFile, FileNotFound, @@ -424,7 +436,6 @@ pub enum IoErrorKind { impl ToStr for IoErrorKind { fn to_str(&self) -> ~str { match *self { - PreviousIoError => ~"PreviousIoError", OtherIoError => ~"OtherIoError", EndOfFile => ~"EndOfFile", FileNotFound => ~"FileNotFound", @@ -446,38 +457,6 @@ impl ToStr for IoErrorKind { } } -// FIXME: Can't put doc comments on macros -// Raised by `I/O` operations on error. -condition! { - pub io_error: IoError -> (); -} - -/// Helper for wrapper calls where you want to -/// ignore any io_errors that might be raised -pub fn ignore_io_error() -> Guard<'static,IoError,()> { - io_error::cond.trap(|_| { - // just swallow the error.. downstream users - // who can make a decision based on a None result - // won't care - }).guard() -} - -/// Helper for catching an I/O error and wrapping it in a Result object. The -/// return result will be the last I/O error that happened or the result of the -/// closure if no error occurred. -pub fn result<T>(cb: || -> T) -> Result<T, IoError> { - let mut err = None; - let ret = io_error::cond.trap(|e| { - if err.is_none() { - err = Some(e); - } - }).inside(cb); - match err { - Some(e) => Err(e), - None => Ok(ret), - } -} - pub trait Reader { // Only two methods which need to get implemented for this trait @@ -504,7 +483,7 @@ pub trait Reader { /// Will people often need to slice their vectors to call this /// and will that be annoying? /// Is it actually possible for 0 bytes to be read successfully? - fn read(&mut self, buf: &mut [u8]) -> Option<uint>; + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint>; // Convenient helper methods based on the above methods @@ -514,16 +493,17 @@ pub trait Reader { /// /// Raises the same conditions as the `read` method. Returns /// `None` if the condition is handled. - fn read_byte(&mut self) -> Option<u8> { + fn read_byte(&mut self) -> IoResult<u8> { let mut buf = [0]; - match self.read(buf) { - Some(0) => { - debug!("read 0 bytes. trying again"); - self.read_byte() + loop { + match self.read(buf) { + Ok(0) => { + debug!("read 0 bytes. trying again"); + } + Ok(1) => return Ok(buf[0]), + Ok(_) => unreachable!(), + Err(e) => return Err(e) } - Some(1) => Some(buf[0]), - Some(_) => unreachable!(), - None => None } } @@ -537,30 +517,26 @@ pub trait Reader { /// 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) { - unsafe { - let start_len = buf.len(); - let mut total_read = 0; - - buf.reserve_additional(len); - buf.set_len(start_len + len); - - (|| { - while total_read < len { - let len = buf.len(); - let slice = buf.mut_slice(start_len + total_read, len); - match self.read(slice) { - Some(nread) => { - total_read += nread; - } - None => { - io_error::cond.raise(standard_error(EndOfFile)); - break; - } + fn push_bytes(&mut self, buf: &mut ~[u8], len: uint) -> IoResult<()> { + let start_len = buf.len(); + let mut total_read = 0; + + buf.reserve_additional(len); + unsafe { buf.set_len(start_len + len); } + + (|| { + while total_read < len { + let len = buf.len(); + let slice = buf.mut_slice(start_len + total_read, len); + match self.read(slice) { + Ok(nread) => { + total_read += nread; } + Err(e) => return Err(e) } - }).finally(|| buf.set_len(start_len + total_read)) - } + } + Ok(()) + }).finally(|| unsafe { buf.set_len(start_len + total_read) }) } /// Reads `len` bytes and gives you back a new vector of length `len` @@ -570,10 +546,10 @@ pub trait Reader { /// 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] { + fn read_bytes(&mut self, len: uint) -> IoResult<~[u8]> { let mut buf = vec::with_capacity(len); - self.push_bytes(&mut buf, len); - return buf; + if_ok!(self.push_bytes(&mut buf, len)); + return Ok(buf); } /// Reads all remaining bytes from the stream. @@ -582,21 +558,16 @@ pub trait Reader { /// /// Raises the same conditions as the `read` method except for /// `EndOfFile` which is swallowed. - fn read_to_end(&mut self) -> ~[u8] { + fn read_to_end(&mut self) -> IoResult<~[u8]> { let mut buf = vec::with_capacity(DEFAULT_BUF_SIZE); - let mut keep_reading = true; - io_error::cond.trap(|e| { - if e.kind == EndOfFile { - keep_reading = false; - } else { - io_error::cond.raise(e) + loop { + match self.push_bytes(&mut buf, DEFAULT_BUF_SIZE) { + Ok(()) => {} + Err(ref e) if e.kind == EndOfFile => break, + Err(e) => return Err(e) } - }).inside(|| { - while keep_reading { - self.push_bytes(&mut buf, DEFAULT_BUF_SIZE) - } - }); - return buf; + } + return Ok(buf); } /// Reads all of the remaining bytes of this stream, interpreting them as a @@ -606,14 +577,13 @@ pub trait Reader { /// /// This function will raise all the same conditions as the `read` method, /// along with raising a condition if the input is not valid UTF-8. - fn read_to_str(&mut self) -> ~str { - match str::from_utf8_owned(self.read_to_end()) { - Some(s) => s, - None => { - io_error::cond.raise(standard_error(InvalidInput)); - ~"" + fn read_to_str(&mut self) -> IoResult<~str> { + self.read_to_end().and_then(|s| { + match str::from_utf8_owned(s) { + Some(s) => Ok(s), + None => Err(standard_error(InvalidInput)), } - } + }) } /// Create an iterator that reads a single byte on @@ -633,225 +603,219 @@ pub trait Reader { /// Reads `n` little-endian unsigned integer bytes. /// /// `n` must be between 1 and 8, inclusive. - fn read_le_uint_n(&mut self, nbytes: uint) -> u64 { + fn read_le_uint_n(&mut self, nbytes: uint) -> IoResult<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; + val += (if_ok!(self.read_u8()) as u64) << pos; pos += 8; i -= 1; } - val + Ok(val) } /// Reads `n` little-endian signed integer bytes. /// /// `n` must be between 1 and 8, inclusive. - fn read_le_int_n(&mut self, nbytes: uint) -> i64 { - extend_sign(self.read_le_uint_n(nbytes), nbytes) + fn read_le_int_n(&mut self, nbytes: uint) -> IoResult<i64> { + self.read_le_uint_n(nbytes).map(|i| extend_sign(i, nbytes)) } /// Reads `n` big-endian unsigned integer bytes. /// /// `n` must be between 1 and 8, inclusive. - fn read_be_uint_n(&mut self, nbytes: uint) -> u64 { + fn read_be_uint_n(&mut self, nbytes: uint) -> IoResult<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 += (if_ok!(self.read_u8()) as u64) << i * 8; } - val + Ok(val) } /// Reads `n` big-endian signed integer bytes. /// /// `n` must be between 1 and 8, inclusive. - fn read_be_int_n(&mut self, nbytes: uint) -> i64 { - extend_sign(self.read_be_uint_n(nbytes), nbytes) + fn read_be_int_n(&mut self, nbytes: uint) -> IoResult<i64> { + self.read_be_uint_n(nbytes).map(|i| extend_sign(i, nbytes)) } /// Reads a little-endian unsigned integer. /// /// The number of bytes returned is system-dependant. - fn read_le_uint(&mut self) -> uint { - self.read_le_uint_n(uint::BYTES) as uint + fn read_le_uint(&mut self) -> IoResult<uint> { + self.read_le_uint_n(uint::BYTES).map(|i| i as uint) } /// Reads a little-endian integer. /// /// The number of bytes returned is system-dependant. - fn read_le_int(&mut self) -> int { - self.read_le_int_n(int::BYTES) as int + fn read_le_int(&mut self) -> IoResult<int> { + self.read_le_int_n(int::BYTES).map(|i| i as int) } /// Reads a big-endian unsigned integer. /// /// The number of bytes returned is system-dependant. - fn read_be_uint(&mut self) -> uint { - self.read_be_uint_n(uint::BYTES) as uint + fn read_be_uint(&mut self) -> IoResult<uint> { + self.read_be_uint_n(uint::BYTES).map(|i| i as uint) } /// Reads a big-endian integer. /// /// The number of bytes returned is system-dependant. - fn read_be_int(&mut self) -> int { - self.read_be_int_n(int::BYTES) as int + fn read_be_int(&mut self) -> IoResult<int> { + self.read_be_int_n(int::BYTES).map(|i| i as int) } /// Reads a big-endian `u64`. /// /// `u64`s are 8 bytes long. - fn read_be_u64(&mut self) -> u64 { + fn read_be_u64(&mut self) -> IoResult<u64> { self.read_be_uint_n(8) } /// Reads a big-endian `u32`. /// /// `u32`s are 4 bytes long. - fn read_be_u32(&mut self) -> u32 { - self.read_be_uint_n(4) as u32 + fn read_be_u32(&mut self) -> IoResult<u32> { + self.read_be_uint_n(4).map(|i| i as u32) } /// Reads a big-endian `u16`. /// /// `u16`s are 2 bytes long. - fn read_be_u16(&mut self) -> u16 { - self.read_be_uint_n(2) as u16 + fn read_be_u16(&mut self) -> IoResult<u16> { + self.read_be_uint_n(2).map(|i| i as u16) } /// Reads a big-endian `i64`. /// /// `i64`s are 8 bytes long. - fn read_be_i64(&mut self) -> i64 { + fn read_be_i64(&mut self) -> IoResult<i64> { self.read_be_int_n(8) } /// Reads a big-endian `i32`. /// /// `i32`s are 4 bytes long. - fn read_be_i32(&mut self) -> i32 { - self.read_be_int_n(4) as i32 + fn read_be_i32(&mut self) -> IoResult<i32> { + self.read_be_int_n(4).map(|i| i as i32) } /// Reads a big-endian `i16`. /// /// `i16`s are 2 bytes long. - fn read_be_i16(&mut self) -> i16 { - self.read_be_int_n(2) as i16 + fn read_be_i16(&mut self) -> IoResult<i16> { + self.read_be_int_n(2).map(|i| i as i16) } /// Reads a big-endian `f64`. /// /// `f64`s are 8 byte, IEEE754 double-precision floating point numbers. - fn read_be_f64(&mut self) -> f64 { - unsafe { - cast::transmute::<u64, f64>(self.read_be_u64()) - } + fn read_be_f64(&mut self) -> IoResult<f64> { + self.read_be_u64().map(|i| unsafe { + cast::transmute::<u64, f64>(i) + }) } /// Reads a big-endian `f32`. /// /// `f32`s are 4 byte, IEEE754 single-precision floating point numbers. - fn read_be_f32(&mut self) -> f32 { - unsafe { - cast::transmute::<u32, f32>(self.read_be_u32()) - } + fn read_be_f32(&mut self) -> IoResult<f32> { + self.read_be_u32().map(|i| unsafe { + cast::transmute::<u32, f32>(i) + }) } /// Reads a little-endian `u64`. /// /// `u64`s are 8 bytes long. - fn read_le_u64(&mut self) -> u64 { + fn read_le_u64(&mut self) -> IoResult<u64> { self.read_le_uint_n(8) } /// Reads a little-endian `u32`. /// /// `u32`s are 4 bytes long. - fn read_le_u32(&mut self) -> u32 { - self.read_le_uint_n(4) as u32 + fn read_le_u32(&mut self) -> IoResult<u32> { + self.read_le_uint_n(4).map(|i| i as u32) } /// Reads a little-endian `u16`. /// /// `u16`s are 2 bytes long. - fn read_le_u16(&mut self) -> u16 { - self.read_le_uint_n(2) as u16 + fn read_le_u16(&mut self) -> IoResult<u16> { + self.read_le_uint_n(2).map(|i| i as u16) } /// Reads a little-endian `i64`. /// /// `i64`s are 8 bytes long. - fn read_le_i64(&mut self) -> i64 { + fn read_le_i64(&mut self) -> IoResult<i64> { self.read_le_int_n(8) } /// Reads a little-endian `i32`. /// /// `i32`s are 4 bytes long. - fn read_le_i32(&mut self) -> i32 { - self.read_le_int_n(4) as i32 + fn read_le_i32(&mut self) -> IoResult<i32> { + self.read_le_int_n(4).map(|i| i as i32) } /// Reads a little-endian `i16`. /// /// `i16`s are 2 bytes long. - fn read_le_i16(&mut self) -> i16 { - self.read_le_int_n(2) as i16 + fn read_le_i16(&mut self) -> IoResult<i16> { + self.read_le_int_n(2).map(|i| i as i16) } /// Reads a little-endian `f64`. /// /// `f64`s are 8 byte, IEEE754 double-precision floating point numbers. - fn read_le_f64(&mut self) -> f64 { - unsafe { - cast::transmute::<u64, f64>(self.read_le_u64()) - } + fn read_le_f64(&mut self) -> IoResult<f64> { + self.read_le_u64().map(|i| unsafe { + cast::transmute::<u64, f64>(i) + }) } /// Reads a little-endian `f32`. /// /// `f32`s are 4 byte, IEEE754 single-precision floating point numbers. - fn read_le_f32(&mut self) -> f32 { - unsafe { - cast::transmute::<u32, f32>(self.read_le_u32()) - } + fn read_le_f32(&mut self) -> IoResult<f32> { + self.read_le_u32().map(|i| unsafe { + cast::transmute::<u32, f32>(i) + }) } /// Read a u8. /// /// `u8`s are 1 byte. - fn read_u8(&mut self) -> u8 { - match self.read_byte() { - Some(b) => b, - None => 0 - } + fn read_u8(&mut self) -> IoResult<u8> { + self.read_byte() } /// Read an i8. /// /// `i8`s are 1 byte. - fn read_i8(&mut self) -> i8 { - match self.read_byte() { - Some(b) => b as i8, - None => 0 - } + fn read_i8(&mut self) -> IoResult<i8> { + self.read_byte().map(|i| i as i8) } } impl Reader for ~Reader { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.read(buf) } + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.read(buf) } } impl<'a> Reader for &'a mut Reader { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.read(buf) } + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.read(buf) } } fn extend_sign(val: u64, nbytes: uint) -> i64 { @@ -865,14 +829,14 @@ pub trait Writer { /// # Failure /// /// Raises the `io_error` condition on error - fn write(&mut self, buf: &[u8]); + fn write(&mut self, buf: &[u8]) -> IoResult<()>; /// Flush this output stream, ensuring that all intermediately buffered /// contents reach their destination. /// /// This is by default a no-op and implementers of the `Writer` trait should /// decide whether their stream needs to be buffered or not. - fn flush(&mut self) {} + fn flush(&mut self) -> IoResult<()> { Ok(()) } /// Write a rust string into this sink. /// @@ -880,8 +844,8 @@ pub trait Writer { /// If other encodings are desired, it is recommended to compose this stream /// with another performing the conversion, or to use `write` with a /// converted byte-array instead. - fn write_str(&mut self, s: &str) { - self.write(s.as_bytes()); + fn write_str(&mut self, s: &str) -> IoResult<()> { + self.write(s.as_bytes()) } /// Writes a string into this sink, and then writes a literal newline (`\n`) @@ -891,125 +855,124 @@ pub trait Writer { /// /// If other encodings or line ending flavors are desired, it is recommended /// that the `write` method is used specifically instead. - fn write_line(&mut self, s: &str) { - self.write_str(s); - self.write(['\n' as u8]); + fn write_line(&mut self, s: &str) -> IoResult<()> { + self.write_str(s).and_then(|()| self.write(['\n' as u8])) } /// Write a single char, encoded as UTF-8. - fn write_char(&mut self, c: char) { + fn write_char(&mut self, c: char) -> IoResult<()> { let mut buf = [0u8, ..4]; let n = c.encode_utf8(buf.as_mut_slice()); - self.write(buf.slice_to(n)); + self.write(buf.slice_to(n)) } /// Write the result of passing n through `int::to_str_bytes`. - fn write_int(&mut self, n: int) { + fn write_int(&mut self, n: int) -> IoResult<()> { int::to_str_bytes(n, 10u, |bytes| self.write(bytes)) } /// Write the result of passing n through `uint::to_str_bytes`. - fn write_uint(&mut self, n: uint) { + fn write_uint(&mut self, n: uint) -> IoResult<()> { uint::to_str_bytes(n, 10u, |bytes| self.write(bytes)) } /// Write a little-endian uint (number of bytes depends on system). - fn write_le_uint(&mut self, n: uint) { + fn write_le_uint(&mut self, n: uint) -> IoResult<()> { extensions::u64_to_le_bytes(n as u64, uint::BYTES, |v| self.write(v)) } /// Write a little-endian int (number of bytes depends on system). - fn write_le_int(&mut self, n: int) { + fn write_le_int(&mut self, n: int) -> IoResult<()> { extensions::u64_to_le_bytes(n as u64, int::BYTES, |v| self.write(v)) } /// Write a big-endian uint (number of bytes depends on system). - fn write_be_uint(&mut self, n: uint) { + fn write_be_uint(&mut self, n: uint) -> IoResult<()> { extensions::u64_to_be_bytes(n as u64, uint::BYTES, |v| self.write(v)) } /// Write a big-endian int (number of bytes depends on system). - fn write_be_int(&mut self, n: int) { + fn write_be_int(&mut self, n: int) -> IoResult<()> { extensions::u64_to_be_bytes(n as u64, int::BYTES, |v| self.write(v)) } /// Write a big-endian u64 (8 bytes). - fn write_be_u64(&mut self, n: u64) { + fn write_be_u64(&mut self, n: u64) -> IoResult<()> { extensions::u64_to_be_bytes(n, 8u, |v| self.write(v)) } /// Write a big-endian u32 (4 bytes). - fn write_be_u32(&mut self, n: u32) { + fn write_be_u32(&mut self, n: u32) -> IoResult<()> { extensions::u64_to_be_bytes(n as u64, 4u, |v| self.write(v)) } /// Write a big-endian u16 (2 bytes). - fn write_be_u16(&mut self, n: u16) { + fn write_be_u16(&mut self, n: u16) -> IoResult<()> { extensions::u64_to_be_bytes(n as u64, 2u, |v| self.write(v)) } /// Write a big-endian i64 (8 bytes). - fn write_be_i64(&mut self, n: i64) { + fn write_be_i64(&mut self, n: i64) -> IoResult<()> { extensions::u64_to_be_bytes(n as u64, 8u, |v| self.write(v)) } /// Write a big-endian i32 (4 bytes). - fn write_be_i32(&mut self, n: i32) { + fn write_be_i32(&mut self, n: i32) -> IoResult<()> { extensions::u64_to_be_bytes(n as u64, 4u, |v| self.write(v)) } /// Write a big-endian i16 (2 bytes). - fn write_be_i16(&mut self, n: i16) { + fn write_be_i16(&mut self, n: i16) -> IoResult<()> { extensions::u64_to_be_bytes(n as u64, 2u, |v| self.write(v)) } /// Write a big-endian IEEE754 double-precision floating-point (8 bytes). - fn write_be_f64(&mut self, f: f64) { + fn write_be_f64(&mut self, f: f64) -> IoResult<()> { unsafe { self.write_be_u64(cast::transmute(f)) } } /// Write a big-endian IEEE754 single-precision floating-point (4 bytes). - fn write_be_f32(&mut self, f: f32) { + fn write_be_f32(&mut self, f: f32) -> IoResult<()> { unsafe { self.write_be_u32(cast::transmute(f)) } } /// Write a little-endian u64 (8 bytes). - fn write_le_u64(&mut self, n: u64) { + fn write_le_u64(&mut self, n: u64) -> IoResult<()> { extensions::u64_to_le_bytes(n, 8u, |v| self.write(v)) } /// Write a little-endian u32 (4 bytes). - fn write_le_u32(&mut self, n: u32) { + fn write_le_u32(&mut self, n: u32) -> IoResult<()> { extensions::u64_to_le_bytes(n as u64, 4u, |v| self.write(v)) } /// Write a little-endian u16 (2 bytes). - fn write_le_u16(&mut self, n: u16) { + fn write_le_u16(&mut self, n: u16) -> IoResult<()> { extensions::u64_to_le_bytes(n as u64, 2u, |v| self.write(v)) } /// Write a little-endian i64 (8 bytes). - fn write_le_i64(&mut self, n: i64) { + fn write_le_i64(&mut self, n: i64) -> IoResult<()> { extensions::u64_to_le_bytes(n as u64, 8u, |v| self.write(v)) } /// Write a little-endian i32 (4 bytes). - fn write_le_i32(&mut self, n: i32) { + fn write_le_i32(&mut self, n: i32) -> IoResult<()> { extensions::u64_to_le_bytes(n as u64, 4u, |v| self.write(v)) } /// Write a little-endian i16 (2 bytes). - fn write_le_i16(&mut self, n: i16) { + fn write_le_i16(&mut self, n: i16) -> IoResult<()> { extensions::u64_to_le_bytes(n as u64, 2u, |v| self.write(v)) } /// Write a little-endian IEEE754 double-precision floating-point /// (8 bytes). - fn write_le_f64(&mut self, f: f64) { + fn write_le_f64(&mut self, f: f64) -> IoResult<()> { unsafe { self.write_le_u64(cast::transmute(f)) } @@ -1017,31 +980,31 @@ pub trait Writer { /// Write a little-endian IEEE754 single-precision floating-point /// (4 bytes). - fn write_le_f32(&mut self, f: f32) { + fn write_le_f32(&mut self, f: f32) -> IoResult<()> { unsafe { self.write_le_u32(cast::transmute(f)) } } /// Write a u8 (1 byte). - fn write_u8(&mut self, n: u8) { + fn write_u8(&mut self, n: u8) -> IoResult<()> { self.write([n]) } /// Write a i8 (1 byte). - fn write_i8(&mut self, n: i8) { + fn write_i8(&mut self, n: i8) -> IoResult<()> { self.write([n as u8]) } } impl Writer for ~Writer { - fn write(&mut self, buf: &[u8]) { self.write(buf) } - fn flush(&mut self) { self.flush() } + fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.write(buf) } + fn flush(&mut self) -> IoResult<()> { self.flush() } } impl<'a> Writer for &'a mut Writer { - fn write(&mut self, buf: &[u8]) { self.write(buf) } - fn flush(&mut self) { self.flush() } + fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.write(buf) } + fn flush(&mut self) -> IoResult<()> { self.flush() } } pub trait Stream: Reader + Writer { } @@ -1068,7 +1031,7 @@ pub struct Lines<'r, T> { impl<'r, T: Buffer> Iterator<~str> for Lines<'r, T> { fn next(&mut self) -> Option<~str> { - self.buffer.read_line() + self.buffer.read_line().ok() } } @@ -1089,7 +1052,7 @@ pub trait Buffer: Reader { /// /// This function will raise on the `io_error` condition if a read error is /// encountered. - fn fill<'a>(&'a mut self) -> &'a [u8]; + fn fill<'a>(&'a mut self) -> IoResult<&'a [u8]>; /// Tells this buffer that `amt` bytes have been consumed from the buffer, /// so they should no longer be returned in calls to `fill` or `read`. @@ -1116,7 +1079,7 @@ pub trait Buffer: Reader { /// `EndOfFile` which is swallowed) if a read error is encountered. /// The task will also fail if sequence of bytes leading up to /// the newline character are not valid UTF-8. - fn read_line(&mut self) -> Option<~str> { + fn read_line(&mut self) -> IoResult<~str> { self.read_until('\n' as u8).map(|line| str::from_utf8_owned(line).unwrap()) } @@ -1140,39 +1103,32 @@ pub trait Buffer: Reader { /// /// This function will raise on the `io_error` condition if a read error is /// encountered, except that `EndOfFile` is swallowed. - fn read_until(&mut self, byte: u8) -> Option<~[u8]> { + fn read_until(&mut self, byte: u8) -> IoResult<~[u8]> { let mut res = ~[]; - io_error::cond.trap(|e| { - if e.kind != EndOfFile { - io_error::cond.raise(e); - } - }).inside(|| { - let mut used; - loop { - { - let available = self.fill(); - match available.iter().position(|&b| b == byte) { - Some(i) => { - res.push_all(available.slice_to(i + 1)); - used = i + 1; - break - } - None => { - res.push_all(available); - used = available.len(); - } + let mut used; + loop { + { + let available = if_ok!(self.fill()); + match available.iter().position(|&b| b == byte) { + Some(i) => { + res.push_all(available.slice_to(i + 1)); + used = i + 1; + break + } + None => { + res.push_all(available); + used = available.len(); } } - if used == 0 { - break - } - self.consume(used); + } + if used == 0 { + break } self.consume(used); - }); - return if res.len() == 0 {None} else {Some(res)}; - + } + self.consume(used); + Ok(res) } /// Reads the next utf8-encoded character from the underlying stream. @@ -1184,27 +1140,26 @@ pub trait Buffer: Reader { /// /// This function will raise on the `io_error` condition if a read error is /// encountered. - fn read_char(&mut self) -> Option<char> { + fn read_char(&mut self) -> IoResult<char> { let width = { - let available = self.fill(); - if available.len() == 0 { return None } // read error + let available = if_ok!(self.fill()); str::utf8_char_width(available[0]) }; - if width == 0 { return None } // not uf8 + if width == 0 { return Err(standard_error(InvalidInput)) } // not uf8 let mut buf = [0, ..4]; { let mut start = 0; loop { - match self.read(buf.mut_slice(start, width)) { - Some(n) if n == width - start => break, - Some(n) if n < width - start => { start += n; } - Some(..) | None => return None // read error + match if_ok!(self.read(buf.mut_slice(start, width))) { + n if n == width - start => break, + n if n < width - start => { start += n; } + _ => return Err(standard_error(InvalidInput)), } } } match str::from_utf8(buf.slice_to(width)) { - Some(s) => Some(s.char_at(0)), - None => None + Some(s) => Ok(s.char_at(0)), + None => Err(standard_error(InvalidInput)) } } } @@ -1222,7 +1177,7 @@ pub enum SeekStyle { /// * Are `u64` and `i64` the right choices? pub trait Seek { /// Return position of file cursor in the stream - fn tell(&self) -> u64; + fn tell(&self) -> IoResult<u64>; /// Seek to an offset in a stream /// @@ -1231,7 +1186,7 @@ pub trait Seek { /// # FIXME /// /// * What is the behavior when seeking past the end of a stream? - fn seek(&mut self, pos: i64, style: SeekStyle); + fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()>; } /// A listener is a value that can consume itself to start listening for connections. @@ -1243,7 +1198,7 @@ pub trait Listener<T, A: Acceptor<T>> { /// /// Raises `io_error` condition. If the condition is handled, /// then `listen` returns `None`. - fn listen(self) -> Option<A>; + fn listen(self) -> IoResult<A>; } /// An acceptor is a value that presents incoming connections @@ -1253,7 +1208,7 @@ pub trait Acceptor<T> { /// # Failure /// Raise `io_error` condition. If the condition is handled, /// then `accept` returns `None`. - fn accept(&mut self) -> Option<T>; + fn accept(&mut self) -> IoResult<T>; /// Create an iterator over incoming connection attempts fn incoming<'r>(&'r mut self) -> IncomingConnections<'r, Self> { @@ -1272,15 +1227,14 @@ pub struct IncomingConnections<'a, A> { priv inc: &'a mut A, } -impl<'a, T, A: Acceptor<T>> Iterator<Option<T>> for IncomingConnections<'a, A> { - fn next(&mut self) -> Option<Option<T>> { +impl<'a, T, A: Acceptor<T>> Iterator<IoResult<T>> for IncomingConnections<'a, A> { + fn next(&mut self) -> Option<IoResult<T>> { Some(self.inc.accept()) } } pub fn standard_error(kind: IoErrorKind) -> IoError { let desc = match kind { - PreviousIoError => "failing due to previous I/O error", EndOfFile => "end of file", IoUnavailable => "I/O is unavailable", InvalidInput => "invalid input", diff --git a/src/libstd/io/net/addrinfo.rs b/src/libstd/io/net/addrinfo.rs index 29bf6261a07..1f8f8beeae3 100644 --- a/src/libstd/io/net/addrinfo.rs +++ b/src/libstd/io/net/addrinfo.rs @@ -17,8 +17,9 @@ getaddrinfo() */ -use option::{Option, Some, None}; +use io::IoResult; use io::net::ip::{SocketAddr, IpAddr}; +use option::{Option, Some, None}; use rt::rtio::{IoFactory, LocalIo}; use vec::ImmutableVector; @@ -73,7 +74,7 @@ pub struct Info { /// # Failure /// /// On failure, this will raise on the `io_error` condition. -pub fn get_host_addresses(host: &str) -> Option<~[IpAddr]> { +pub fn get_host_addresses(host: &str) -> IoResult<~[IpAddr]> { lookup(Some(host), None, None).map(|a| a.map(|i| i.address.ip)) } @@ -94,7 +95,7 @@ pub fn get_host_addresses(host: &str) -> Option<~[IpAddr]> { /// FIXME: 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<Hint>) - -> Option<~[Info]> { + -> IoResult<~[Info]> { LocalIo::maybe_raise(|io| io.get_host_addresses(hostname, servname, hint)) } diff --git a/src/libstd/io/net/tcp.rs b/src/libstd/io/net/tcp.rs index 475e3b206f2..cc923d5b736 100644 --- a/src/libstd/io/net/tcp.rs +++ b/src/libstd/io/net/tcp.rs @@ -8,11 +8,8 @@ // 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 io::net::ip::SocketAddr; -use io::{Reader, Writer, Listener, Acceptor}; -use io::{io_error, EndOfFile}; +use io::{Reader, Writer, Listener, Acceptor, IoResult}; use rt::rtio::{IoFactory, LocalIo, RtioSocket, RtioTcpListener}; use rt::rtio::{RtioTcpAcceptor, RtioTcpStream}; @@ -25,57 +22,27 @@ impl TcpStream { TcpStream { obj: s } } - pub fn connect(addr: SocketAddr) -> Option<TcpStream> { + pub fn connect(addr: SocketAddr) -> IoResult<TcpStream> { LocalIo::maybe_raise(|io| { io.tcp_connect(addr).map(TcpStream::new) }) } - pub fn peer_name(&mut self) -> Option<SocketAddr> { - match self.obj.peer_name() { - Ok(pn) => Some(pn), - Err(ioerr) => { - debug!("failed to get peer name: {:?}", ioerr); - io_error::cond.raise(ioerr); - None - } - } + pub fn peer_name(&mut self) -> IoResult<SocketAddr> { + self.obj.peer_name() } - pub fn socket_name(&mut self) -> Option<SocketAddr> { - match self.obj.socket_name() { - Ok(sn) => Some(sn), - Err(ioerr) => { - debug!("failed to get socket name: {:?}", ioerr); - io_error::cond.raise(ioerr); - None - } - } + pub fn socket_name(&mut self) -> IoResult<SocketAddr> { + self.obj.socket_name() } } impl Reader for TcpStream { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { - match self.obj.read(buf) { - Ok(read) => Some(read), - Err(ioerr) => { - // EOF is indicated by returning None - if ioerr.kind != EndOfFile { - io_error::cond.raise(ioerr); - } - return None; - } - } - } + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.obj.read(buf) } } impl Writer for TcpStream { - fn write(&mut self, buf: &[u8]) { - match self.obj.write(buf) { - Ok(_) => (), - Err(ioerr) => io_error::cond.raise(ioerr), - } - } + fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.obj.write(buf) } } pub struct TcpListener { @@ -83,33 +50,20 @@ pub struct TcpListener { } impl TcpListener { - pub fn bind(addr: SocketAddr) -> Option<TcpListener> { + pub fn bind(addr: SocketAddr) -> IoResult<TcpListener> { LocalIo::maybe_raise(|io| { io.tcp_bind(addr).map(|l| TcpListener { obj: l }) }) } - pub fn socket_name(&mut self) -> Option<SocketAddr> { - match self.obj.socket_name() { - Ok(sn) => Some(sn), - Err(ioerr) => { - debug!("failed to get socket name: {:?}", ioerr); - io_error::cond.raise(ioerr); - None - } - } + pub fn socket_name(&mut self) -> IoResult<SocketAddr> { + self.obj.socket_name() } } impl Listener<TcpStream, TcpAcceptor> for TcpListener { - fn listen(self) -> Option<TcpAcceptor> { - match self.obj.listen() { - Ok(acceptor) => Some(TcpAcceptor { obj: acceptor }), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None - } - } + fn listen(self) -> IoResult<TcpAcceptor> { + self.obj.listen().map(|acceptor| TcpAcceptor { obj: acceptor }) } } @@ -118,14 +72,8 @@ pub struct TcpAcceptor { } impl Acceptor<TcpStream> for TcpAcceptor { - fn accept(&mut self) -> Option<TcpStream> { - match self.obj.accept() { - Ok(s) => Some(TcpStream::new(s)), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None - } - } + fn accept(&mut self) -> IoResult<TcpStream> { + self.obj.accept().map(TcpStream::new) } } diff --git a/src/libstd/io/net/udp.rs b/src/libstd/io/net/udp.rs index 1cf30d469f7..abb6bdea75b 100644 --- a/src/libstd/io/net/udp.rs +++ b/src/libstd/io/net/udp.rs @@ -8,11 +8,9 @@ // 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 io::net::ip::SocketAddr; -use io::{Reader, Writer}; -use io::{io_error, EndOfFile}; +use io::{Reader, Writer, IoResult}; use rt::rtio::{RtioSocket, RtioUdpSocket, IoFactory, LocalIo}; pub struct UdpSocket { @@ -20,45 +18,26 @@ pub struct UdpSocket { } impl UdpSocket { - pub fn bind(addr: SocketAddr) -> Option<UdpSocket> { + pub fn bind(addr: SocketAddr) -> IoResult<UdpSocket> { LocalIo::maybe_raise(|io| { io.udp_bind(addr).map(|s| UdpSocket { obj: s }) }) } - pub fn recvfrom(&mut self, buf: &mut [u8]) -> Option<(uint, SocketAddr)> { - match self.obj.recvfrom(buf) { - Ok((nread, src)) => Some((nread, src)), - Err(ioerr) => { - // EOF is indicated by returning None - if ioerr.kind != EndOfFile { - io_error::cond.raise(ioerr); - } - None - } - } + pub fn recvfrom(&mut self, buf: &mut [u8]) -> IoResult<(uint, SocketAddr)> { + self.obj.recvfrom(buf) } - pub fn sendto(&mut self, buf: &[u8], dst: SocketAddr) { - match self.obj.sendto(buf, dst) { - Ok(_) => (), - Err(ioerr) => io_error::cond.raise(ioerr), - } + pub fn sendto(&mut self, buf: &[u8], dst: SocketAddr) -> IoResult<()> { + self.obj.sendto(buf, dst) } pub fn connect(self, other: SocketAddr) -> UdpStream { UdpStream { socket: self, connectedTo: other } } - pub fn socket_name(&mut self) -> Option<SocketAddr> { - match self.obj.socket_name() { - Ok(sn) => Some(sn), - Err(ioerr) => { - debug!("failed to get socket name: {:?}", ioerr); - io_error::cond.raise(ioerr); - None - } - } + pub fn socket_name(&mut self) -> IoResult<SocketAddr> { + self.obj.socket_name() } } @@ -76,21 +55,21 @@ impl UdpStream { } impl Reader for UdpStream { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { let peer = self.connectedTo; self.as_socket(|sock| { match sock.recvfrom(buf) { - Some((_nread, src)) if src != peer => Some(0), - Some((nread, _src)) => Some(nread), - None => None, + Ok((_nread, src)) if src != peer => Ok(0), + Ok((nread, _src)) => Ok(nread), + Err(e) => Err(e), } }) } } impl Writer for UdpStream { - fn write(&mut self, buf: &[u8]) { - self.as_socket(|sock| sock.sendto(buf, self.connectedTo)); + fn write(&mut self, buf: &[u8]) -> IoResult<()> { + self.as_socket(|sock| sock.sendto(buf, self.connectedTo)) } } diff --git a/src/libstd/io/net/unix.rs b/src/libstd/io/net/unix.rs index d470e9bfda1..b8b396b24fd 100644 --- a/src/libstd/io/net/unix.rs +++ b/src/libstd/io/net/unix.rs @@ -28,7 +28,7 @@ use c_str::ToCStr; use rt::rtio::{IoFactory, LocalIo, RtioUnixListener}; use rt::rtio::{RtioUnixAcceptor, RtioPipe}; use io::pipe::PipeStream; -use io::{io_error, Listener, Acceptor, Reader, Writer}; +use io::{Listener, Acceptor, Reader, Writer, IoResult}; /// A stream which communicates over a named pipe. pub struct UnixStream { @@ -52,13 +52,15 @@ impl UnixStream { /// /// # Example /// - /// use std::io::net::unix::UnixStream; + /// ```rust + /// # #[allow(unused_must_use)]; + /// use std::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<P: ToCStr>(path: &P) -> Option<UnixStream> { + /// let server = Path::new("path/to/my/socket"); + /// let mut stream = UnixStream::connect(&server); + /// stream.write([1, 2, 3]); + /// ``` + pub fn connect<P: ToCStr>(path: &P) -> IoResult<UnixStream> { LocalIo::maybe_raise(|io| { io.unix_connect(&path.to_c_str()).map(UnixStream::new) }) @@ -66,11 +68,11 @@ impl UnixStream { } impl Reader for UnixStream { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.obj.read(buf) } + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.obj.read(buf) } } impl Writer for UnixStream { - fn write(&mut self, buf: &[u8]) { self.obj.write(buf) } + fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.obj.write(buf) } } pub struct UnixListener { @@ -91,16 +93,18 @@ impl UnixListener { /// /// # Example /// - /// use std::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]); - /// } + /// ``` + /// use std::io::net::unix::UnixListener; + /// use std::io::Listener; /// - pub fn bind<P: ToCStr>(path: &P) -> Option<UnixListener> { + /// let server = Path::new("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<P: ToCStr>(path: &P) -> IoResult<UnixListener> { LocalIo::maybe_raise(|io| { io.unix_bind(&path.to_c_str()).map(|s| UnixListener { obj: s }) }) @@ -108,14 +112,8 @@ impl UnixListener { } impl Listener<UnixStream, UnixAcceptor> for UnixListener { - fn listen(self) -> Option<UnixAcceptor> { - match self.obj.listen() { - Ok(acceptor) => Some(UnixAcceptor { obj: acceptor }), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None - } - } + fn listen(self) -> IoResult<UnixAcceptor> { + self.obj.listen().map(|obj| UnixAcceptor { obj: obj }) } } @@ -124,14 +122,8 @@ pub struct UnixAcceptor { } impl Acceptor<UnixStream> for UnixAcceptor { - fn accept(&mut self) -> Option<UnixStream> { - match self.obj.accept() { - Ok(s) => Some(UnixStream::new(s)), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None - } - } + fn accept(&mut self) -> IoResult<UnixStream> { + self.obj.accept().map(UnixStream::new) } } diff --git a/src/libstd/io/pipe.rs b/src/libstd/io/pipe.rs index 9919d333f41..34d8bf96aa2 100644 --- a/src/libstd/io/pipe.rs +++ b/src/libstd/io/pipe.rs @@ -14,7 +14,7 @@ //! enough so that pipes can be created to child processes. use prelude::*; -use io::{io_error, EndOfFile}; +use io::IoResult; use libc; use rt::rtio::{RtioPipe, LocalIo}; @@ -42,7 +42,7 @@ impl PipeStream { /// /// If the pipe cannot be created, an error will be raised on the /// `io_error` condition. - pub fn open(fd: libc::c_int) -> Option<PipeStream> { + pub fn open(fd: libc::c_int) -> IoResult<PipeStream> { LocalIo::maybe_raise(|io| { io.pipe_open(fd).map(|obj| PipeStream { obj: obj }) }) @@ -54,29 +54,11 @@ impl PipeStream { } impl Reader for PipeStream { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { - match self.obj.read(buf) { - Ok(read) => Some(read), - Err(ioerr) => { - // EOF is indicated by returning None - if ioerr.kind != EndOfFile { - io_error::cond.raise(ioerr); - } - return None; - } - } - } + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { self.obj.read(buf) } } impl Writer for PipeStream { - fn write(&mut self, buf: &[u8]) { - match self.obj.write(buf) { - Ok(_) => (), - Err(ioerr) => { - io_error::cond.raise(ioerr); - } - } - } + fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.obj.write(buf) } } #[cfg(test)] diff --git a/src/libstd/io/process.rs b/src/libstd/io/process.rs index 6a10f24916f..62f6b3c3029 100644 --- a/src/libstd/io/process.rs +++ b/src/libstd/io/process.rs @@ -14,7 +14,7 @@ use prelude::*; use libc; use io; -use io::io_error; +use io::IoResult; use rt::rtio::{RtioProcess, IoFactory, LocalIo}; use fmt; @@ -93,7 +93,7 @@ pub enum ProcessExit { impl fmt::Show for ProcessExit { /// Format a ProcessExit enum, to nicely present the information. - fn fmt(obj: &ProcessExit, f: &mut fmt::Formatter) { + fn fmt(obj: &ProcessExit, f: &mut fmt::Formatter) -> fmt::Result { match *obj { ExitStatus(code) => write!(f.buf, "exit code: {}", code), ExitSignal(code) => write!(f.buf, "signal: {}", code), @@ -118,7 +118,7 @@ impl ProcessExit { impl Process { /// Creates a new pipe initialized, but not bound to any particular /// source/destination - pub fn new(config: ProcessConfig) -> Option<Process> { + pub fn new(config: ProcessConfig) -> IoResult<Process> { let mut config = Some(config); LocalIo::maybe_raise(|io| { io.spawn(config.take_unwrap()).map(|(p, io)| { @@ -142,13 +142,8 @@ impl Process { /// function. /// /// If the signal delivery fails, then the `io_error` condition is raised on - pub fn signal(&mut self, signal: int) { - match self.handle.kill(signal) { - Ok(()) => {} - Err(err) => { - io_error::cond.raise(err) - } - } + pub fn signal(&mut self, signal: int) -> IoResult<()> { + self.handle.kill(signal) } /// Wait for the child to exit completely, returning the status that it diff --git a/src/libstd/io/option.rs b/src/libstd/io/result.rs index e2eec652d9d..6eed4d146ba 100644 --- a/src/libstd/io/option.rs +++ b/src/libstd/io/result.rs @@ -14,80 +14,64 @@ //! These implementations allow e.g. `Option<File>` to be used //! as a `Reader` without unwrapping the option first. -use option::*; -use super::{Reader, Writer, Listener, Acceptor, Seek, SeekStyle}; -use super::{standard_error, PreviousIoError, io_error, IoError}; +use clone::Clone; +use result::{Ok, Err}; +use super::{Reader, Writer, Listener, Acceptor, Seek, SeekStyle, IoResult}; -fn prev_io_error() -> IoError { - standard_error(PreviousIoError) -} - -impl<W: Writer> Writer for Option<W> { - fn write(&mut self, buf: &[u8]) { +impl<W: Writer> Writer for IoResult<W> { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { match *self { - Some(ref mut writer) => writer.write(buf), - None => io_error::cond.raise(prev_io_error()) + Ok(ref mut writer) => writer.write(buf), + Err(ref e) => Err((*e).clone()) } } - fn flush(&mut self) { + fn flush(&mut self) -> IoResult<()> { match *self { - Some(ref mut writer) => writer.flush(), - None => io_error::cond.raise(prev_io_error()) + Ok(ref mut writer) => writer.flush(), + Err(ref e) => Err(e.clone()), } } } -impl<R: Reader> Reader for Option<R> { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { +impl<R: Reader> Reader for IoResult<R> { + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { match *self { - Some(ref mut reader) => reader.read(buf), - None => { - io_error::cond.raise(prev_io_error()); - None - } + Ok(ref mut reader) => reader.read(buf), + Err(ref e) => Err(e.clone()), } } } -impl<S: Seek> Seek for Option<S> { - fn tell(&self) -> u64 { +impl<S: Seek> Seek for IoResult<S> { + fn tell(&self) -> IoResult<u64> { match *self { - Some(ref seeker) => seeker.tell(), - None => { - io_error::cond.raise(prev_io_error()); - 0 - } + Ok(ref seeker) => seeker.tell(), + Err(ref e) => Err(e.clone()), } } - fn seek(&mut self, pos: i64, style: SeekStyle) { + fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> { match *self { - Some(ref mut seeker) => seeker.seek(pos, style), - None => io_error::cond.raise(prev_io_error()) + Ok(ref mut seeker) => seeker.seek(pos, style), + Err(ref e) => Err(e.clone()) } } } -impl<T, A: Acceptor<T>, L: Listener<T, A>> Listener<T, A> for Option<L> { - fn listen(self) -> Option<A> { +impl<T, A: Acceptor<T>, L: Listener<T, A>> Listener<T, A> for IoResult<L> { + fn listen(self) -> IoResult<A> { match self { - Some(listener) => listener.listen(), - None => { - io_error::cond.raise(prev_io_error()); - None - } + Ok(listener) => listener.listen(), + Err(e) => Err(e), } } } -impl<T, A: Acceptor<T>> Acceptor<T> for Option<A> { - fn accept(&mut self) -> Option<T> { +impl<T, A: Acceptor<T>> Acceptor<T> for IoResult<A> { + fn accept(&mut self) -> IoResult<T> { match *self { - Some(ref mut acceptor) => acceptor.accept(), - None => { - io_error::cond.raise(prev_io_error()); - None - } + Ok(ref mut acceptor) => acceptor.accept(), + Err(ref e) => Err(e.clone()), } } } diff --git a/src/libstd/io/signal.rs b/src/libstd/io/signal.rs index 5575e289b59..aaec1aba4b8 100644 --- a/src/libstd/io/signal.rs +++ b/src/libstd/io/signal.rs @@ -20,10 +20,11 @@ definitions for a number of signals. */ use clone::Clone; +use result::{Ok, Err}; use comm::{Port, SharedChan}; use container::{Map, MutableMap}; use hashmap; -use option::{Some, None}; +use io; use rt::rtio::{IoFactory, LocalIo, RtioSignal}; #[repr(int)] @@ -117,18 +118,18 @@ impl Listener { /// 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 { + pub fn register(&mut self, signum: Signum) -> io::IoResult<()> { if self.handles.contains_key(&signum) { - return true; // self is already listening to signum, so succeed + return Ok(()); // self is already listening to signum, so succeed } match LocalIo::maybe_raise(|io| { io.signal(signum, self.chan.clone()) }) { - Some(handle) => { + Ok(handle) => { self.handles.insert(signum, handle); - true + Ok(()) } - None => false + Err(e) => Err(e) } } diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index d9fa2a4fc33..bdf013233c0 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -28,7 +28,7 @@ out.write(bytes!("Hello, world!")); use container::Container; use fmt; -use io::{Reader, Writer, io_error, IoError, OtherIoError, +use io::{Reader, Writer, IoResult, IoError, OtherIoError, standard_error, EndOfFile, LineBufferedWriter}; use libc; use option::{Option, Some, None}; @@ -114,7 +114,8 @@ fn reset_helper(w: ~Writer, match f(t.get(), w) { Some(mut w) => { drop(t); - w.flush(); + // FIXME: is failing right here? + w.flush().unwrap(); Some(w) } None => None @@ -155,9 +156,9 @@ pub fn set_stderr(stderr: ~Writer) -> Option<~Writer> { // // io1 aliases io2 // }) // }) -fn with_task_stdout(f: |&mut Writer|) { +fn with_task_stdout(f: |&mut Writer| -> IoResult<()> ) { let task: Option<~Task> = Local::try_take(); - match task { + let result = match task { Some(mut task) => { // Printing may run arbitrary code, so ensure that the task is in // TLS to allow all std services. Note that this means a print while @@ -169,7 +170,7 @@ fn with_task_stdout(f: |&mut Writer|) { if my_stdout.is_none() { my_stdout = Some(~LineBufferedWriter::new(stdout()) as ~Writer); } - f(*my_stdout.get_mut_ref()); + let ret = f(*my_stdout.get_mut_ref()); // Note that we need to be careful when putting the stdout handle // back into the task. If the handle was set to `Some` while @@ -184,22 +185,29 @@ fn with_task_stdout(f: |&mut Writer|) { let prev = util::replace(&mut t.get().stdout, my_stdout); drop(t); drop(prev); + ret } None => { struct Stdout; impl Writer for Stdout { - fn write(&mut self, data: &[u8]) { + fn write(&mut self, data: &[u8]) -> IoResult<()> { unsafe { libc::write(libc::STDOUT_FILENO, data.as_ptr() as *libc::c_void, data.len() as libc::size_t); } + Ok(()) // just ignore the results } } let mut io = Stdout; - f(&mut io as &mut Writer); + f(&mut io as &mut Writer) } + }; + + match result { + Ok(()) => {} + Err(e) => fail!("failed printing to stdout: {}", e), } } @@ -226,8 +234,7 @@ pub fn print(s: &str) { /// `\n` character is printed to the console after the string. pub fn println(s: &str) { with_task_stdout(|io| { - io.write(s.as_bytes()); - io.write(['\n' as u8]); + io.write(s.as_bytes()).and_then(|()| io.write(['\n' as u8])) }) } @@ -249,7 +256,7 @@ pub struct StdReader { } impl Reader for StdReader { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { + fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> { let ret = match self.inner { TTY(ref mut tty) => tty.read(buf), File(ref mut file) => file.read(buf).map(|i| i as uint), @@ -260,15 +267,8 @@ impl Reader for StdReader { // return an actual EOF error, but apparently for stdin it's a // little different. Hence, here we convert a 0 length read to an // end-of-file indicator so the caller knows to stop reading. - Ok(0) => { - io_error::cond.raise(standard_error(EndOfFile)); - None - } - Ok(amt) => Some(amt), - Err(e) => { - io_error::cond.raise(e); - None - } + Ok(0) => { Err(standard_error(EndOfFile)) } + ret @ Ok(..) | ret @ Err(..) => ret, } } } @@ -289,24 +289,15 @@ impl StdWriter { /// /// This function will raise on the `io_error` condition if an error /// happens. - pub fn winsize(&mut self) -> Option<(int, int)> { + pub fn winsize(&mut self) -> IoResult<(int, int)> { match self.inner { - TTY(ref mut tty) => { - match tty.get_winsize() { - Ok(p) => Some(p), - Err(e) => { - io_error::cond.raise(e); - None - } - } - } + TTY(ref mut tty) => tty.get_winsize(), File(..) => { - io_error::cond.raise(IoError { + Err(IoError { kind: OtherIoError, desc: "stream is not a tty", detail: None, - }); - None + }) } } } @@ -318,20 +309,15 @@ impl StdWriter { /// /// This function will raise on the `io_error` condition if an error /// happens. - pub fn set_raw(&mut self, raw: bool) { + pub fn set_raw(&mut self, raw: bool) -> IoResult<()> { match self.inner { - TTY(ref mut tty) => { - match tty.set_raw(raw) { - Ok(()) => {}, - Err(e) => io_error::cond.raise(e), - } - } + TTY(ref mut tty) => tty.set_raw(raw), File(..) => { - io_error::cond.raise(IoError { + Err(IoError { kind: OtherIoError, desc: "stream is not a tty", detail: None, - }); + }) } } } @@ -346,14 +332,10 @@ impl StdWriter { } impl Writer for StdWriter { - fn write(&mut self, buf: &[u8]) { - let ret = match self.inner { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { + 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/io/timer.rs b/src/libstd/io/timer.rs index 24eaf6adf3f..692aaa7afd0 100644 --- a/src/libstd/io/timer.rs +++ b/src/libstd/io/timer.rs @@ -39,8 +39,8 @@ loop { */ use comm::Port; -use option::Option; use rt::rtio::{IoFactory, LocalIo, RtioTimer}; +use io::IoResult; pub struct Timer { priv obj: ~RtioTimer @@ -48,7 +48,8 @@ pub struct Timer { /// Sleep the current task for `msecs` milliseconds. pub fn sleep(msecs: u64) { - let mut timer = Timer::new().expect("timer::sleep: could not create a Timer"); + let timer = Timer::new(); + let mut timer = timer.ok().expect("timer::sleep: could not create a Timer"); timer.sleep(msecs) } @@ -57,7 +58,7 @@ impl Timer { /// Creates a new timer which can be used to put the current task to sleep /// for a number of milliseconds, or to possibly create channels which will /// get notified after an amount of time has passed. - pub fn new() -> Option<Timer> { + pub fn new() -> IoResult<Timer> { LocalIo::maybe_raise(|io| io.timer_init().map(|t| Timer { obj: t })) } diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs index a1794d24fc9..2c7f64ba747 100644 --- a/src/libstd/io/util.rs +++ b/src/libstd/io/util.rs @@ -7,8 +7,10 @@ // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. + use prelude::*; use cmp; +use io; use vec::bytes::MutableByteVector; /// Wraps a `Reader`, limiting the number of bytes that can be read from it. @@ -25,9 +27,9 @@ impl<'a, R: Reader> LimitReader<'a, R> { } impl<'a, R: Reader> Reader for LimitReader<'a, R> { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { + fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> { if self.limit == 0 { - return None; + return Err(io::standard_error(io::EndOfFile)); } let len = cmp::min(self.limit, buf.len()); @@ -43,7 +45,7 @@ pub struct NullWriter; impl Writer for NullWriter { #[inline] - fn write(&mut self, _buf: &[u8]) { } + fn write(&mut self, _buf: &[u8]) -> io::IoResult<()> { Ok(()) } } /// A `Reader` which returns an infinite stream of 0 bytes, like /dev/zero. @@ -51,9 +53,9 @@ pub struct ZeroReader; impl Reader for ZeroReader { #[inline] - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { + fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> { buf.set_memory(0); - Some(buf.len()) + Ok(buf.len()) } } @@ -62,8 +64,8 @@ pub struct NullReader; impl Reader for NullReader { #[inline] - fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { - None + fn read(&mut self, _buf: &mut [u8]) -> io::IoResult<uint> { + Err(io::standard_error(io::EndOfFile)) } } @@ -81,17 +83,21 @@ impl MultiWriter { impl Writer for MultiWriter { #[inline] - fn write(&mut self, buf: &[u8]) { + fn write(&mut self, buf: &[u8]) -> io::IoResult<()> { + let mut ret = Ok(()); for writer in self.writers.mut_iter() { - writer.write(buf); + ret = ret.and(writer.write(buf)); } + return ret; } #[inline] - fn flush(&mut self) { + fn flush(&mut self) -> io::IoResult<()> { + let mut ret = Ok(()); for writer in self.writers.mut_iter() { - writer.flush(); + ret = ret.and(writer.flush()); } + return ret; } } @@ -111,20 +117,25 @@ impl<R: Reader, I: Iterator<R>> ChainedReader<I, R> { } impl<R: Reader, I: Iterator<R>> Reader for ChainedReader<I, R> { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { + fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> { loop { - match self.cur_reader { + let err = match self.cur_reader { Some(ref mut r) => { match r.read(buf) { - Some(len) => return Some(len), - None => {} + Ok(len) => return Ok(len), + Err(ref e) if e.kind == io::EndOfFile => None, + Err(e) => Some(e), } } None => break + }; + self.cur_reader = self.readers.next(); + match err { + Some(e) => return Err(e), + None => {} } - self.cur_reader = self.readers.next() } - None + Err(io::standard_error(io::EndOfFile)) } } @@ -150,22 +161,23 @@ impl<R: Reader, W: Writer> TeeReader<R, W> { } impl<R: Reader, W: Writer> Reader for TeeReader<R, W> { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { - self.reader.read(buf).map(|len| { - self.writer.write(buf.slice_to(len)); - len + fn read(&mut self, buf: &mut [u8]) -> io::IoResult<uint> { + self.reader.read(buf).and_then(|len| { + self.writer.write(buf.slice_to(len)).map(|()| len) }) } } /// Copies all data from a `Reader` to a `Writer`. -pub fn copy<R: Reader, W: Writer>(r: &mut R, w: &mut W) { +pub fn copy<R: Reader, W: Writer>(r: &mut R, w: &mut W) -> io::IoResult<()> { let mut buf = [0, ..super::DEFAULT_BUF_SIZE]; loop { - match r.read(buf) { - Some(len) => w.write(buf.slice_to(len)), - None => break - } + let len = match r.read(buf) { + Ok(len) => len, + Err(ref e) if e.kind == io::EndOfFile => return Ok(()), + Err(e) => return Err(e), + }; + if_ok!(w.write(buf.slice_to(len))); } } |
