diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index f3c0dd0c3dc..550b25ac3a7 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -56,8 +56,10 @@ use core::fmt; use core::hash::{self, Hash}; use core::mem; use core::ops::{Deref, DerefMut}; -use core::ptr::Unique; -use core::raw::TraitObject; +use core::ptr::{self, Unique}; +use core::raw::{TraitObject, Slice}; + +use heap; /// A value that represents the heap. This is the default place that the `box` /// keyword allocates into when no place is supplied. @@ -313,3 +315,43 @@ impl<'a, E: Error + 'a> From for Box { Box::new(err) } } + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, E: Error + Send + 'a> From for Box { + fn from(err: E) -> Box { + Box::new(err) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, 'b> From<&'b str> for Box { + fn from(err: &'b str) -> Box { + #[derive(Debug)] + struct StringError(Box); + impl Error for StringError { + fn description(&self) -> &str { &self.0 } + } + impl fmt::Display for StringError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } + } + + // Unfortunately `String` is located in libcollections, so we construct + // a `Box` manually here. + unsafe { + let alloc = if err.len() == 0 { + 0 as *mut u8 + } else { + let ptr = heap::allocate(err.len(), 1); + if ptr.is_null() { ::oom(); } + ptr as *mut u8 + }; + ptr::copy(err.as_bytes().as_ptr(), alloc, err.len()); + Box::new(StringError(mem::transmute(Slice { + data: alloc, + len: err.len(), + }))) + } + } +} diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index b92dfa9117e..a880ba5cfe4 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -78,6 +78,7 @@ #![feature(unsafe_no_drop_flag, filling_drop)] #![feature(core)] #![feature(unique)] +#![feature(convert)] #![cfg_attr(test, feature(test, alloc, rustc_private))] #![cfg_attr(all(not(feature = "external_funcs"), not(feature = "external_crate")), feature(libc))] diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index 092cd780ec7..878ef04942a 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -862,8 +862,8 @@ pub mod writer { } else if 0x100 <= n && n < NUM_TAGS { w.write_all(&[0xf0 | (n >> 8) as u8, n as u8]) } else { - Err(io::Error::new(io::ErrorKind::Other, "invalid tag", - Some(n.to_string()))) + Err(io::Error::new(io::ErrorKind::Other, + &format!("invalid tag: {}", n)[..])) } } @@ -876,7 +876,7 @@ pub mod writer { 4 => w.write_all(&[0x10 | ((n >> 24) as u8), (n >> 16) as u8, (n >> 8) as u8, n as u8]), _ => Err(io::Error::new(io::ErrorKind::Other, - "isize too big", Some(n.to_string()))) + &format!("isize too big: {}", n)[..])) } } @@ -885,8 +885,8 @@ pub mod writer { if n < 0x4000 { return write_sized_vuint(w, n, 2); } if n < 0x200000 { return write_sized_vuint(w, n, 3); } if n < 0x10000000 { return write_sized_vuint(w, n, 4); } - Err(io::Error::new(io::ErrorKind::Other, "isize too big", - Some(n.to_string()))) + Err(io::Error::new(io::ErrorKind::Other, + &format!("isize too big: {}", n)[..])) } impl<'a> Encoder<'a> { @@ -1077,8 +1077,8 @@ pub mod writer { self.wr_tagged_raw_u32(EsSub32 as usize, v) } else { Err(io::Error::new(io::ErrorKind::Other, - "length or variant id too big", - Some(v.to_string()))) + &format!("length or variant id too big: {}", + v)[..])) } } diff --git a/src/librustc_back/fs.rs b/src/librustc_back/fs.rs index d3f3b1dad78..231f6ee3be6 100644 --- a/src/librustc_back/fs.rs +++ b/src/librustc_back/fs.rs @@ -21,9 +21,7 @@ pub fn realpath(original: &Path) -> io::Result { let old = old_path::Path::new(original.to_str().unwrap()); match old_realpath(&old) { Ok(p) => Ok(PathBuf::from(p.as_str().unwrap())), - Err(e) => Err(io::Error::new(io::ErrorKind::Other, - "realpath error", - Some(e.to_string()))) + Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)) } } diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs index fa1af0ca3f0..7591ebf67f8 100644 --- a/src/librustc_back/lib.rs +++ b/src/librustc_back/lib.rs @@ -36,7 +36,6 @@ #![feature(collections)] #![feature(core)] #![feature(old_fs)] -#![feature(io)] #![feature(old_io)] #![feature(old_path)] #![feature(rustc_private)] diff --git a/src/librustc_back/target/apple_ios_base.rs b/src/librustc_back/target/apple_ios_base.rs index 2fbbe7d1f7c..42cbdd7577d 100644 --- a/src/librustc_back/target/apple_ios_base.rs +++ b/src/librustc_back/target/apple_ios_base.rs @@ -47,9 +47,10 @@ pub fn get_sdk_root(sdk_name: &str) -> String { Ok(String::from_utf8(output.stdout).unwrap()) } else { let error = String::from_utf8(output.stderr); + let error = format!("process exit with error: {}", + error.unwrap()); Err(io::Error::new(io::ErrorKind::Other, - "process exit with error", - error.ok())) + &error[..])) } }); diff --git a/src/librustc_back/tempdir.rs b/src/librustc_back/tempdir.rs index 6935499f5a0..b12732f8794 100644 --- a/src/librustc_back/tempdir.rs +++ b/src/librustc_back/tempdir.rs @@ -67,8 +67,7 @@ impl TempDir { } Err(Error::new(ErrorKind::AlreadyExists, - "too many temporary directories already exist", - None)) + "too many temporary directories already exist")) } /// Attempts to make a temporary directory inside of `env::temp_dir()` whose diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 450c8eb66c8..be416327dad 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -34,7 +34,6 @@ #![feature(unsafe_destructor)] #![feature(staged_api)] #![feature(exit_status)] -#![feature(io)] #![feature(set_stdio)] #![feature(unicode)] diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 9e693a64ef0..fe55ca3b73b 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -699,8 +699,8 @@ fn print_flowgraph(variants: Vec, fn expand_err_details(r: io::Result<()>) -> io::Result<()> { r.map_err(|ioerr| { - io::Error::new(io::ErrorKind::Other, "graphviz::render failed", - Some(ioerr.to_string())) + io::Error::new(io::ErrorKind::Other, + &format!("graphviz::render failed: {}", ioerr)[..]) }) } } diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 42ea50bff77..de91e5f3268 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -241,7 +241,7 @@ impl fmt::Display for NulError { impl From for io::Error { fn from(_: NulError) -> io::Error { io::Error::new(io::ErrorKind::InvalidInput, - "data provided contains a nul byte", None) + "data provided contains a nul byte") } } diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index c34d128081b..4f97ae8f69b 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -576,8 +576,7 @@ pub fn copy, Q: AsRef>(from: P, to: Q) -> io::Result { let to = to.as_ref(); if !from.is_file() { return Err(Error::new(ErrorKind::InvalidInput, - "the source path is not an existing file", - None)) + "the source path is not an existing file")) } let mut reader = try!(File::open(from)); diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 628ad839c16..479665c4728 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -165,7 +165,7 @@ impl BufWriter { match self.inner.as_mut().unwrap().write(&self.buf[written..]) { Ok(0) => { ret = Err(Error::new(ErrorKind::WriteZero, - "failed to write the buffered data", None)); + "failed to write the buffered data")); break; } Ok(n) => written += n, diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index ad81143b7b4..a7b7f96c22b 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -75,8 +75,7 @@ macro_rules! seek { if pos < 0 { Err(Error::new(ErrorKind::InvalidInput, - "invalid seek to a negative position", - None)) + "invalid seek to a negative position")) } else { self.pos = pos as u64; Ok(self.pos) diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index 615df771e9b..b84dcb8fb62 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -9,11 +9,12 @@ // except according to those terms. use boxed::Box; +use convert::Into; use error; use fmt; +use marker::Send; use option::Option::{self, Some, None}; use result; -use string::String; use sys; /// A type for results generated by I/O related functions where the `Err` type @@ -30,23 +31,22 @@ pub type Result = result::Result; /// Errors mostly originate from the underlying OS, but custom instances of /// `Error` can be created with crafted error messages and a particular value of /// `ErrorKind`. -#[derive(PartialEq, Eq, Clone, Debug)] +#[derive(Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Error { repr: Repr, } -#[derive(PartialEq, Eq, Clone, Debug)] +#[derive(Debug)] enum Repr { Os(i32), Custom(Box), } -#[derive(PartialEq, Eq, Clone, Debug)] +#[derive(Debug)] struct Custom { kind: ErrorKind, - desc: &'static str, - detail: Option + error: Box, } /// A list specifying general categories of I/O error. @@ -124,18 +124,34 @@ pub enum ErrorKind { } impl Error { - /// Creates a new custom error from a specified kind/description/detail. - #[unstable(feature = "io", reason = "the exact makeup of an Error may - change to include `Box` for \ - example")] - pub fn new(kind: ErrorKind, - description: &'static str, - detail: Option) -> Error { + /// Creates a new I/O error from a known kind of error as well as an + /// arbitrary error payload. + /// + /// This function is used to generically create I/O errors which do not + /// originate from the OS itself. The `error` argument is an arbitrary + /// payload which will be contained in this `Error`. Accessors as well as + /// downcasting will soon be added to this type as well to access the custom + /// information. + /// + /// # Examples + /// + /// ``` + /// use std::io::{Error, ErrorKind}; + /// + /// // errors can be created from strings + /// let custom_error = Error::new(ErrorKind::Other, "oh no!"); + /// + /// // errors can also be created from other errors + /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new(kind: ErrorKind, error: E) -> Error + where E: Into> + { Error { repr: Repr::Custom(Box::new(Custom { kind: kind, - desc: description, - detail: detail, + error: error.into(), })) } } @@ -161,8 +177,7 @@ impl Error { /// /// If this `Error` was constructed via `last_os_error` then this function /// will return `Some`, otherwise it will return `None`. - #[unstable(feature = "io", reason = "function was just added and the return \ - type may become an abstract OS error")] + #[stable(feature = "rust1", since = "1.0.0")] pub fn raw_os_error(&self) -> Option { match self.repr { Repr::Os(i) => Some(i), @@ -188,21 +203,7 @@ impl fmt::Display for Error { let detail = sys::os::error_string(code); write!(fmt, "{} (os error {})", detail, code) } - Repr::Custom(ref c) => { - match **c { - Custom { - kind: ErrorKind::Other, - desc: "unknown error", - detail: Some(ref detail) - } => { - write!(fmt, "{}", detail) - } - Custom { detail: None, desc, .. } => - write!(fmt, "{}", desc), - Custom { detail: Some(ref detail), desc, .. } => - write!(fmt, "{} ({})", desc, detail) - } - } + Repr::Custom(ref c) => c.error.fmt(fmt), } } } @@ -212,7 +213,7 @@ impl error::Error for Error { fn description(&self) -> &str { match self.repr { Repr::Os(..) => "os error", - Repr::Custom(ref c) => c.desc, + Repr::Custom(ref c) => c.error.description(), } } } diff --git a/src/libstd/io/impls.rs b/src/libstd/io/impls.rs index 52daba36213..67bc45d3b62 100644 --- a/src/libstd/io/impls.rs +++ b/src/libstd/io/impls.rs @@ -180,7 +180,7 @@ impl<'a> Write for &'a mut [u8] { if try!(self.write(data)) == data.len() { Ok(()) } else { - Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer", None)) + Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer")) } } diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 0e379b5ab43..d72abe8c69b 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -83,7 +83,7 @@ fn append_to_string(buf: &mut String, f: F) -> Result if str::from_utf8(&g.s[g.len..]).is_err() { ret.and_then(|_| { Err(Error::new(ErrorKind::InvalidInput, - "stream did not contain valid UTF-8", None)) + "stream did not contain valid UTF-8")) }) } else { g.len = g.s.len(); @@ -359,8 +359,7 @@ pub trait Write { while buf.len() > 0 { match self.write(buf) { Ok(0) => return Err(Error::new(ErrorKind::WriteZero, - "failed to write whole buffer", - None)), + "failed to write whole buffer")), Ok(n) => buf = &buf[n..], Err(ref e) if e.kind() == ErrorKind::Interrupted => {} Err(e) => return Err(e), @@ -782,7 +781,7 @@ pub struct Chars { /// An enumeration of possible errors that can be generated from the `Chars` /// adapter. -#[derive(PartialEq, Clone, Debug)] +#[derive(Debug)] #[unstable(feature = "io", reason = "awaiting stability of Read::chars")] pub enum CharsError { /// Variant representing that the underlying stream was read successfully diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index a08b33b342b..eb6cb441606 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -435,7 +435,7 @@ impl ToSocketAddrs for str { match $e { Some(r) => r, None => return Err(io::Error::new(io::ErrorKind::InvalidInput, - $msg, None)), + $msg)), } ) } diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index ee57300765e..a152b98822a 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -72,7 +72,7 @@ fn each_addr(addr: A, mut f: F) -> io::Result } Err(last_err.unwrap_or_else(|| { Error::new(ErrorKind::InvalidInput, - "could not resolve to any addresses", None) + "could not resolve to any addresses") })) } diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index 497e6bcbd71..14b5c974b67 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -76,7 +76,7 @@ impl UdpSocket { match try!(addr.to_socket_addrs()).next() { Some(addr) => self.0.send_to(buf, &addr), None => Err(Error::new(ErrorKind::InvalidInput, - "no addresses to send data to", None)), + "no addresses to send data to")), } } diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 63023855514..ca25cadb9dc 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -456,7 +456,6 @@ impl Child { return Err(Error::new( ErrorKind::InvalidInput, "invalid argument: can't kill an exited process", - None )) } diff --git a/src/libstd/sys/common/net2.rs b/src/libstd/sys/common/net2.rs index e787442052d..7d42d65d360 100644 --- a/src/libstd/sys/common/net2.rs +++ b/src/libstd/sys/common/net2.rs @@ -75,7 +75,7 @@ fn sockaddr_to_addr(storage: &libc::sockaddr_storage, }))) } _ => { - Err(Error::new(ErrorKind::InvalidInput, "invalid argument", None)) + Err(Error::new(ErrorKind::InvalidInput, "invalid argument")) } } } @@ -158,8 +158,7 @@ pub fn lookup_addr(addr: &IpAddr) -> io::Result { match from_utf8(data.to_bytes()) { Ok(name) => Ok(name.to_string()), Err(_) => Err(io::Error::new(io::ErrorKind::Other, - "failed to lookup address information", - Some("invalid host name".to_string()))) + "failed to lookup address information")) } } diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index 00b907ce10c..908136a42ab 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -35,7 +35,8 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> { .to_string() }; Err(io::Error::new(io::ErrorKind::Other, - "failed to lookup address information", Some(detail))) + &format!("failed to lookup address information: {}", + detail)[..])) } impl Socket {