Skip to content

Commit ac77392

Browse files
committed
std: Stabilize last bits of io::Error
This commit stabilizes a few remaining bits of the `io::Error` type: * The `Error::new` method is now stable. The last `detail` parameter was removed and the second `desc` parameter was generalized to `E: Into<Box<Error>>` to allow creating an I/O error from any form of error. Currently there is no form of downcasting, but this will be added in time. * An implementation of `From<&str> for Box<Error>` was added to liballoc to allow construction of errors from raw strings. * The `Error::raw_os_error` method was stabilized as-is. * Trait impls for `Clone`, `Eq`, and `PartialEq` were removed from `Error` as it is not possible to use them with trait objects. This is a breaking change due to the modification of the `new` method as well as the removal of the trait implementations for the `Error` type. [breaking-change]
1 parent 80bf31d commit ac77392

File tree

23 files changed

+109
-96
lines changed

23 files changed

+109
-96
lines changed

src/liballoc/boxed.rs

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,10 @@ use core::fmt;
5656
use core::hash::{self, Hash};
5757
use core::mem;
5858
use core::ops::{Deref, DerefMut};
59-
use core::ptr::Unique;
60-
use core::raw::TraitObject;
59+
use core::ptr::{self, Unique};
60+
use core::raw::{TraitObject, Slice};
61+
62+
use heap;
6163

6264
/// A value that represents the heap. This is the default place that the `box`
6365
/// keyword allocates into when no place is supplied.
@@ -327,3 +329,43 @@ impl<'a, E: Error + 'a> FromError<E> for Box<Error + 'a> {
327329
Box::new(err)
328330
}
329331
}
332+
333+
#[stable(feature = "rust1", since = "1.0.0")]
334+
impl<'a, E: Error + Send + 'a> From<E> for Box<Error + Send + 'a> {
335+
fn from(err: E) -> Box<Error + Send + 'a> {
336+
Box::new(err)
337+
}
338+
}
339+
340+
#[stable(feature = "rust1", since = "1.0.0")]
341+
impl<'a, 'b> From<&'b str> for Box<Error + Send + 'a> {
342+
fn from(err: &'b str) -> Box<Error + Send + 'a> {
343+
#[derive(Debug)]
344+
struct StringError(Box<str>);
345+
impl Error for StringError {
346+
fn description(&self) -> &str { &self.0 }
347+
}
348+
impl fmt::Display for StringError {
349+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
350+
self.0.fmt(f)
351+
}
352+
}
353+
354+
// Unfortunately `String` is located in libcollections, so we construct
355+
// a `Box<str>` manually here.
356+
unsafe {
357+
let alloc = if err.len() == 0 {
358+
0 as *mut u8
359+
} else {
360+
let ptr = heap::allocate(err.len(), 1);
361+
if ptr.is_null() { ::oom(); }
362+
ptr as *mut u8
363+
};
364+
ptr::copy(err.as_bytes().as_ptr(), alloc, err.len());
365+
Box::new(StringError(mem::transmute(Slice {
366+
data: alloc,
367+
len: err.len(),
368+
})))
369+
}
370+
}
371+
}

src/liballoc/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
#![feature(unsafe_no_drop_flag, filling_drop)]
7979
#![feature(core)]
8080
#![feature(unique)]
81+
#![feature(convert)]
8182
#![cfg_attr(test, feature(test, alloc, rustc_private))]
8283
#![cfg_attr(all(not(feature = "external_funcs"), not(feature = "external_crate")),
8384
feature(libc))]

src/librbml/lib.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -862,8 +862,8 @@ pub mod writer {
862862
} else if 0x100 <= n && n < NUM_TAGS {
863863
w.write_all(&[0xf0 | (n >> 8) as u8, n as u8])
864864
} else {
865-
Err(io::Error::new(io::ErrorKind::Other, "invalid tag",
866-
Some(n.to_string())))
865+
Err(io::Error::new(io::ErrorKind::Other,
866+
&format!("invalid tag: {}", n)[..]))
867867
}
868868
}
869869

