// coherence challenge (e.g., specialization, neg impls, etc) we can
// reconsider what crate these items belong in.
-use boxed::Box;
+use any::TypeId;
+use boxed::{self, Box};
use convert::From;
use fmt::{self, Debug, Display};
-use marker::{Send, Sync};
+use marker::{Send, Sync, Reflect};
+use mem::transmute;
use num;
-use option::Option;
-use option::Option::None;
+use option::Option::{self, Some, None};
+use result::Result::{self, Ok, Err};
+use raw::TraitObject;
use str;
use string::{self, String};
/// Base functionality for all errors in Rust.
#[stable(feature = "rust1", since = "1.0.0")]
-pub trait Error: Debug + Display {
+pub trait Error: Debug + Display + Reflect {
/// A short description of the error.
///
/// The description should not contain newlines or sentence-ending
/// The lower-level cause of this error, if any.
#[stable(feature = "rust1", since = "1.0.0")]
fn cause(&self) -> Option<&Error> { None }
+
+ /// Get the `TypeId` of `self`
+ #[doc(hidden)]
+ #[unstable(feature = "core",
+ reason = "unclear whether to commit to this public implementation detail")]
+ fn type_id(&self) -> TypeId where Self: 'static {
+ TypeId::of::<Self>()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
}
}
+// copied from any.rs
+impl Error + 'static {
+ /// Returns true if the boxed type is the same as `T`
+ #[unstable(feature = "error_downcast", reason = "recently added")]
+ #[inline]
+ pub fn is<T: Error + 'static>(&self) -> bool {
+ // Get TypeId of the type this function is instantiated with
+ let t = TypeId::of::<T>();
+
+ // Get TypeId of the type in the trait object
+ let boxed = self.type_id();
+
+ // Compare both TypeIds on equality
+ t == boxed
+ }
+
+ /// Returns some reference to the boxed value if it is of type `T`, or
+ /// `None` if it isn't.
+ #[unstable(feature = "error_downcast", reason = "recently added")]
+ #[inline]
+ pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
+ if self.is::<T>() {
+ unsafe {
+ // Get the raw representation of the trait object
+ let to: TraitObject = transmute(self);
+
+ // Extract the data pointer
+ Some(transmute(to.data))
+ }
+ } else {
+ None
+ }
+ }
+
+ /// Returns some mutable reference to the boxed value if it is of type `T`, or
+ /// `None` if it isn't.
+ #[unstable(feature = "error_downcast", reason = "recently added")]
+ #[inline]
+ pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
+ if self.is::<T>() {
+ unsafe {
+ // Get the raw representation of the trait object
+ let to: TraitObject = transmute(self);
+
+ // Extract the data pointer
+ Some(transmute(to.data))
+ }
+ } else {
+ None
+ }
+ }
+}
+
+impl Error + 'static + Send {
+ /// Forwards to the method defined on the type `Any`.
+ #[unstable(feature = "error_downcast", reason = "recently added")]
+ #[inline]
+ pub fn is<T: Error + 'static>(&self) -> bool {
+ <Error + 'static>::is::<T>(self)
+ }
+
+ /// Forwards to the method defined on the type `Any`.
+ #[unstable(feature = "error_downcast", reason = "recently added")]
+ #[inline]
+ pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
+ <Error + 'static>::downcast_ref::<T>(self)
+ }
+
+ /// Forwards to the method defined on the type `Any`.
+ #[unstable(feature = "error_downcast", reason = "recently added")]
+ #[inline]
+ pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
+ <Error + 'static>::downcast_mut::<T>(self)
+ }
+}
+
+impl Error {
+ #[inline]
+ #[unstable(feature = "error_downcast", reason = "recently added")]
+ /// Attempt to downcast the box to a concrete type.
+ pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Error>> {
+ if self.is::<T>() {
+ unsafe {
+ // Get the raw representation of the trait object
+ let raw = boxed::into_raw(self);
+ let to: TraitObject =
+ transmute::<*mut Error, TraitObject>(raw);
+
+ // Extract the data pointer
+ Ok(Box::from_raw(to.data as *mut T))
+ }
+ } else {
+ Err(self)
+ }
+ }
+}
+
+impl Error + Send {
+ #[inline]
+ #[unstable(feature = "error_downcast", reason = "recently added")]
+ /// Attempt to downcast the box to a concrete type.
+ pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Error + Send>> {
+ let err: Box<Error> = self;
+ <Error>::downcast(err).map_err(|s| unsafe {
+ // reapply the Send marker
+ transmute::<Box<Error>, Box<Error + Send>>(s)
+ })
+ }
+}