Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cherry-pick std::error downcasting to beta #25121

Merged
merged 1 commit into from
May 5, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions src/liballoc/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ impl<T: ?Sized + Hash> Hash for Box<T> {
impl Box<Any> {
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// Attempt to downcast the box to a concrete type.
pub fn downcast<T: Any>(self) -> Result<Box<T>, Box<Any>> {
if self.is::<T>() {
unsafe {
Expand All @@ -257,11 +258,15 @@ impl Box<Any> {
}
}

impl Box<Any+Send> {
impl Box<Any + Send> {
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn downcast<T: Any>(self) -> Result<Box<T>, Box<Any>> {
<Box<Any>>::downcast(self)
/// Attempt to downcast the box to a concrete type.
pub fn downcast<T: Any>(self) -> Result<Box<T>, Box<Any + Send>> {
<Box<Any>>::downcast(self).map_err(|s| unsafe {
// reapply the Send marker
mem::transmute::<Box<Any>, Box<Any + Send>>(s)
})
}
}

Expand Down
6 changes: 2 additions & 4 deletions src/libcore/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,7 @@ pub trait Any: Reflect + 'static {
fn get_type_id(&self) -> TypeId;
}

impl<T> Any for T
where T: Reflect + 'static
{
impl<T: Reflect + 'static> Any for T {
fn get_type_id(&self) -> TypeId { TypeId::of::<T>() }
}

Expand Down Expand Up @@ -222,7 +220,7 @@ impl TypeId {
/// Returns the `TypeId` of the type this generic function has been
/// instantiated with
#[stable(feature = "rust1", since = "1.0.0")]
pub fn of<T: ?Sized + Any>() -> TypeId {
pub fn of<T: ?Sized + Reflect + 'static>() -> TypeId {
TypeId {
t: unsafe { intrinsics::type_id::<T>() },
}
Expand Down
2 changes: 2 additions & 0 deletions src/libcore/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,8 @@ mod impls {
#[unstable(feature = "core", reason = "requires RFC and more experience")]
#[allow(deprecated)]
#[cfg(not(stage0))]
#[rustc_on_unimplemented = "`{Self}` does not implement `Any`; \
ensure all type parameters are bounded by `Any`"]
pub trait Reflect {}

/// dox
Expand Down
130 changes: 125 additions & 5 deletions src/libstd/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,22 @@
// 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
Expand All @@ -71,6 +74,14 @@ pub trait Error: Debug + Display {
/// 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")]
Expand Down Expand Up @@ -154,3 +165,112 @@ impl Error for string::FromUtf16Error {
}
}

// 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)
})
}
}
3 changes: 2 additions & 1 deletion src/libstd/io/buffered.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use prelude::v1::*;
use io::prelude::*;

use marker::Reflect;
use cmp;
use error;
use fmt;
Expand Down Expand Up @@ -325,7 +326,7 @@ impl<W> From<IntoInnerError<W>> for Error {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Send + fmt::Debug> error::Error for IntoInnerError<W> {
impl<W: Reflect + Send + fmt::Debug> error::Error for IntoInnerError<W> {
fn description(&self) -> &str {
error::Error::description(self.error())
}
Expand Down
6 changes: 3 additions & 3 deletions src/libstd/sync/mpsc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ use error;
use fmt;
use mem;
use cell::UnsafeCell;
use marker::Reflect;

pub use self::select::{Select, Handle};
use self::select::StartResult;
Expand Down Expand Up @@ -927,8 +928,7 @@ impl<T> fmt::Display for SendError<T> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Send> error::Error for SendError<T> {

impl<T: Send + Reflect> error::Error for SendError<T> {
fn description(&self) -> &str {
"sending on a closed channel"
}
Expand Down Expand Up @@ -963,7 +963,7 @@ impl<T> fmt::Display for TrySendError<T> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Send> error::Error for TrySendError<T> {
impl<T: Send + Reflect> error::Error for TrySendError<T> {

fn description(&self) -> &str {
match *self {
Expand Down
7 changes: 4 additions & 3 deletions src/libstd/sys/common/poison.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

use prelude::v1::*;

use marker::Reflect;
use cell::UnsafeCell;
use error::{Error};
use fmt;
Expand Down Expand Up @@ -109,7 +110,7 @@ impl<T> fmt::Display for PoisonError<T> {
}
}

impl<T: Send> Error for PoisonError<T> {
impl<T: Send + Reflect> Error for PoisonError<T> {
fn description(&self) -> &str {
"poisoned lock: another task failed inside"
}
Expand Down Expand Up @@ -155,13 +156,13 @@ impl<T> fmt::Debug for TryLockError<T> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Send> fmt::Display for TryLockError<T> {
impl<T: Send + Reflect> fmt::Display for TryLockError<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.description().fmt(f)
}
}

impl<T: Send> Error for TryLockError<T> {
impl<T: Send + Reflect> Error for TryLockError<T> {
fn description(&self) -> &str {
match *self {
TryLockError::Poisoned(ref p) => p.description(),
Expand Down