diff --git a/src/libnative/io/timer_timerfd.rs b/src/libnative/io/timer_timerfd.rs index ca20314997e8c..7c22e90bbffe2 100644 --- a/src/libnative/io/timer_timerfd.rs +++ b/src/libnative/io/timer_timerfd.rs @@ -96,7 +96,7 @@ fn helper(input: libc::c_int, messages: Port) { if fd == input { let mut buf = [0, ..1]; // drain the input file descriptor of its input - FileDesc::new(fd, false).inner_read(buf).unwrap(); + let _ = FileDesc::new(fd, false).inner_read(buf).unwrap(); incoming = true; } else { let mut bits = [0, ..8]; @@ -104,7 +104,7 @@ fn helper(input: libc::c_int, messages: Port) { // // FIXME: should this perform a send() this number of // times? - FileDesc::new(fd, false).inner_read(bits).unwrap(); + let _ = FileDesc::new(fd, false).inner_read(bits).unwrap(); let remove = { match map.find(&fd).expect("fd unregistered") { &(ref c, oneshot) => !c.try_send(()) || oneshot @@ -166,7 +166,8 @@ impl Timer { } pub fn sleep(ms: u64) { - unsafe { libc::usleep((ms * 1000) as libc::c_uint); } + // FIXME: this can fail because of EINTR, what do do? + let _ = unsafe { libc::usleep((ms * 1000) as libc::c_uint) }; } fn remove(&mut self) { diff --git a/src/libstd/fmt/mod.rs b/src/libstd/fmt/mod.rs index e0944dea9b276..0bc567b270a4c 100644 --- a/src/libstd/fmt/mod.rs +++ b/src/libstd/fmt/mod.rs @@ -163,9 +163,10 @@ method of the signature: ```rust # use std; +# mod fmt { pub type Result = (); } # struct T; # trait SomeName { -fn fmt(value: &T, f: &mut std::fmt::Formatter); +fn fmt(value: &T, f: &mut std::fmt::Formatter) -> fmt::Result; # } ``` @@ -174,7 +175,14 @@ emit output into the `f.buf` stream. It is up to each format trait implementation to correctly adhere to the requested formatting parameters. The values of these parameters will be listed in the fields of the `Formatter` struct. In order to help with this, the `Formatter` struct also provides some -helper methods. An example of implementing the formatting traits would look +helper methods. + +Additionally, the return value of this function is `fmt::Result` which is a +typedef to `Result<(), IoError>` (also known as `IoError<()>`). Formatting +implementations should ensure that they return errors from `write!` correctly +(propagating errors upward). + +An example of implementing the formatting traits would look like: ```rust @@ -187,7 +195,7 @@ struct Vector2D { } impl fmt::Show for Vector2D { - fn fmt(obj: &Vector2D, f: &mut fmt::Formatter) { + fn fmt(obj: &Vector2D, f: &mut fmt::Formatter) -> fmt::Result { // The `f.buf` value is of the type `&mut io::Writer`, which is what th // write! macro is expecting. Note that this formatting ignores the // various flags provided to format strings. @@ -198,7 +206,7 @@ impl fmt::Show for Vector2D { // Different traits allow different forms of output of a type. The meaning of // this format is to print the magnitude of a vector. impl fmt::Binary for Vector2D { - fn fmt(obj: &Vector2D, f: &mut fmt::Formatter) { + fn fmt(obj: &Vector2D, f: &mut fmt::Formatter) -> fmt::Result { let magnitude = (obj.x * obj.x + obj.y * obj.y) as f64; let magnitude = magnitude.sqrt(); @@ -207,7 +215,7 @@ impl fmt::Binary for Vector2D { // for details, and the function `pad` can be used to pad strings. let decimals = f.precision.unwrap_or(3); let string = f64::to_str_exact(magnitude, decimals); - f.pad_integral(string.as_bytes(), "", true); + f.pad_integral(string.as_bytes(), "", true) } } @@ -242,6 +250,7 @@ strings and instead directly write the output. Under the hood, this function is actually invoking the `write` function defined in this module. Example usage is: ```rust +# #[allow(unused_must_use)]; use std::io; let mut w = io::MemWriter::new(); @@ -655,11 +664,12 @@ uniform_fn_call_workaround! { /// # Example /// /// ```rust +/// # #[allow(unused_must_use)]; /// use std::fmt; /// use std::io; /// /// let w = &mut io::stdout() as &mut io::Writer; -/// format_args!(|args| { fmt::write(w, args) }, "Hello, {}!", "world"); +/// format_args!(|args| { fmt::write(w, args); }, "Hello, {}!", "world"); /// ``` pub fn write(output: &mut io::Writer, args: &Arguments) -> Result { unsafe { write_unsafe(output, args.fmt, args.args) } diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index e3bc97b6f28f0..256f9d325f3ed 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -31,14 +31,13 @@ use vec; /// ```rust /// use std::io::{BufferedReader, File}; /// -/// # let _g = ::std::io::ignore_io_error(); /// let file = File::open(&Path::new("message.txt")); /// let mut reader = BufferedReader::new(file); /// /// let mut buf = [0, ..100]; /// match reader.read(buf) { -/// Some(nread) => println!("Read {} bytes", nread), -/// None => println!("At the end of the file!") +/// Ok(nread) => println!("Read {} bytes", nread), +/// Err(e) => println!("error reading: {}", e) /// } /// ``` pub struct BufferedReader { @@ -121,9 +120,9 @@ impl Reader for BufferedReader { /// # Example /// /// ```rust +/// # #[allow(unused_must_use)]; /// use std::io::{BufferedWriter, File}; /// -/// # let _g = ::std::io::ignore_io_error(); /// let file = File::open(&Path::new("message.txt")); /// let mut writer = BufferedWriter::new(file); /// @@ -268,9 +267,9 @@ impl Reader for InternalBufferedWriter { /// # Example /// /// ```rust +/// # #[allow(unused_must_use)]; /// use std::io::{BufferedStream, File}; /// -/// # let _g = ::std::io::ignore_io_error(); /// let file = File::open(&Path::new("message.txt")); /// let mut stream = BufferedStream::new(file); /// @@ -279,8 +278,8 @@ impl Reader for InternalBufferedWriter { /// /// let mut buf = [0, ..100]; /// match stream.read(buf) { -/// Some(nread) => println!("Read {} bytes", nread), -/// None => println!("At the end of the stream!") +/// Ok(nread) => println!("Read {} bytes", nread), +/// Err(e) => println!("error reading: {}", e) /// } /// ``` pub struct BufferedStream { diff --git a/src/libstd/io/fs.rs b/src/libstd/io/fs.rs index 1b669539288da..ef1b1a56ec0e0 100644 --- a/src/libstd/io/fs.rs +++ b/src/libstd/io/fs.rs @@ -14,11 +14,11 @@ This module provides a set of functions and traits for working 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 `Path` object. +with various filesystem operations. They all operate on `Path` objects. All operations in this module, including those as part of `File` et al -block the task during execution. Most will raise `std::io::io_error` -conditions in the event of failure. +block the task during execution. In the event of failure, all functions/methods +will return an `IoResult` type with an `Err` value. Also included in this module is an implementation block on the `Path` object defined in `std::path::Path`. The impl adds useful methods about inspecting the @@ -42,7 +42,7 @@ file.write(bytes!("foobar")); let mut file = File::open(&path); file.read_to_end(); -println!("{}", path.stat().size); +println!("{}", path.stat().unwrap().size); # drop(file); fs::unlink(&path); ``` @@ -68,11 +68,12 @@ use vec::{OwnedVector, ImmutableVector}; /// Can be constructed via `File::open()`, `File::create()`, and /// `File::open_mode()`. /// -/// # Errors +/// # Error /// -/// This type will raise an io_error condition if operations are attempted against -/// it for which its underlying file descriptor was not configured at creation -/// time, via the `FileAccess` parameter to `File::open_mode()`. +/// This type will return errors as an `IoResult` if operations are +/// attempted against it for which its underlying file descriptor was not +/// configured at creation time, via the `FileAccess` parameter to +/// `File::open_mode()`. pub struct File { priv fd: ~RtioFileStream, priv path: Path, @@ -85,7 +86,7 @@ impl File { /// /// # Example /// - /// ```rust + /// ```rust,should_fail /// use std::io::{File, Open, ReadWrite}; /// /// let p = Path::new("/some/file/path.txt"); @@ -107,12 +108,12 @@ impl File { /// /// Note that, with this function, a `File` is returned regardless of the /// access-limitations indicated by `FileAccess` (e.g. calling `write` on a - /// `File` opened as `Read` will raise an `io_error` condition at runtime). + /// `File` opened as `Read` will return an error at runtime). /// - /// # Errors + /// # Error /// - /// This function will raise an `io_error` condition under a number of - /// different circumstances, to include but not limited to: + /// This function will return an error under a number of different + /// circumstances, to include but not limited to: /// /// * Opening a file that does not exist with `Read` access. /// * Attempting to open a file with a `FileAccess` that the user lacks @@ -164,7 +165,7 @@ impl 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")); + /// # ::std::io::fs::unlink(&Path::new("foo.txt")); /// ``` pub fn create(path: &Path) -> IoResult { File::open_mode(path, Truncate, Write) @@ -178,10 +179,6 @@ impl File { /// Synchronizes all modifications to this file to its permanent storage /// device. This will flush any internal buffers necessary to perform this /// operation. - /// - /// # Errors - /// - /// This function will raise on the `io_error` condition on failure. pub fn fsync(&mut self) -> IoResult<()> { self.fd.fsync() } @@ -190,10 +187,6 @@ impl File { /// file metadata to the filesystem. This is intended for use case which /// must synchronize content, but don't need the metadata on disk. The goal /// of this method is to reduce disk operations. - /// - /// # Errors - /// - /// This function will raise on the `io_error` condition on failure. pub fn datasync(&mut self) -> IoResult<()> { self.fd.datasync() } @@ -206,10 +199,6 @@ impl File { /// be shrunk. If it is greater than the current file's size, then the file /// will be extended to `size` and have all of the intermediate data filled /// in with 0s. - /// - /// # Errors - /// - /// On error, this function will raise on the `io_error` condition. pub fn truncate(&mut self, size: i64) -> IoResult<()> { self.fd.truncate(size) } @@ -239,11 +228,11 @@ impl File { /// guaranteed that a file is immediately deleted (e.g. depending on /// platform, other open file descriptors may prevent immediate removal) /// -/// # Errors +/// # Error /// -/// 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. +/// This function will return an error 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) -> IoResult<()> { LocalIo::maybe_raise(|io| io.fs_unlink(&path.to_c_str())) } @@ -259,7 +248,6 @@ pub fn unlink(path: &Path) -> IoResult<()> { /// # Example /// /// ```rust -/// use std::io; /// use std::io::fs; /// /// let p = Path::new("/some/file/path.txt"); @@ -269,11 +257,11 @@ pub fn unlink(path: &Path) -> IoResult<()> { /// } /// ``` /// -/// # Errors +/// # Error /// -/// 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. +/// This call will return an error 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) -> IoResult { LocalIo::maybe_raise(|io| { io.fs_stat(&path.to_c_str()) @@ -285,7 +273,7 @@ pub fn stat(path: &Path) -> IoResult { /// information about the symlink file instead of the file that it points /// to. /// -/// # Errors +/// # Error /// /// See `stat` pub fn lstat(path: &Path) -> IoResult { @@ -305,11 +293,11 @@ pub fn lstat(path: &Path) -> IoResult { /// fs::rename(&Path::new("foo"), &Path::new("bar")); /// ``` /// -/// # Errors +/// # Error /// -/// 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. +/// Will return an error 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) -> IoResult<()> { LocalIo::maybe_raise(|io| io.fs_rename(&from.to_c_str(), &to.to_c_str())) } @@ -329,10 +317,10 @@ pub fn rename(from: &Path, to: &Path) -> IoResult<()> { /// fs::copy(&Path::new("foo.txt"), &Path::new("bar.txt")); /// ``` /// -/// # Errors +/// # Error /// -/// Will raise an `io_error` condition is the following situations, but is -/// not limited to just these cases: +/// Will return an error in the following situations, but is not limited to +/// just these cases: /// /// * The `from` path is not a file /// * The `from` file does not exist @@ -373,7 +361,7 @@ pub fn copy(from: &Path, to: &Path) -> IoResult<()> { /// # Example /// /// ```rust -/// # #[allow(unused_must_use)] +/// # #[allow(unused_must_use)]; /// use std::io; /// use std::io::fs; /// @@ -383,20 +371,16 @@ pub fn copy(from: &Path, to: &Path) -> IoResult<()> { /// fs::chmod(&Path::new("file.exe"), io::UserExec); /// ``` /// -/// # Errors +/// # Error /// -/// 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 +/// If this function encounters an I/O error, it will return an `Err` value. +/// 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) -> 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. -/// -/// # Errors -/// -/// This function will raise on the `io_error` condition on failure. pub fn chown(path: &Path, uid: int, gid: int) -> IoResult<()> { LocalIo::maybe_raise(|io| io.fs_chown(&path.to_c_str(), uid, gid)) } @@ -404,31 +388,22 @@ pub fn chown(path: &Path, uid: int, gid: int) -> IoResult<()> { /// Creates a new hard link on the filesystem. The `dst` path will be a /// link pointing to the `src` path. Note that systems often require these /// two paths to both be located on the same filesystem. -/// -/// # Errors -/// -/// This function will raise on the `io_error` condition on failure. 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 /// symlink pointing to the `src` path. -/// -/// # Errors -/// -/// This function will raise on the `io_error` condition on failure. 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. /// -/// # Errors +/// # Error /// -/// 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. +/// This function will return an error 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) -> IoResult { LocalIo::maybe_raise(|io| io.fs_readlink(&path.to_c_str())) } @@ -446,11 +421,10 @@ pub fn readlink(path: &Path) -> IoResult { /// fs::mkdir(&p, io::UserRWX); /// ``` /// -/// # Errors +/// # Error /// -/// 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. +/// This call will return an error 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) -> IoResult<()> { LocalIo::maybe_raise(|io| io.fs_mkdir(&path.to_c_str(), mode)) } @@ -467,11 +441,10 @@ pub fn mkdir(path: &Path, mode: FilePermission) -> IoResult<()> { /// fs::rmdir(&p); /// ``` /// -/// # Errors +/// # Error /// -/// 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. +/// This call will return an error 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) -> IoResult<()> { LocalIo::maybe_raise(|io| io.fs_rmdir(&path.to_c_str())) } @@ -481,26 +454,32 @@ pub fn rmdir(path: &Path) -> IoResult<()> { /// # Example /// /// ```rust +/// use std::io; /// use std::io::fs; /// /// // one possible implementation of fs::walk_dir only visiting files -/// fn visit_dirs(dir: &Path, cb: |&Path|) { +/// fn visit_dirs(dir: &Path, cb: |&Path|) -> io::IoResult<()> { /// if dir.is_dir() { -/// let contents = fs::readdir(dir).unwrap(); +/// let contents = if_ok!(fs::readdir(dir)); /// for entry in contents.iter() { -/// if entry.is_dir() { visit_dirs(entry, cb); } -/// else { cb(entry); } +/// if entry.is_dir() { +/// if_ok!(visit_dirs(entry, |p| cb(p))); +/// } else { +/// cb(entry); +/// } /// } +/// Ok(()) +/// } else { +/// Err(io::standard_error(io::InvalidInput)) /// } -/// else { fail!("nope"); } /// } /// ``` /// -/// # Errors +/// # Error /// -/// 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 +/// Will return an error 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) -> IoResult<~[Path]> { LocalIo::maybe_raise(|io| { io.fs_readdir(&path.to_c_str(), 0) @@ -539,11 +518,10 @@ impl Iterator for Directories { /// Recursively create a directory and all of its parent components if they /// are missing. /// -/// # Errors +/// # Error /// -/// This function will raise on the `io_error` condition if an error -/// happens, see `fs::mkdir` for more information about error conditions -/// and performance. +/// This function will return an `Err` value if an error happens, see +/// `fs::mkdir` for more information about error conditions and performance. pub fn mkdir_recursive(path: &Path, mode: FilePermission) -> IoResult<()> { // tjc: if directory exists but with different permissions, // should we return false? @@ -559,11 +537,10 @@ pub fn mkdir_recursive(path: &Path, mode: FilePermission) -> IoResult<()> { /// Removes a directory at this path, after removing all its contents. Use /// carefully! /// -/// # Errors +/// # Error /// -/// This function will raise on the `io_error` condition if an error -/// happens. See `file::unlink` and `fs::readdir` for possible error -/// conditions. +/// This function will return an `Err` value if an error happens. See +/// `file::unlink` and `fs::readdir` for possible error conditions. pub fn rmdir_recursive(path: &Path) -> IoResult<()> { let children = if_ok!(readdir(path)); for child in children.iter() { @@ -581,11 +558,6 @@ pub fn rmdir_recursive(path: &Path) -> IoResult<()> { /// The file at the path specified will have its last access time set to /// `atime` and its modification time set to `mtime`. The times specified should /// be in milliseconds. -/// -/// # Errors -/// -/// 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) -> IoResult<()> { LocalIo::maybe_raise(|io| io.fs_utime(&path.to_c_str(), atime, mtime)) @@ -639,7 +611,7 @@ impl path::Path { /// filesystem. This will return true if the path points to either a /// directory or a file. /// - /// # Errors + /// # Error /// /// Will not raise a condition pub fn exists(&self) -> bool { @@ -651,7 +623,7 @@ impl path::Path { /// to non-existent locations or directories or other non-regular files /// (named pipes, etc). /// - /// # Errors + /// # Error /// /// Will not raise a condition pub fn is_file(&self) -> bool { @@ -666,7 +638,7 @@ impl path::Path { /// Will return false for paths to non-existent locations or if the item is /// not a directory (eg files, named pipes, links, etc) /// - /// # Errors + /// # Error /// /// Will not raise a condition pub fn is_dir(&self) -> bool { diff --git a/src/libstd/io/mem.rs b/src/libstd/io/mem.rs index 3a6aa1939a411..395ece17eded6 100644 --- a/src/libstd/io/mem.rs +++ b/src/libstd/io/mem.rs @@ -25,6 +25,7 @@ use vec::{Vector, ImmutableVector, MutableVector, OwnedCloneableVector}; /// # Example /// /// ```rust +/// # #[allow(unused_must_use)]; /// use std::io::MemWriter; /// /// let mut w = MemWriter::new(); @@ -113,11 +114,12 @@ impl Seek for MemWriter { /// # Example /// /// ```rust +/// # #[allow(unused_must_use)]; /// use std::io::MemReader; /// /// let mut r = MemReader::new(~[0, 1, 2]); /// -/// assert_eq!(r.read_to_end(), ~[0, 1, 2]); +/// assert_eq!(r.read_to_end().unwrap(), ~[0, 1, 2]); /// ``` pub struct MemReader { priv buf: ~[u8], @@ -182,12 +184,13 @@ impl Buffer for MemReader { /// Writes to a fixed-size byte slice /// -/// If a write will not fit in the buffer, it raises the `io_error` -/// condition and does not write any data. +/// If a write will not fit in the buffer, it returns an error and does not +/// write any data. /// /// # Example /// /// ```rust +/// # #[allow(unused_must_use)]; /// use std::io::BufWriter; /// /// let mut buf = [0, ..4]; @@ -252,12 +255,13 @@ impl<'a> Seek for BufWriter<'a> { /// # Example /// /// ```rust +/// # #[allow(unused_must_use)]; /// use std::io::BufReader; /// /// let mut buf = [0, 1, 2, 3]; /// let mut r = BufReader::new(buf); /// -/// assert_eq!(r.read_to_end(), ~[0, 1, 2, 3]); +/// assert_eq!(r.read_to_end().unwrap(), ~[0, 1, 2, 3]); /// ``` pub struct BufReader<'a> { priv buf: &'a [u8], diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index bd7a349a2aaac..58a35e96393a3 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -29,7 +29,6 @@ Some examples of obvious things you might want to do use std::io::BufferedReader; use std::io::stdin; - # let _g = ::std::io::ignore_io_error(); let mut stdin = BufferedReader::new(stdin()); for line in stdin.lines() { print!("{}", line); @@ -41,7 +40,6 @@ Some examples of obvious things you might want to do ```rust use std::io::File; - # let _g = ::std::io::ignore_io_error(); let contents = File::open(&Path::new("message.txt")).read_to_end(); ``` @@ -50,7 +48,6 @@ Some examples of obvious things you might want to do ```rust use std::io::File; - # let _g = ::std::io::ignore_io_error(); let mut file = File::create(&Path::new("message.txt")); file.write(bytes!("hello, file!\n")); # drop(file); @@ -63,7 +60,6 @@ Some examples of obvious things you might want to do use std::io::BufferedReader; use std::io::File; - # let _g = ::std::io::ignore_io_error(); let path = Path::new("message.txt"); let mut file = BufferedReader::new(File::open(&path)); for line in file.lines() { @@ -77,7 +73,6 @@ Some examples of obvious things you might want to do use std::io::BufferedReader; use std::io::File; - # let _g = ::std::io::ignore_io_error(); let path = Path::new("message.txt"); let mut file = BufferedReader::new(File::open(&path)); let lines: ~[~str] = file.lines().collect(); @@ -91,7 +86,6 @@ Some examples of obvious things you might want to do use std::io::net::ip::SocketAddr; use std::io::net::tcp::TcpStream; - # let _g = ::std::io::ignore_io_error(); let addr = from_str::("127.0.0.1:8080").unwrap(); let mut socket = TcpStream::connect(addr).unwrap(); socket.write(bytes!("GET / HTTP/1.0\n\n")); @@ -168,72 +162,50 @@ asynchronous request completes. # Error Handling I/O is an area where nearly every operation can result in unexpected -errors. It should allow errors to be handled efficiently. -It needs to be convenient to use I/O when you don't care -about dealing with specific errors. +errors. Errors should be painfully visible when they happen, and handling them +should be easy to work with. It should be convenient to handle specific I/O +errors, and it should also be convenient to not deal with I/O errors. Rust's I/O employs a combination of techniques to reduce boilerplate while still providing feedback about errors. The basic strategy: -* Errors are fatal by default, resulting in task failure -* Errors raise the `io_error` condition which provides an opportunity to inspect - an IoError object containing details. -* Return values must have a sensible null or zero value which is returned - if a condition is handled successfully. This may be an `Option`, an empty - vector, or other designated error value. -* Common traits are implemented for `Option`, e.g. `impl Reader for Option`, - so that nullable values do not have to be 'unwrapped' before use. +* All I/O operations return `IoResult` which is equivalent to + `Result`. The core `Result` type is defined in the `std::result` + module. +* If the `Result` type goes unused, then the compiler will by default emit a + warning about the unused result. +* Common traits are implemented for `IoResult`, e.g. + `impl Reader for IoResult`, so that error values do not have + to be 'unwrapped' before use. These features combine in the API to allow for expressions like `File::create(&Path::new("diary.txt")).write(bytes!("Met a girl.\n"))` without having to worry about whether "diary.txt" exists or whether the write succeeds. As written, if either `new` or `write_line` -encounters an error the task will fail. +encounters an error then the result of the entire expression will +be an error. If you wanted to handle the error though you might write: ```rust use std::io::File; -use std::io::{IoError, io_error}; -let mut error = None; -io_error::cond.trap(|e: IoError| { - error = Some(e); -}).inside(|| { - File::create(&Path::new("diary.txt")).write(bytes!("Met a girl.\n")); -}); - -if error.is_some() { - println!("failed to write my diary"); +match File::create(&Path::new("diary.txt")).write(bytes!("Met a girl.\n")) { + Ok(()) => { /* succeeded */ } + Err(e) => println!("failed to write to my diary: {}", e), } + # ::std::io::fs::unlink(&Path::new("diary.txt")); ``` -FIXME: Need better condition handling syntax - -In this case the condition handler will have the opportunity to -inspect the IoError raised by either the call to `new` or the call to -`write_line`, but then execution will continue. - -So what actually happens if `new` encounters an error? To understand -that it's important to know that what `new` returns is not a `File` -but an `Option`. If the file does not open, and the condition -is handled, then `new` will simply return `None`. Because there is an -implementation of `Writer` (the trait required ultimately required for -types to implement `write_line`) there is no need to inspect or unwrap -the `Option` and we simply call `write_line` on it. If `new` -returned a `None` then the followup call to `write_line` will also -raise an error. - -## Concerns about this strategy - -This structure will encourage a programming style that is prone -to errors similar to null pointer dereferences. -In particular code written to ignore errors and expect conditions to be unhandled -will start passing around null or zero objects when wrapped in a condition handler. - -* FIXME: How should we use condition handlers that return values? -* FIXME: Should EOF raise default conditions when EOF is not an error? +So what actually happens if `create` encounters an error? +It's important to know that what `new` returns is not a `File` +but an `IoResult`. If the file does not open, then `new` will simply +return `Err(..)`. Because there is an implementation of `Writer` (the trait +required ultimately required for types to implement `write_line`) there is no +need to inspect or unwrap the `IoResult` and we simply call `write_line` +on it. If `new` returned an `Err(..)` then the followup call to `write_line` +will also return an error. # Issues with i/o scheduler affinity, work stealing, task pinning @@ -460,40 +432,23 @@ impl ToStr for IoErrorKind { pub trait Reader { - // Only two methods which need to get implemented for this trait + // Only method which need to get implemented for this trait /// Read bytes, up to the length of `buf` and place them in `buf`. /// Returns the number of bytes read. The number of bytes read my - /// be less than the number requested, even 0. Returns `None` on EOF. - /// - /// # Failure + /// be less than the number requested, even 0. Returns `Err` on EOF. /// - /// 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` (FIXME see below). + /// # Error /// - /// # FIXME - /// - /// * Should raise_default error on eof? - /// * If the condition is handled it should still return the bytes read, - /// in which case there's no need to return Option - but then you *have* - /// to install a handler to detect eof. - /// - /// This doesn't take a `len` argument like the old `read`. - /// 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? + /// If an error occurs during this I/O operation, then it is returned as + /// `Err(IoError)`. Note that end-of-file is considered an error, and can be + /// inspected for in the error's `kind` field. Also note that reading 0 + /// bytes is not considered an error in all circumstances fn read(&mut self, buf: &mut [u8]) -> IoResult; // Convenient helper methods based on the above methods - /// Reads a single byte. Returns `None` on EOF. - /// - /// # Failure - /// - /// Raises the same conditions as the `read` method. Returns - /// `None` if the condition is handled. + /// Reads a single byte. Returns `Err` on EOF. fn read_byte(&mut self) -> IoResult { let mut buf = [0]; loop { @@ -511,13 +466,9 @@ pub trait Reader { /// Reads `len` bytes and appends them to a vector. /// /// May push fewer than the requested number of bytes on error - /// or EOF. Returns true on success, false on EOF or error. - /// - /// # Failure - /// - /// 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. + /// or EOF. If `Ok(())` is returned, then all of the requested bytes were + /// pushed on to the vector, otherwise the amount `len` bytes couldn't be + /// read (an error was encountered), and the error is returned. fn push_bytes(&mut self, buf: &mut ~[u8], len: uint) -> IoResult<()> { let start_len = buf.len(); let mut total_read = 0; @@ -542,29 +493,36 @@ pub trait Reader { /// Reads `len` bytes and gives you back a new vector of length `len` /// - /// # Failure + /// # Error /// - /// 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. + /// Fails with the same conditions as `read`. Additionally returns error on + /// on EOF. Note that if an error is returned, then some number of bytes may + /// have already been consumed from the underlying reader, and they are lost + /// (not returned as part of the error). If this is unacceptable, then it is + /// recommended to use the `push_bytes` or `read` methods. fn read_bytes(&mut self, len: uint) -> IoResult<~[u8]> { let mut buf = vec::with_capacity(len); - if_ok!(self.push_bytes(&mut buf, len)); - return Ok(buf); + match self.push_bytes(&mut buf, len) { + Ok(()) => Ok(buf), + Err(e) => Err(e), + } } /// Reads all remaining bytes from the stream. /// - /// # Failure + /// # Error + /// + /// Returns any non-EOF error immediately. Previously read bytes are + /// discarded when an error is returned. /// - /// Raises the same conditions as the `read` method except for - /// `EndOfFile` which is swallowed. + /// When EOF is encountered, all bytes read up to that point are returned, + /// but if 0 bytes have been read then the EOF error is returned. fn read_to_end(&mut self) -> IoResult<~[u8]> { let mut buf = vec::with_capacity(DEFAULT_BUF_SIZE); loop { match self.push_bytes(&mut buf, DEFAULT_BUF_SIZE) { Ok(()) => {} - Err(ref e) if e.kind == EndOfFile => break, + Err(ref e) if buf.len() > 0 && e.kind == EndOfFile => break, Err(e) => return Err(e) } } @@ -574,10 +532,11 @@ pub trait Reader { /// Reads all of the remaining bytes of this stream, interpreting them as a /// UTF-8 encoded stream. The corresponding string is returned. /// - /// # Failure + /// # Error /// - /// 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. + /// This function returns all of the same errors as `read_to_end` with an + /// additional error if the reader's contents are not a valid sequence of + /// UTF-8 bytes. fn read_to_str(&mut self) -> IoResult<~str> { self.read_to_end().and_then(|s| { match str::from_utf8_owned(s) { @@ -590,11 +549,12 @@ pub trait Reader { /// Create an iterator that reads a single byte on /// each iteration, until EOF. /// - /// # Failure + /// # Error /// - /// Raises the same conditions as the `read` method, for - /// each call to its `.next()` method. - /// Ends the iteration if the condition is handled. + /// The iterator protocol causes all specifics about errors encountered to + /// be swallowed. All errors will be signified by returning `None` from the + /// iterator. If this is undesirable, it is recommended to use the + /// `read_byte` method. fn bytes<'r>(&'r mut self) -> extensions::Bytes<'r, Self> { extensions::Bytes::new(self) } @@ -825,11 +785,14 @@ fn extend_sign(val: u64, nbytes: uint) -> i64 { } pub trait Writer { - /// Write the given buffer + /// Write the entirety of a given buffer /// - /// # Failure + /// # Errors /// - /// Raises the `io_error` condition on error + /// If an error happens during the I/O operation, the error is returned as + /// `Err`. Note that it is considered an error if the entire buffer could + /// not be written, and if an error is returned then it is unknown how much + /// data (if any) was actually written. fn write(&mut self, buf: &[u8]) -> IoResult<()>; /// Flush this output stream, ensuring that all intermediately buffered @@ -1021,11 +984,11 @@ impl Stream for T {} /// an iteration, but continue to yield elements if iteration /// is attempted again. /// -/// # Failure +/// # Error /// -/// Raises the same conditions as the `read` method except for `EndOfFile` -/// which is swallowed. -/// Iteration yields `None` if the condition is handled. +/// This iterator will swallow all I/O errors, transforming `Err` values to +/// `None`. If errors need to be handled, it is recommended to use the +/// `read_line` method directly. pub struct Lines<'r, T> { priv buffer: &'r mut T, } @@ -1049,10 +1012,11 @@ pub trait Buffer: Reader { /// consumed from this buffer returned to ensure that the bytes are never /// returned twice. /// - /// # Failure + /// # Error /// - /// This function will raise on the `io_error` condition if a read error is - /// encountered. + /// This function will return an I/O error if the underlying reader was + /// read, but returned an error. Note that it is not an error to return a + /// 0-length buffer. fn fill<'a>(&'a mut self) -> IoResult<&'a [u8]>; /// Tells this buffer that `amt` bytes have been consumed from the buffer, @@ -1067,50 +1031,73 @@ pub trait Buffer: Reader { /// /// ```rust /// use std::io::{BufferedReader, stdin}; - /// # let _g = ::std::io::ignore_io_error(); /// /// let mut reader = BufferedReader::new(stdin()); /// - /// let input = reader.read_line().unwrap_or(~"nothing"); + /// let input = reader.read_line().ok().unwrap_or(~"nothing"); /// ``` /// - /// # Failure + /// # Error + /// + /// This function has the same error semantics as `read_until`: + /// + /// * All non-EOF errors will be returned immediately + /// * If an error is returned previously consumed bytes are lost + /// * EOF is only returned if no bytes have been read + /// * Reach EOF may mean that the delimiter is not present in the return + /// value /// - /// This function will raise on the `io_error` condition (except for - /// `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. + /// Additionally, this function can fail if the line of input read is not a + /// valid UTF-8 sequence of bytes. fn read_line(&mut self) -> IoResult<~str> { - self.read_until('\n' as u8).map(|line| str::from_utf8_owned(line).unwrap()) + self.read_until('\n' as u8).and_then(|line| + match str::from_utf8_owned(line) { + Some(s) => Ok(s), + None => Err(standard_error(InvalidInput)), + } + ) } /// Create an iterator that reads a line on each iteration until EOF. /// - /// # Failure + /// # Error /// - /// Iterator raises the same conditions as the `read` method - /// except for `EndOfFile`. + /// This iterator will transform all error values to `None`, discarding the + /// cause of the error. If this is undesirable, it is recommended to call + /// `read_line` directly. fn lines<'r>(&'r mut self) -> Lines<'r, Self> { - Lines { - buffer: self, - } + Lines { buffer: self } } /// Reads a sequence of bytes leading up to a specified delimiter. Once the /// specified byte is encountered, reading ceases and the bytes up to and /// including the delimiter are returned. /// - /// # Failure + /// # Error /// - /// This function will raise on the `io_error` condition if a read error is - /// encountered, except that `EndOfFile` is swallowed. + /// If any I/O error is encountered other than EOF, the error is immediately + /// returned. Note that this may discard bytes which have already been read, + /// and those bytes will *not* be returned. It is recommended to use other + /// methods if this case is worrying. + /// + /// If EOF is encountered, then this function will return EOF if 0 bytes + /// have been read, otherwise the pending byte buffer is returned. This + /// is the reason that the byte buffer returned may not always contain the + /// delimiter. fn read_until(&mut self, byte: u8) -> IoResult<~[u8]> { let mut res = ~[]; let mut used; loop { { - let available = if_ok!(self.fill()); + let available = match self.fill() { + Ok(n) => n, + Err(ref e) if res.len() > 0 && e.kind == EndOfFile => { + used = 0; + break + } + Err(e) => return Err(e) + }; match available.iter().position(|&b| b == byte) { Some(i) => { res.push_all(available.slice_to(i + 1)); @@ -1131,13 +1118,11 @@ pub trait Buffer: Reader { /// Reads the next utf8-encoded character from the underlying stream. /// - /// This will return `None` if the following sequence of bytes in the - /// stream are not a valid utf8-sequence, or if an I/O error is encountered. + /// # Error /// - /// # Failure - /// - /// This function will raise on the `io_error` condition if a read error is - /// encountered. + /// If an I/O error occurs, or EOF, then this function will return `Err`. + /// This function will also return error if the stream does not contain a + /// valid utf-8 encoded codepoint as the next few bytes in the stream. fn read_char(&mut self) -> IoResult { let first_byte = if_ok!(self.read_byte()); let width = str::utf8_char_width(first_byte); @@ -1186,15 +1171,17 @@ pub trait Seek { fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()>; } -/// A listener is a value that can consume itself to start listening for connections. +/// A listener is a value that can consume itself to start listening for +/// connections. +/// /// Doing so produces some sort of Acceptor. pub trait Listener> { /// Spin up the listener and start queuing incoming connections /// - /// # Failure + /// # Error /// - /// Raises `io_error` condition. If the condition is handled, - /// then `listen` returns `None`. + /// Returns `Err` if this listener could not be bound to listen for + /// connections. In all cases, this listener is consumed. fn listen(self) -> IoResult; } @@ -1202,12 +1189,14 @@ pub trait Listener> { pub trait Acceptor { /// Wait for and accept an incoming connection /// - /// # Failure - /// Raise `io_error` condition. If the condition is handled, - /// then `accept` returns `None`. + /// # Error + /// + /// Returns `Err` if an I/O error is encountered. fn accept(&mut self) -> IoResult; - /// Create an iterator over incoming connection attempts + /// Create an iterator over incoming connection attempts. + /// + /// Note that I/O errors will be yielded by the iterator itself. fn incoming<'r>(&'r mut self) -> IncomingConnections<'r, Self> { IncomingConnections { inc: self } } @@ -1216,10 +1205,10 @@ pub trait Acceptor { /// An infinite iterator over incoming connection attempts. /// Calling `next` will block the task until a connection is attempted. /// -/// Since connection attempts can continue forever, this iterator always returns Some. -/// The Some contains another Option representing whether the connection attempt was succesful. -/// A successful connection will be wrapped in Some. -/// A failed connection is represented as a None and raises a condition. +/// Since connection attempts can continue forever, this iterator always returns +/// `Some`. The `Some` contains the `IoResult` representing whether the +/// connection attempt was succesful. A successful connection will be wrapped +/// in `Ok`. A failed connection is represented as an `Err`. pub struct IncomingConnections<'a, A> { priv inc: &'a mut A, } @@ -1265,7 +1254,7 @@ pub enum FileMode { } /// Access permissions with which the file should be opened. `File`s -/// opened with `Read` will raise an `io_error` condition if written to. +/// opened with `Read` will return an error if written to. pub enum FileAccess { Read, Write, diff --git a/src/libstd/io/net/addrinfo.rs b/src/libstd/io/net/addrinfo.rs index f72c6aecd6425..e9ffe97f1c356 100644 --- a/src/libstd/io/net/addrinfo.rs +++ b/src/libstd/io/net/addrinfo.rs @@ -70,10 +70,6 @@ pub struct Info { /// 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) -> IoResult<~[IpAddr]> { lookup(Some(host), None, None).map(|a| a.map(|i| i.address.ip)) } @@ -88,10 +84,6 @@ pub fn get_host_addresses(host: &str) -> IoResult<~[IpAddr]> { /// * 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. -/// /// 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) diff --git a/src/libstd/io/net/unix.rs b/src/libstd/io/net/unix.rs index 63a2ba3d0951a..ce95b987663f7 100644 --- a/src/libstd/io/net/unix.rs +++ b/src/libstd/io/net/unix.rs @@ -45,11 +45,6 @@ impl UnixStream { /// /// 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 /// /// ```rust @@ -86,11 +81,6 @@ impl UnixListener { /// /// 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 /// /// ``` diff --git a/src/libstd/io/pipe.rs b/src/libstd/io/pipe.rs index 75791164b8919..ca85707149b92 100644 --- a/src/libstd/io/pipe.rs +++ b/src/libstd/io/pipe.rs @@ -32,16 +32,14 @@ impl PipeStream { /// /// # Example /// - /// use std::libc; - /// use std::io::pipe; + /// ```rust + /// # #[allow(unused_must_use)]; + /// use std::libc; + /// use std::io::pipe::PipeStream; /// - /// 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. + /// let mut pipe = PipeStream::open(libc::STDERR_FILENO); + /// pipe.write(bytes!("Hello, stderr!")); + /// ``` pub fn open(fd: libc::c_int) -> IoResult { LocalIo::maybe_raise(|io| { io.pipe_open(fd).map(|obj| PipeStream { obj: obj }) diff --git a/src/libstd/io/process.rs b/src/libstd/io/process.rs index 87d47868d0af1..ccf3d4582def4 100644 --- a/src/libstd/io/process.rs +++ b/src/libstd/io/process.rs @@ -141,7 +141,7 @@ impl Process { /// Note that this is purely a wrapper around libuv's `uv_process_kill` /// function. /// - /// If the signal delivery fails, then the `io_error` condition is raised on + /// If the signal delivery fails, the corresponding error is returned. pub fn signal(&mut self, signal: int) -> IoResult<()> { self.handle.kill(signal) } diff --git a/src/libstd/io/result.rs b/src/libstd/io/result.rs index aa33ecb19e556..8e03cffd0fb24 100644 --- a/src/libstd/io/result.rs +++ b/src/libstd/io/result.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Implementations of I/O traits for the Option type +//! Implementations of I/O traits for the IoResult type //! //! 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. +//! These implementations allow e.g. `IoResult` to be used +//! as a `Reader` without unwrapping the result first. use clone::Clone; use result::{Ok, Err}; diff --git a/src/libstd/io/signal.rs b/src/libstd/io/signal.rs index 8096bfeddfd40..92b86afe24df5 100644 --- a/src/libstd/io/signal.rs +++ b/src/libstd/io/signal.rs @@ -113,11 +113,10 @@ impl Listener { /// a signal, and a later call to `recv` will return the signal that was /// received while no task was waiting on it. /// - /// # Failure + /// # Error /// /// 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. + /// be returned. pub fn register(&mut self, signum: Signum) -> io::IoResult<()> { if self.handles.contains_key(&signum) { return Ok(()); // self is already listening to signum, so succeed @@ -206,13 +205,11 @@ mod test { use super::User1; let mut s = Listener::new(); let mut called = false; - io::io_error::cond.trap(|_| { - called = true; - }).inside(|| { - if s.register(User1) { + match s.register(User1) { + Ok(..) => { fail!("Unexpected successful registry of signum {:?}", User1); } - }); - assert!(called); + Err(..) => {} + } } } diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 702ecfb603151..937ad0783e9ab 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -18,6 +18,7 @@ about the stream or terminal that it is attached to. # Example ```rust +# #[allow(unused_must_use)]; use std::io; let mut out = io::stdout(); @@ -283,12 +284,12 @@ impl StdWriter { /// 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)). + /// If successful, returns `Ok((width, height))`. /// - /// # Failure + /// # Error /// - /// This function will raise on the `io_error` condition if an error - /// happens. + /// This function will return an error if the output stream is not actually + /// connected to a TTY instance, or if querying the TTY instance fails. pub fn winsize(&mut self) -> IoResult<(int, int)> { match self.inner { TTY(ref mut tty) => tty.get_winsize(), @@ -305,10 +306,10 @@ impl StdWriter { /// Controls whether this output stream is a "raw stream" or simply a normal /// stream. /// - /// # Failure + /// # Error /// - /// This function will raise on the `io_error` condition if an error - /// happens. + /// This function will return an error if the output stream is not actually + /// connected to a TTY instance, or if querying the TTY instance fails. pub fn set_raw(&mut self, raw: bool) -> IoResult<()> { match self.inner { TTY(ref mut tty) => tty.set_raw(raw), diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 2457917d2e4d1..8815f88d694e3 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -372,9 +372,9 @@ pub fn self_exe_name() -> Option { fn load_self() -> Option<~[u8]> { use std::io; - match io::result(|| io::fs::readlink(&Path::new("/proc/self/exe"))) { - Ok(Some(path)) => Some(path.as_vec().to_owned()), - Ok(None) | Err(..) => None + match io::fs::readlink(&Path::new("/proc/self/exe")) { + Ok(path) => Some(path.as_vec().to_owned()), + Err(..) => None } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 17b0b7b9c3849..f0ef5014ca817 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2059,21 +2059,17 @@ pub fn print_generics(s: &mut State, } else { let idx = idx - generics.lifetimes.len(); let param = generics.ty_params.get(idx); -<<<<<<< HEAD - print_ident(s, param.ident); - print_bounds(s, ¶m.bounds, false); + if_ok!(print_ident(s, param.ident)); + if_ok!(print_bounds(s, ¶m.bounds, false)); match param.default { Some(default) => { - space(&mut s.s); - word_space(s, "="); - print_type(s, default); + if_ok!(space(&mut s.s)); + if_ok!(word_space(s, "=")); + if_ok!(print_type(s, default)); } _ => {} } -======= - if_ok!(print_ident(s, param.ident)); - print_bounds(s, ¶m.bounds, false) ->>>>>>> syntax: Remove io_error usage + Ok(()) } }