Skip to content

Commit c872537

Browse files
committed
auto merge of #17753 : aturon/rust/error-interop, r=alexcrichton
This PR: * Adds the error interoperation traits (`Error` and `FromError`) to a new module, `std::error`, as per [RFC 70](https://github.com/rust-lang/rfcs/blob/master/active/0070-error-chaining.md). Note that this module must live in `std` in order to refer to `String`. Note that, until multidispatch lands, the `FromError` trait cannot be usefully implemented outside of the blanket impl given here. * Incorporates `std::error::FromError` into the `try!` macro. * Implements `Error` for most existing error enumerations. Closes #17747
2 parents 5e83424 + 276919c commit c872537

File tree

12 files changed

+239
-7
lines changed

12 files changed

+239
-7
lines changed

src/libcore/any.rs

+3
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,9 @@ pub trait AnyRefExt<'a> {
114114
fn downcast_ref<T: 'static>(self) -> Option<&'a T>;
115115
}
116116

117+
// Note: this code is copied to std::error, and should be unified as
118+
// soon as possible.
119+
117120
#[stable]
118121
impl<'a> AnyRefExt<'a> for &'a Any {
119122
#[inline]

src/libcore/prelude.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ pub use ops::{Shl, Shr};
3737
pub use ops::{Index, IndexMut};
3838
pub use ops::{Slice, SliceMut};
3939
pub use ops::{Fn, FnMut, FnOnce};
40-
pub use option::{Option, Some, None};
41-
pub use result::{Result, Ok, Err};
4240

4341
// Reexported functions
4442
pub use iter::range;
@@ -57,7 +55,9 @@ pub use iter::{OrdIterator, MutableDoubleEndedIterator, ExactSize};
5755
pub use num::{Num, NumCast, CheckedAdd, CheckedSub, CheckedMul};
5856
pub use num::{Signed, Unsigned, Float};
5957
pub use num::{Primitive, Int, ToPrimitive, FromPrimitive};
58+
pub use option::{Option, Some, None};
6059
pub use ptr::RawPtr;
60+
pub use result::{Result, Ok, Err};
6161
pub use str::{Str, StrSlice};
6262
pub use tuple::{Tuple1, Tuple2, Tuple3, Tuple4};
6363
pub use tuple::{Tuple5, Tuple6, Tuple7, Tuple8};

src/librustc/driver/driver.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,7 @@ fn write_out_deps(sess: &Session,
660660
_ => return,
661661
};
662662

