4747// coherence challenge (e.g., specialization, neg impls, etc) we can
4848// reconsider what crate these items belong in.
4949
50- use boxed:: Box ;
50+ use any:: TypeId ;
51+ use boxed:: { self , Box } ;
5152use convert:: From ;
5253use fmt:: { self , Debug , Display } ;
53- use marker:: { Send , Sync } ;
54+ use marker:: { Send , Sync , Reflect } ;
55+ use mem:: transmute;
5456use num;
55- use option:: Option ;
56- use option:: Option :: None ;
57+ use option:: Option :: { self , Some , None } ;
58+ use result:: Result :: { self , Ok , Err } ;
59+ use raw:: TraitObject ;
5760use str;
5861use string:: { self , String } ;
5962
6063/// Base functionality for all errors in Rust.
6164#[ stable( feature = "rust1" , since = "1.0.0" ) ]
62- pub trait Error : Debug + Display {
65+ pub trait Error : Debug + Display + Reflect {
6366 /// A short description of the error.
6467 ///
6568 /// The description should not contain newlines or sentence-ending
@@ -71,6 +74,14 @@ pub trait Error: Debug + Display {
7174 /// The lower-level cause of this error, if any.
7275 #[ stable( feature = "rust1" , since = "1.0.0" ) ]
7376 fn cause ( & self ) -> Option < & Error > { None }
77+
78+ /// Get the `TypeId` of `self`
79+ #[ doc( hidden) ]
80+ #[ unstable( feature = "core" ,
81+ reason = "unclear whether to commit to this public implementation detail" ) ]
82+ fn type_id ( & self ) -> TypeId where Self : ' static {
83+ TypeId :: of :: < Self > ( )
84+ }
7485}
7586
7687#[ stable( feature = "rust1" , since = "1.0.0" ) ]
@@ -154,3 +165,112 @@ impl Error for string::FromUtf16Error {
154165 }
155166}
156167
168+ // copied from any.rs
169+ impl Error + ' static {
170+ /// Returns true if the boxed type is the same as `T`
171+ #[ unstable( feature = "error_downcast" , reason = "recently added" ) ]
172+ #[ inline]
173+ pub fn is < T : Error + ' static > ( & self ) -> bool {
174+ // Get TypeId of the type this function is instantiated with
175+ let t = TypeId :: of :: < T > ( ) ;
176+
177+ // Get TypeId of the type in the trait object
178+ let boxed = self . type_id ( ) ;
179+
180+ // Compare both TypeIds on equality
181+ t == boxed
182+ }
183+
184+ /// Returns some reference to the boxed value if it is of type `T`, or
185+ /// `None` if it isn't.
186+ #[ unstable( feature = "error_downcast" , reason = "recently added" ) ]
187+ #[ inline]
188+ pub fn downcast_ref < T : Error + ' static > ( & self ) -> Option < & T > {
189+ if self . is :: < T > ( ) {
190+ unsafe {
191+ // Get the raw representation of the trait object
192+ let to: TraitObject = transmute ( self ) ;
193+
194+ // Extract the data pointer
195+ Some ( transmute ( to. data ) )
196+ }
197+ } else {
198+ None
199+ }
200+ }
201+
202+ /// Returns some mutable reference to the boxed value if it is of type `T`, or
203+ /// `None` if it isn't.
204+ #[ unstable( feature = "error_downcast" , reason = "recently added" ) ]
205+ #[ inline]
206+ pub fn downcast_mut < T : Error + ' static > ( & mut self ) -> Option < & mut T > {
207+ if self . is :: < T > ( ) {
208+ unsafe {
209+ // Get the raw representation of the trait object
210+ let to: TraitObject = transmute ( self ) ;
211+
212+ // Extract the data pointer
213+ Some ( transmute ( to. data ) )
214+ }
215+ } else {
216+ None
217+ }
218+ }
219+ }
220+
221+ impl Error + ' static + Send {
222+ /// Forwards to the method defined on the type `Any`.
223+ #[ unstable( feature = "error_downcast" , reason = "recently added" ) ]
224+ #[ inline]
225+ pub fn is < T : Error + ' static > ( & self ) -> bool {
226+ <Error + ' static >:: is :: < T > ( self )
227+ }
228+
229+ /// Forwards to the method defined on the type `Any`.
230+ #[ unstable( feature = "error_downcast" , reason = "recently added" ) ]
231+ #[ inline]
232+ pub fn downcast_ref < T : Error + ' static > ( & self ) -> Option < & T > {
233+ <Error + ' static >:: downcast_ref :: < T > ( self )
234+ }
235+
236+ /// Forwards to the method defined on the type `Any`.
237+ #[ unstable( feature = "error_downcast" , reason = "recently added" ) ]
238+ #[ inline]
239+ pub fn downcast_mut < T : Error + ' static > ( & mut self ) -> Option < & mut T > {
240+ <Error + ' static >:: downcast_mut :: < T > ( self )
241+ }
242+ }
243+
244+ impl Error {
245+ #[ inline]
246+ #[ unstable( feature = "error_downcast" , reason = "recently added" ) ]
247+ /// Attempt to downcast the box to a concrete type.
248+ pub fn downcast < T : Error + ' static > ( self : Box < Self > ) -> Result < Box < T > , Box < Error > > {
249+ if self . is :: < T > ( ) {
250+ unsafe {
251+ // Get the raw representation of the trait object
252+ let raw = boxed:: into_raw ( self ) ;
253+ let to: TraitObject =
254+ transmute :: < * mut Error , TraitObject > ( raw) ;
255+
256+ // Extract the data pointer
257+ Ok ( Box :: from_raw ( to. data as * mut T ) )
258+ }
259+ } else {
260+ Err ( self )
261+ }
262+ }
263+ }
264+
265+ impl Error + Send {
266+ #[ inline]
267+ #[ unstable( feature = "error_downcast" , reason = "recently added" ) ]
268+ /// Attempt to downcast the box to a concrete type.
269+ pub fn downcast < T : Error + ' static > ( self : Box < Self > ) -> Result < Box < T > , Box < Error + Send > > {
270+ let err: Box < Error > = self ;
271+ <Error >:: downcast ( err) . map_err ( |s| unsafe {
272+ // reapply the Send marker
273+ transmute :: < Box < Error > , Box < Error + Send > > ( s)
274+ } )
275+ }
276+ }
0 commit comments