PageRenderTime 62ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/src/libstd/error.rs

https://github.com/paulstansifer/rust
Rust | 361 lines | 240 code | 43 blank | 78 comment | 23 complexity | 3ccfd8ee2f594abde60480d6052412e9 MD5 | raw file
Possible License(s): 0BSD, Apache-2.0, MIT, AGPL-1.0
  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. //! Traits for working with Errors.
  11. //!
  12. //! # The `Error` trait
  13. //!
  14. //! `Error` is a trait representing the basic expectations for error values,
  15. //! i.e. values of type `E` in `Result<T, E>`. At a minimum, errors must provide
  16. //! a description, but they may optionally provide additional detail (via
  17. //! `Display`) and cause chain information:
  18. //!
  19. //! ```
  20. //! use std::fmt::Display;
  21. //!
  22. //! trait Error: Display {
  23. //! fn description(&self) -> &str;
  24. //!
  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. #![stable(feature = "rust1", since = "1.0.0")]
  36. // A note about crates and the facade:
  37. //
  38. // Originally, the `Error` trait was defined in libcore, and the impls
  39. // were scattered about. However, coherence objected to this
  40. // arrangement, because to create the blanket impls for `Box` required
  41. // knowing that `&str: !Error`, and we have no means to deal with that
  42. // sort of conflict just now. Therefore, for the time being, we have
  43. // moved the `Error` trait into libstd. As we evolve a sol'n to the
  44. // coherence challenge (e.g., specialization, neg impls, etc) we can
  45. // reconsider what crate these items belong in.
  46. use any::TypeId;
  47. use boxed::Box;
  48. use convert::From;
  49. use fmt::{self, Debug, Display};
  50. use marker::{Send, Sync, Reflect};
  51. use mem::transmute;
  52. use num;
  53. use option::Option::{self, Some, None};
  54. use result::Result::{self, Ok, Err};
  55. use raw::TraitObject;
  56. use str;
  57. use string::{self, String};
  58. /// Base functionality for all errors in Rust.
  59. #[stable(feature = "rust1", since = "1.0.0")]
  60. pub trait Error: Debug + Display + Reflect {
  61. /// A short description of the error.
  62. ///
  63. /// The description should not contain newlines or sentence-ending
  64. /// punctuation, to facilitate embedding in larger user-facing
  65. /// strings.
  66. #[stable(feature = "rust1", since = "1.0.0")]
  67. fn description(&self) -> &str;
  68. /// The lower-level cause of this error, if any.
  69. #[stable(feature = "rust1", since = "1.0.0")]
  70. fn cause(&self) -> Option<&Error> { None }
  71. /// Get the `TypeId` of `self`
  72. #[doc(hidden)]
  73. #[unstable(feature = "error_type_id",
  74. reason = "unclear whether to commit to this public implementation detail",
  75. issue = "27745")]
  76. fn type_id(&self) -> TypeId where Self: 'static {
  77. TypeId::of::<Self>()
  78. }
  79. }
  80. #[stable(feature = "rust1", since = "1.0.0")]
  81. impl<'a, E: Error + 'a> From<E> for Box<Error + 'a> {
  82. fn from(err: E) -> Box<Error + 'a> {
  83. Box::new(err)
  84. }
  85. }
  86. #[stable(feature = "rust1", since = "1.0.0")]
  87. impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<Error + Send + Sync + 'a> {
  88. fn from(err: E) -> Box<Error + Send + Sync + 'a> {
  89. Box::new(err)
  90. }
  91. }
  92. #[stable(feature = "rust1", since = "1.0.0")]
  93. impl From<String> for Box<Error + Send + Sync> {
  94. fn from(err: String) -> Box<Error + Send + Sync> {
  95. #[derive(Debug)]
  96. struct StringError(String);
  97. impl Error for StringError {
  98. fn description(&self) -> &str { &self.0 }
  99. }
  100. impl Display for StringError {
  101. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  102. Display::fmt(&self.0, f)
  103. }
  104. }
  105. Box::new(StringError(err))
  106. }
  107. }
  108. #[stable(feature = "rust1", since = "1.0.0")]
  109. impl<'a, 'b> From<&'b str> for Box<Error + Send + Sync + 'a> {
  110. fn from(err: &'b str) -> Box<Error + Send + Sync + 'a> {
  111. From::from(String::from(err))
  112. }
  113. }
  114. #[stable(feature = "rust1", since = "1.0.0")]
  115. impl Error for str::ParseBoolError {
  116. fn description(&self) -> &str { "failed to parse bool" }
  117. }
  118. #[stable(feature = "rust1", since = "1.0.0")]
  119. impl Error for str::Utf8Error {
  120. fn description(&self) -> &str {
  121. "invalid utf-8: corrupt contents"
  122. }
  123. }
  124. #[stable(feature = "rust1", since = "1.0.0")]
  125. impl Error for num::ParseIntError {
  126. fn description(&self) -> &str {
  127. self.__description()
  128. }
  129. }
  130. #[stable(feature = "rust1", since = "1.0.0")]
  131. impl Error for num::ParseFloatError {
  132. fn description(&self) -> &str {
  133. self.__description()
  134. }
  135. }
  136. #[stable(feature = "rust1", since = "1.0.0")]
  137. impl Error for string::FromUtf8Error {
  138. fn description(&self) -> &str {
  139. "invalid utf-8"
  140. }
  141. }
  142. #[stable(feature = "rust1", since = "1.0.0")]
  143. impl Error for string::FromUtf16Error {
  144. fn description(&self) -> &str {
  145. "invalid utf-16"
  146. }
  147. }
  148. // copied from any.rs
  149. impl Error + 'static {
  150. /// Returns true if the boxed type is the same as `T`
  151. #[stable(feature = "error_downcast", since = "1.3.0")]
  152. #[inline]
  153. pub fn is<T: Error + 'static>(&self) -> bool {
  154. // Get TypeId of the type this function is instantiated with
  155. let t = TypeId::of::<T>();
  156. // Get TypeId of the type in the trait object
  157. let boxed = self.type_id();
  158. // Compare both TypeIds on equality
  159. t == boxed
  160. }
  161. /// Returns some reference to the boxed value if it is of type `T`, or
  162. /// `None` if it isn't.
  163. #[stable(feature = "error_downcast", since = "1.3.0")]
  164. #[inline]
  165. pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
  166. if self.is::<T>() {
  167. unsafe {
  168. // Get the raw representation of the trait object
  169. let to: TraitObject = transmute(self);
  170. // Extract the data pointer
  171. Some(&*(to.data as *const T))
  172. }
  173. } else {
  174. None
  175. }
  176. }
  177. /// Returns some mutable reference to the boxed value if it is of type `T`, or
  178. /// `None` if it isn't.
  179. #[stable(feature = "error_downcast", since = "1.3.0")]
  180. #[inline]
  181. pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
  182. if self.is::<T>() {
  183. unsafe {
  184. // Get the raw representation of the trait object
  185. let to: TraitObject = transmute(self);
  186. // Extract the data pointer
  187. Some(&mut *(to.data as *const T as *mut T))
  188. }
  189. } else {
  190. None
  191. }
  192. }
  193. }
  194. impl Error + 'static + Send {
  195. /// Forwards to the method defined on the type `Any`.
  196. #[stable(feature = "error_downcast", since = "1.3.0")]
  197. #[inline]
  198. pub fn is<T: Error + 'static>(&self) -> bool {
  199. <Error + 'static>::is::<T>(self)
  200. }
  201. /// Forwards to the method defined on the type `Any`.
  202. #[stable(feature = "error_downcast", since = "1.3.0")]
  203. #[inline]
  204. pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
  205. <Error + 'static>::downcast_ref::<T>(self)
  206. }
  207. /// Forwards to the method defined on the type `Any`.
  208. #[stable(feature = "error_downcast", since = "1.3.0")]
  209. #[inline]
  210. pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
  211. <Error + 'static>::downcast_mut::<T>(self)
  212. }
  213. }
  214. impl Error + 'static + Send + Sync {
  215. /// Forwards to the method defined on the type `Any`.
  216. #[stable(feature = "error_downcast", since = "1.3.0")]
  217. #[inline]
  218. pub fn is<T: Error + 'static>(&self) -> bool {
  219. <Error + 'static>::is::<T>(self)
  220. }
  221. /// Forwards to the method defined on the type `Any`.
  222. #[stable(feature = "error_downcast", since = "1.3.0")]
  223. #[inline]
  224. pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
  225. <Error + 'static>::downcast_ref::<T>(self)
  226. }
  227. /// Forwards to the method defined on the type `Any`.
  228. #[stable(feature = "error_downcast", since = "1.3.0")]
  229. #[inline]
  230. pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
  231. <Error + 'static>::downcast_mut::<T>(self)
  232. }
  233. }
  234. impl Error {
  235. #[inline]
  236. #[stable(feature = "error_downcast", since = "1.3.0")]
  237. /// Attempt to downcast the box to a concrete type.
  238. pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Error>> {
  239. if self.is::<T>() {
  240. unsafe {
  241. // Get the raw representation of the trait object
  242. let raw = Box::into_raw(self);
  243. let to: TraitObject =
  244. transmute::<*mut Error, TraitObject>(raw);
  245. // Extract the data pointer
  246. Ok(Box::from_raw(to.data as *mut T))
  247. }
  248. } else {
  249. Err(self)
  250. }
  251. }
  252. }
  253. impl Error + Send {
  254. #[inline]
  255. #[stable(feature = "error_downcast", since = "1.3.0")]
  256. /// Attempt to downcast the box to a concrete type.
  257. pub fn downcast<T: Error + 'static>(self: Box<Self>)
  258. -> Result<Box<T>, Box<Error + Send>> {
  259. let err: Box<Error> = self;
  260. <Error>::downcast(err).map_err(|s| unsafe {
  261. // reapply the Send marker
  262. transmute::<Box<Error>, Box<Error + Send>>(s)
  263. })
  264. }
  265. }
  266. impl Error + Send + Sync {
  267. #[inline]
  268. #[stable(feature = "error_downcast", since = "1.3.0")]
  269. /// Attempt to downcast the box to a concrete type.
  270. pub fn downcast<T: Error + 'static>(self: Box<Self>)
  271. -> Result<Box<T>, Box<Self>> {
  272. let err: Box<Error> = self;
  273. <Error>::downcast(err).map_err(|s| unsafe {
  274. // reapply the Send+Sync marker
  275. transmute::<Box<Error>, Box<Error + Send + Sync>>(s)
  276. })
  277. }
  278. }
  279. #[cfg(test)]
  280. mod tests {
  281. use prelude::v1::*;
  282. use super::Error;
  283. use fmt;
  284. #[derive(Debug, PartialEq)]
  285. struct A;
  286. #[derive(Debug, PartialEq)]
  287. struct B;
  288. impl fmt::Display for A {
  289. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  290. write!(f, "A")
  291. }
  292. }
  293. impl fmt::Display for B {
  294. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  295. write!(f, "B")
  296. }
  297. }
  298. impl Error for A {
  299. fn description(&self) -> &str { "A-desc" }
  300. }
  301. impl Error for B {
  302. fn description(&self) -> &str { "A-desc" }
  303. }
  304. #[test]
  305. fn downcasting() {
  306. let mut a = A;
  307. let mut a = &mut a as &mut (Error + 'static);
  308. assert_eq!(a.downcast_ref::<A>(), Some(&A));
  309. assert_eq!(a.downcast_ref::<B>(), None);
  310. assert_eq!(a.downcast_mut::<A>(), Some(&mut A));
  311. assert_eq!(a.downcast_mut::<B>(), None);
  312. let a: Box<Error> = Box::new(A);
  313. match a.downcast::<B>() {
  314. Ok(..) => panic!("expected error"),
  315. Err(e) => assert_eq!(*e.downcast::<A>().unwrap(), A),
  316. }
  317. }
  318. }