663-
let result = (|| {
663+
let result = (|| -> io::IoResult<()> {
664664
// Build a list of files used to compile the output and
665665
// write Makefile-compatible dependency rules
666666
let files: Vec<String> = sess.codemap().files.borrow()

src/libserialize/base64.rs

+14
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
//! Base64 binary-to-text encoding
1414
use std::fmt;
1515
use std::string;
16+
use std::error;
1617

1718
/// Available encoding character sets
1819
pub enum CharacterSet {
@@ -178,6 +179,19 @@ impl fmt::Show for FromBase64Error {
178179
}
179180
}
180181

182+
impl error::Error for FromBase64Error {
183+
fn description(&self) -> &str {
184+
match *self {
185+
InvalidBase64Byte(_, _) => "invalid character",
186+
InvalidBase64Length => "invalid length",
187+
}
188+
}
189+
190+
fn detail(&self) -> Option<String> {
191+
Some(self.to_string())
192+
}
193+
}
194+
181195
impl<'a> FromBase64 for &'a str {
182196
/**
183197
* Convert any base64 encoded string (literal, `@`, `&`, or `~`)

src/libserialize/hex.rs

+15
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
//! Hex binary-to-text encoding
1414
use std::fmt;
1515
use std::string;
16+
use std::error;
1617

1718
/// A trait for converting a value to hexadecimal encoding
1819
pub trait ToHex {
@@ -77,6 +78,20 @@ impl fmt::Show for FromHexError {
7778
}
7879
}
7980

81+
impl error::Error for FromHexError {
82+
fn description(&self) -> &str {
83+
match *self {
84+
InvalidHexCharacter(_, _) => "invalid character",
85+
InvalidHexLength => "invalid length",
86+
}
87+
}
88+
89+
fn detail(&self) -> Option<String> {
90+
Some(self.to_string())
91+
}
92+
}
93+
94+
8095
impl<'a> FromHex for &'a str {
8196
/**
8297
* Convert any hexadecimal encoded string (literal, `@`, `&`, or `~`)

src/libserialize/json.rs

+5
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,11 @@ fn io_error_to_error(io: io::IoError) -> ParserError {
313313
IoError(io.kind, io.desc)
314314
}
315315

316+
impl std::error::Error for DecoderError {
317+
fn description(&self) -> &str { "decoder error" }
318+
fn detail(&self) -> Option<std::string::String> { Some(self.to_string()) }
319+
}
320+
316321
pub type EncodeResult = io::IoResult<()>;
317322
pub type DecodeResult<T> = Result<T, DecoderError>;
318323

src/libstd/error.rs

+156
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! Traits for working with Errors.
12+
//!
13+
//! # The `Error` trait
14+
//!
15+
//! `Error` is a trait representing the basic expectations for error values,
16+
//! i.e. values of type `E` in `Result<T, E>`. At a minimum, errors must provide
17+
//! a description, but they may optionally provide additional detail and cause
18+
//! chain information:
19+
//!
20+
//! ```
21+
//! pub trait Error: Send + Any {
22+
//! fn description(&self) -> &str;
23+
//!
24+
//! fn detail(&self) -> Option<String> { None }
25+
//! fn cause(&self) -> Option<&Error> { None }
26+
//! }
27+
//! ```
28+
//!
29+
//! The `cause` method is generally used when errors cross "abstraction
30+
//! boundaries", i.e. when a one module must report an error that is "caused"
31+
//! by an error from a lower-level module. This setup makes it possible for the
32+
//! high-level module to provide its own errors that do not commit to any
33+
//! particular implementation, but also reveal some of its implementation for
34+
//! debugging via `cause` chains.
35+
//!
36+
//! The trait inherits from `Any` to allow *downcasting*: converting from a
37+
//! trait object to a specific concrete type when applicable.
38+
//!
39+
//! # The `FromError` trait
40+
//!
41+
//! `FromError` is a simple trait that expresses conversions between different
42+
//! error types. To provide maximum flexibility, it does not require either of
43+
//! the types to actually implement the `Error` trait, although this will be the
44+
//! common case.
45+
//!
46+
//! The main use of this trait is in the `try!` macro, which uses it to
47+
//! automatically convert a given error to the error specified in a function's
48+
//! return type.
49+
//!
50+
//! For example,
51+
//!
52+
//! ```
53+
//! use std::io::IoError;
54+
//! use std::os::MapError;
55+
//!
56+
//! impl FromError<IoError> for Box<Error> {
57+
//! fn from_error(err: IoError) -> Box<Error> {
58+
//! box err
59+
//! }
60+
//! }
61+
//!
62+
//! impl FromError<MapError> for Box<Error> {
63+
//! fn from_error(err: MapError) -> Box<Error> {
64+
//! box err
65+
//! }
66+
//! }
67+
//!
68+
//! #[allow(unused_variables)]
69+
//! fn open_and_map() -> Box<Error> {
70+
//! let f = try!(io::File::open("foo.txt"));
71+
//! let m = try!(os::MemoryMap::new(0, &[]));
72+
//! // do something interesting here...
73+
//! }
74+
//! ```
75+
76+
use any::{Any, AnyRefExt, AnyMutRefExt};
77+
use mem::{transmute, transmute_copy};
78+
use option::{Option, Some, None};
79+
use raw::TraitObject;
80+
use intrinsics::TypeId;
81+
use kinds::Send;
82+
use string::String;
83+
84+
/// Base functionality for all errors in Rust.
85+
pub trait Error: Send + Any {
86+
/// A short description of the error; usually a static string.
87+
fn description(&self) -> &str;
88+
89+
/// A detailed description of the error, usually including dynamic information.
90+
fn detail(&self) -> Option<String> { None }
91+
92+
/// The lower-level cause of this error, if any.
93+
fn cause(&self) -> Option<&Error> { None }
94+
}
95+
96+
/// A trait for types that can be converted from a given error type `E`.
97+
pub trait FromError<E> {
98+
/// Perform the conversion.
99+
fn from_error(err: E) -> Self;
100+
}
101+
102+
// Any type is convertable from itself
103+
impl<E> FromError<E> for E {
104+
fn from_error(err: E) -> E {
105+
err
106+
}
107+
}
108+
109+
// Note: the definitions below are copied from core::any, and should be unified
110+
// as soon as possible.
111+
112+
impl<'a> AnyRefExt<'a> for &'a Error {
113+
#[inline]
114+
fn is<T: 'static>(self) -> bool {
115+
// Get TypeId of the type this function is instantiated with
116+
let t = TypeId::of::<T>();
117+
118+
// Get TypeId of the type in the trait object
119+
let boxed = self.get_type_id();
120+
121+
// Compare both TypeIds on equality
122+
t == boxed
123+
}
124+
125+
#[inline]
126+
fn downcast_ref<T: 'static>(self) -> Option<&'a T> {
127+
if self.is::<T>() {
128+
unsafe {
129+
// Get the raw representation of the trait object
130+
let to: TraitObject = transmute_copy(&self);
131+
132+
// Extract the data pointer
133+
Some(transmute(to.data))
134+
}
135+
} else {
136+
None
137+
}
138+
}
139+
}
140+
141+
impl<'a> AnyMutRefExt<'a> for &'a mut Error {
142+
#[inline]
143+
fn downcast_mut<T: 'static>(self) -> Option<&'a mut T> {
144+
if self.is::<T>() {
145+
unsafe {
146+
// Get the raw representation of the trait object
147+
let to: TraitObject = transmute_copy(&self);
148+
149+
// Extract the data pointer
150+
Some(transmute(to.data))
151+
}
152+
} else {
153+
None
154+
}
155+
}
156+
}

src/libstd/io/mod.rs

+18
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,9 @@ responding to errors that may occur while attempting to read the numbers.
223223

224224
use char::Char;
225225
use collections::Collection;
226+
use clone::Clone;
226227
use default::Default;
228+
use error::{FromError, Error};
227229
use fmt;
228230
use int;
229231
use iter::Iterator;
@@ -434,6 +436,22 @@ impl fmt::Show for IoError {
434436
}
435437
}
436438

439+
impl Error for IoError {
440+
fn description(&self) -> &str {
441+
self.desc
442+
}
443+
444+
fn detail(&self) -> Option<String> {
445+
self.detail.clone()
446+
}
447+
}
448+
449+
impl FromError<IoError> for Box<Error> {
450+
fn from_error(err: IoError) -> Box<Error> {
451+
box err
452+
}
453+
}
454+
437455
/// A list specifying general categories of I/O error.
438456
#[deriving(PartialEq, Eq, Clone, Show)]
439457
pub enum IoErrorKind {

src/libstd/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ pub mod time;
218218

219219
/* Common traits */
220220

221+
pub mod error;
221222
pub mod from_str;
222223
pub mod num;
223224
pub mod to_string;
@@ -257,6 +258,7 @@ mod std {
257258
pub use hash;
258259

259260
pub use comm; // used for select!()
261+
pub use error; // used for try!()
260262
pub use fmt; // used for any formatting strings
261263
pub use io; // used for println!()
262264
pub use local_data; // used for local_data_key!()

src/libstd/macros.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -317,8 +317,13 @@ macro_rules! local_data_key(
317317
/// error if the value of the expression is `Err`. For more information, see
318318
/// `std::io`.
319319
#[macro_export]
320-
macro_rules! try(
321-
($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
320+
macro_rules! try (
321+
($expr:expr) => ({
322+
match $expr {
323+
Ok(val) => val,
324+
Err(err) => return Err(::std::error::FromError::from_error(err))
325+
}
326+
})
322327
)
323328

324329
/// Create a `std::vec::Vec` containing the arguments.

src/libstd/os.rs

+14
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,13 @@
3333

3434
use clone::Clone;
3535
use collections::{Collection, MutableSeq};
36+
use error::{FromError, Error};
3637
use fmt;
3738
use io::{IoResult, IoError};
3839
use iter::Iterator;
3940
use libc::{c_void, c_int};
4041
use libc;
42+
use boxed::Box;
4143
use ops::Drop;
4244
use option::{Some, None, Option};
4345
use os;
@@ -49,6 +51,7 @@ use slice::{AsSlice, ImmutableSlice, MutableSlice, ImmutablePartialEqSlice};
4951
use slice::CloneableVector;
5052
use str::{Str, StrSlice, StrAllocating};
5153
use string::String;
54+
use to_string::ToString;
5255
use sync::atomic::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
5356
use vec::Vec;
5457

@@ -1438,6 +1441,17 @@ impl fmt::Show for MapError {
14381441
}
14391442
}
14401443

1444+
impl Error for MapError {
1445+
fn description(&self) -> &str { "memory map error" }
1446+
fn detail(&self) -> Option<String> { Some(self.to_string()) }
1447+
}
1448+
1449+
impl FromError<MapError> for Box<Error> {
1450+
fn from_error(err: MapError) -> Box<Error> {
1451+
box err
1452+
}
1453+
}
1454+
14411455
#[cfg(unix)]
14421456
impl MemoryMap {
14431457
/// Create a new mapping with the given `options`, at least `min_len` bytes

src/libstd/prelude.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,6 @@
4848
#[doc(no_inline)] pub use ops::{Index, IndexMut};
4949
#[doc(no_inline)] pub use ops::{Slice, SliceMut};
5050
#[doc(no_inline)] pub use ops::{Fn, FnMut, FnOnce};
51-
#[doc(no_inline)] pub use option::{Option, Some, None};
52-
#[doc(no_inline)] pub use result::{Result, Ok, Err};
5351

5452
// Reexported functions
5553
#[doc(no_inline)] pub use from_str::from_str;
@@ -75,8 +73,10 @@
7573
#[doc(no_inline)] pub use num::{Signed, Unsigned, Primitive, Int, Float};
7674
#[doc(no_inline)] pub use num::{FloatMath, ToPrimitive, FromPrimitive};
7775
#[doc(no_inline)] pub use boxed::Box;
76+
#[doc(no_inline)] pub use option::{Option, Some, None};
7877
#[doc(no_inline)] pub use path::{GenericPath, Path, PosixPath, WindowsPath};
7978
#[doc(no_inline)] pub use ptr::{RawPtr, RawMutPtr};
79+
#[doc(no_inline)] pub use result::{Result, Ok, Err};
8080
#[doc(no_inline)] pub use io::{Buffer, Writer, Reader, Seek};
8181
#[doc(no_inline)] pub use str::{Str, StrVector, StrSlice};
8282
#[doc(no_inline)] pub use str::{IntoMaybeOwned, StrAllocating, UnicodeStrSlice};

0 commit comments

Comments
 (0)