@@ -876,7 +876,7 @@ pub mod writer {
876876
4 => w.write_all(&[0x10 | ((n >> 24) as u8), (n >> 16) as u8,
877877
(n >> 8) as u8, n as u8]),
878878
_ => Err(io::Error::new(io::ErrorKind::Other,
879-
"isize too big", Some(n.to_string())))
879+
&format!("isize too big: {}", n)[..]))
880880
}
881881
}
882882

@@ -885,8 +885,8 @@ pub mod writer {
885885
if n < 0x4000 { return write_sized_vuint(w, n, 2); }
886886
if n < 0x200000 { return write_sized_vuint(w, n, 3); }
887887
if n < 0x10000000 { return write_sized_vuint(w, n, 4); }
888-
Err(io::Error::new(io::ErrorKind::Other, "isize too big",
889-
Some(n.to_string())))
888+
Err(io::Error::new(io::ErrorKind::Other,
889+
&format!("isize too big: {}", n)[..]))
890890
}
891891

892892
impl<'a> Encoder<'a> {
@@ -1077,8 +1077,8 @@ pub mod writer {
10771077
self.wr_tagged_raw_u32(EsSub32 as usize, v)
10781078
} else {
10791079
Err(io::Error::new(io::ErrorKind::Other,
1080-
"length or variant id too big",
1081-
Some(v.to_string())))
1080+
&format!("length or variant id too big: {}",
1081+
v)[..]))
10821082
}
10831083
}
10841084

src/librustc_back/fs.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@ pub fn realpath(original: &Path) -> io::Result<PathBuf> {
2020
let old = old_path::Path::new(original.to_str().unwrap());
2121
match old_realpath(&old) {
2222
Ok(p) => Ok(PathBuf::from(p.as_str().unwrap())),
23-
Err(e) => Err(io::Error::new(io::ErrorKind::Other,
24-
"realpath error",
25-
Some(e.to_string())))
23+
Err(e) => Err(io::Error::new(io::ErrorKind::Other, e))
2624
}
2725
}
2826

src/librustc_back/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
#![feature(collections)]
3737
#![feature(core)]
3838
#![feature(old_fs)]
39-
#![feature(io)]
4039
#![feature(old_io)]
4140
#![feature(old_path)]
4241
#![feature(os)]

src/librustc_back/target/apple_ios_base.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,10 @@ pub fn get_sdk_root(sdk_name: &str) -> String {
4747
Ok(String::from_utf8(output.stdout).unwrap())
4848
} else {
4949
let error = String::from_utf8(output.stderr);
50+
let error = format!("process exit with error: {}",
51+
error.unwrap());
5052
Err(io::Error::new(io::ErrorKind::Other,
51-
"process exit with error",
52-
error.ok()))
53+
&error[..]))
5354
}
5455
});
5556

src/librustc_back/tempdir.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,7 @@ impl TempDir {
6767
}
6868

6969
Err(Error::new(ErrorKind::AlreadyExists,
70-
"too many temporary directories already exist",
71-
None))
70+
"too many temporary directories already exist"))
7271
}
7372

7473
/// Attempts to make a temporary directory inside of `env::temp_dir()` whose

src/librustc_driver/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
#![feature(unsafe_destructor)]
3636
#![feature(staged_api)]
3737
#![feature(exit_status)]
38-
#![feature(io)]
3938
#![feature(set_stdio)]
4039
#![feature(unicode)]
4140
#![feature(convert)]

src/librustc_driver/pretty.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -699,8 +699,8 @@ fn print_flowgraph<W: Write>(variants: Vec<borrowck_dot::Variant>,
699699

700700
fn expand_err_details(r: io::Result<()>) -> io::Result<()> {
701701
r.map_err(|ioerr| {
702-
io::Error::new(io::ErrorKind::Other, "graphviz::render failed",
703-
Some(ioerr.to_string()))
702+
io::Error::new(io::ErrorKind::Other,
703+
&format!("graphviz::render failed: {}", ioerr)[..])
704704
})
705705
}
706706
}

