Skip to content

Commit f95111f

Browse files
committed
Add error module with Error and FromError traits
As per [RFC 70](https://github.com/rust-lang/rfcs/blob/master/active/0070-error-chaining.md) Closes #17747 Note that the `error` 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.
1 parent 7e66231 commit f95111f

File tree

5 files changed

+145
-4
lines changed

5 files changed

+145
-4
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/libstd/error.rs

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
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+
use any::{Any, AnyRefExt, AnyMutRefExt};
51+
use mem::{transmute, transmute_copy};
52+
use option::{Option, Some, None};
53+
use raw::TraitObject;
54+
use intrinsics::TypeId;
55+
use kinds::Send;
56+
use string::String;
57+
58+
/// Base functionality for all errors in Rust.
59+
pub trait Error: Send + Any {
60+
/// A short description of the error; usually a static string.
61+
fn description(&self) -> &str;
62+
63+
/// A detailed description of the error, usually including dynamic information.
64+
fn detail(&self) -> Option<String> { None }
65+
66+
/// The lower-level cause of this error, if any.
67+
fn cause(&self) -> Option<&Error> { None }
68+
}
69+
70+
/// A trait for types that can be converted from a given error type `E`.
71+
pub trait FromError<E> {
72+
/// Perform the conversion.
73+
fn from_error(err: E) -> Self;
74+
}
75+
76+
// Any type is convertable from itself
77+
impl<E> FromError<E> for E {
78+
fn from_error(err: E) -> E {
79+
err
80+
}
81+
}
82+
83+
// FIXME (#https://github.com/rust-lang/rust/pull/17669/): Add this once multidispatch lands
84+
// impl<E: Error> FromError<E> for Box<Error> {
85+
// fn from_err(err: E) -> Box<Error> {
86+
// box err as Box<Error>
87+
// }
88+
// }
89+
90+
// Note: the definitions below are copied from core::any, and should be unified
91+
// as soon as possible.
92+
93+
impl<'a> AnyRefExt<'a> for &'a Error {
94+
#[inline]
95+
fn is<T: 'static>(self) -> bool {
96+
// Get TypeId of the type this function is instantiated with
97+
let t = TypeId::of::<T>();
98+
99+
// Get TypeId of the type in the trait object
100+
let boxed = self.get_type_id();
101+
102+
// Compare both TypeIds on equality
103+
t == boxed
104+
}
105+
106+
#[inline]
107+
fn downcast_ref<T: 'static>(self) -> Option<&'a T> {
108+
if self.is::<T>() {
109+
unsafe {
110+
// Get the raw representation of the trait object
111+
let to: TraitObject = transmute_copy(&self);
112+
113+
// Extract the data pointer
114+
Some(transmute(to.data))
115+
}
116+
} else {
117+
None
118+
}
119+
}
120+
}
121+
122+
impl<'a> AnyMutRefExt<'a> for &'a mut Error {
123+
#[inline]
124+
fn downcast_mut<T: 'static>(self) -> Option<&'a mut T> {
125+
if self.is::<T>() {
126+
unsafe {
127+
// Get the raw representation of the trait object
128+
let to: TraitObject = transmute_copy(&self);
129+
130+
// Extract the data pointer
131+
Some(transmute(to.data))
132+
}
133+
} else {
134+
None
135+
}
136+
}
137+
}

src/libstd/lib.rs

+1
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;

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)