src/libstd/ffi/c_str.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ impl fmt::Display for NulError {
301301
impl FromError<NulError> for io::Error {
302302
fn from_error(_: NulError) -> io::Error {
303303
io::Error::new(io::ErrorKind::InvalidInput,
304-
"data provided contains a nul byte", None)
304+
"data provided contains a nul byte")
305305
}
306306
}
307307

src/libstd/fs/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -575,8 +575,7 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
575575
let to = to.as_ref();
576576
if !from.is_file() {
577577
return Err(Error::new(ErrorKind::InvalidInput,
578-
"the source path is not an existing file",
579-
None))
578+
"the source path is not an existing file"))
580579
}
581580

582581
let mut reader = try!(File::open(from));

src/libstd/fs/tempdir.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,7 @@ impl TempDir {
7373
}
7474

7575
Err(Error::new(ErrorKind::AlreadyExists,
76-
"too many temporary directories already exist",
77-
None))
76+
"too many temporary directories already exist"))
7877
}
7978

8079
/// Attempts to make a temporary directory inside of `env::temp_dir()` whose

src/libstd/io/buffered.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ impl<W: Write> BufWriter<W> {
165165
match self.inner.as_mut().unwrap().write(&self.buf[written..]) {
166166
Ok(0) => {
167167
ret = Err(Error::new(ErrorKind::WriteZero,
168-
"failed to write the buffered data", None));
168+
"failed to write the buffered data"));
169169
break;
170170
}
171171
Ok(n) => written += n,

src/libstd/io/cursor.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,7 @@ macro_rules! seek {
7575

7676
if pos < 0 {
7777
Err(Error::new(ErrorKind::InvalidInput,
78-
"invalid seek to a negative position",
79-
None))
78+
"invalid seek to a negative position"))
8079
} else {
8180
self.pos = pos as u64;
8281
Ok(self.pos)

src/libstd/io/error.rs

Lines changed: 34 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@
99
// except according to those terms.
1010

1111
use boxed::Box;
12-
use clone::Clone;
12+
use convert::Into;
1313
use error;
1414
use fmt;
15+
use marker::Send;
1516
use option::Option::{self, Some, None};
1617
use result;
17-
use string::String;
1818
use sys;
1919

2020
/// A type for results generated by I/O related functions where the `Err` type
@@ -31,23 +31,22 @@ pub type Result<T> = result::Result<T, Error>;
3131
/// Errors mostly originate from the underlying OS, but custom instances of
3232
/// `Error` can be created with crafted error messages and a particular value of
3333
/// `ErrorKind`.
34-
#[derive(PartialEq, Eq, Clone, Debug)]
34+
#[derive(Debug)]
3535
#[stable(feature = "rust1", since = "1.0.0")]
3636
pub struct Error {
3737
repr: Repr,
3838
}
3939

40-
#[derive(PartialEq, Eq, Clone, Debug)]
40+
#[derive(Debug)]
4141
enum Repr {
4242
Os(i32),
4343
Custom(Box<Custom>),
4444
}
4545

46-
#[derive(PartialEq, Eq, Clone, Debug)]
46+
#[derive(Debug)]
4747
struct Custom {
4848
kind: ErrorKind,
49-
desc: &'static str,
50-
detail: Option<String>
49+
error: Box<error::Error+Send>,
5150
}
5251

5352
/// A list specifying general categories of I/O error.
@@ -125,18 +124,34 @@ pub enum ErrorKind {
125124
}
126125

127126
impl Error {
128-
/// Creates a new custom error from a specified kind/description/detail.
129-
#[unstable(feature = "io", reason = "the exact makeup of an Error may
130-
change to include `Box<Error>` for \
131-
example")]
132-
pub fn new(kind: ErrorKind,
133-
description: &'static str,
134-
detail: Option<String>) -> Error {
127+
/// Creates a new I/O error from a known kind of error as well as an
128+
/// arbitrary error payload.
129+
///
130+
/// This function is used to generically create I/O errors which do not
131+
/// originate from the OS itself. The `error` argument is an arbitrary
132+
/// payload which will be contained in this `Error`. Accessors as well as
133+
/// downcasting will soon be added to this type as well to access the custom
134+
/// information.
135+
///
136+
/// # Examples
137+
///
138+
/// ```
139+
/// use std::io::{Error, ErrorKind};
140+
///
141+
/// // errors can be created from strings
142+
/// let custom_error = Error::new(ErrorKind::Other, "oh no!");
143+
///
144+
/// // errors can also be created from other errors
145+
/// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
146+
/// ```
147+
#[stable(feature = "rust1", since = "1.0.0")]
148+
pub fn new<E>(kind: ErrorKind, error: E) -> Error
149+
where E: Into<Box<error::Error+Send>>
150+
{
135151
Error {
136152
repr: Repr::Custom(Box::new(Custom {
137153
kind: kind,
138-
desc: description,
139-
detail: detail,
154+
error: error.into(),
140155
}))
141156
}
142157
}
@@ -162,8 +177,7 @@ impl Error {
162177
///
163178
/// If this `Error` was constructed via `last_os_error` then this function
164179
/// will return `Some`, otherwise it will return `None`.
165-
#[unstable(feature = "io", reason = "function was just added and the return \
166-
type may become an abstract OS error")]
180+
#[stable(feature = "rust1", since = "1.0.0")]
167181
pub fn raw_os_error(&self) -> Option<i32> {
168182
match self.repr {
169183
Repr::Os(i) => Some(i),
@@ -179,27 +193,6 @@ impl Error {
179193
Repr::Custom(ref c) => c.kind,
180194
}
181195
}
182-
183-
/// Returns a short description for this error message
184-
#[unstable(feature = "io")]
185-
#[deprecated(since = "1.0.0", reason = "use the Error trait's description \
186-
method instead")]
187-
pub fn description(&self) -> &str {
188-
match self.repr {
189-
Repr::Os(..) => "os error",
190-
Repr::Custom(ref c) => c.desc,
191-
}
192-
}
193-
194-
/// Returns a detailed error message for this error (if one is available)
195-
#[unstable(feature = "io")]
196-
#[deprecated(since = "1.0.0", reason = "use the to_string() method instead")]
197-
pub fn detail(&self) -> Option<String> {
198-
match self.repr {
199-
Repr::Os(code) => Some(sys::os::error_string(code)),
200-
Repr::Custom(ref s) => s.detail.clone(),
201-
}
202-
}
203196
}
204197

205198
#[stable(feature = "rust1", since = "1.0.0")]
@@ -210,21 +203,7 @@ impl fmt::Display for Error {
210203
let detail = sys::os::error_string(code);
211204
write!(fmt, "{} (os error {})", detail, code)
212205
}
213-
Repr::Custom(ref c) => {
214-
match **c {
215-
Custom {
216-
kind: ErrorKind::Other,
217-
desc: "unknown error",
218-
detail: Some(ref detail)
219-
} => {
220-
write!(fmt, "{}", detail)
221-
}
222-
Custom { detail: None, desc, .. } =>
223-
write!(fmt, "{}", desc),
224-
Custom { detail: Some(ref detail), desc, .. } =>
225-
write!(fmt, "{} ({})", desc, detail)
226-
}
227-
}
206+
Repr::Custom(ref c) => c.error.fmt(fmt),
228207
}
229208
}
230209
}
@@ -234,7 +213,7 @@ impl error::Error for Error {
234213
fn description(&self) -> &str {
235214
match self.repr {
236215
Repr::Os(..) => "os error",
237-
Repr::Custom(ref c) => c.desc,
216+
Repr::Custom(ref c) => c.error.description(),
238217
}
239218
}
240219
}

src/libstd/io/impls.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ impl<'a> Write for &'a mut [u8] {
180180
if try!(self.write(data)) == data.len() {
181181
Ok(())
182182
} else {
183-
Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer", None))
183+
Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer"))
184184
}
185185
}
186186

0 commit comments

Comments
 (0)