summaryrefslogtreecommitdiffstats
path: root/third_party/rust/failure/src/error
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/failure/src/error')
-rw-r--r--third_party/rust/failure/src/error/error_impl.rs50
-rw-r--r--third_party/rust/failure/src/error/error_impl_small.rs132
-rw-r--r--third_party/rust/failure/src/error/mod.rs248
3 files changed, 430 insertions, 0 deletions
diff --git a/third_party/rust/failure/src/error/error_impl.rs b/third_party/rust/failure/src/error/error_impl.rs
new file mode 100644
index 0000000000..6a95d92d18
--- /dev/null
+++ b/third_party/rust/failure/src/error/error_impl.rs
@@ -0,0 +1,50 @@
+use core::any::TypeId;
+
+use Fail;
+use backtrace::Backtrace;
+
+pub(crate) struct ErrorImpl {
+ inner: Box<Inner<dyn Fail>>,
+}
+
+struct Inner<F: ?Sized + Fail> {
+ backtrace: Backtrace,
+ pub(crate) failure: F,
+}
+
+impl<F: Fail> From<F> for ErrorImpl {
+ fn from(failure: F) -> ErrorImpl {
+ let inner: Inner<F> = {
+ let backtrace = if failure.backtrace().is_none() {
+ Backtrace::new()
+ } else { Backtrace::none() };
+ Inner { failure, backtrace }
+ };
+ ErrorImpl { inner: Box::new(inner) }
+ }
+}
+
+impl ErrorImpl {
+ pub(crate) fn failure(&self) -> &dyn Fail {
+ &self.inner.failure
+ }
+
+ pub(crate) fn failure_mut(&mut self) -> &mut dyn Fail {
+ &mut self.inner.failure
+ }
+
+ pub(crate) fn backtrace(&self) -> &Backtrace {
+ &self.inner.backtrace
+ }
+
+ pub(crate) fn downcast<T: Fail>(self) -> Result<T, ErrorImpl> {
+ if self.failure().__private_get_type_id__() == TypeId::of::<T>() {
+ let ErrorImpl { inner } = self;
+ let casted = unsafe { Box::from_raw(Box::into_raw(inner) as *mut Inner<T>) };
+ let Inner { backtrace:_, failure } = *casted;
+ Ok(failure)
+ } else {
+ Err(self)
+ }
+ }
+}
diff --git a/third_party/rust/failure/src/error/error_impl_small.rs b/third_party/rust/failure/src/error/error_impl_small.rs
new file mode 100644
index 0000000000..6ff7c78ec7
--- /dev/null
+++ b/third_party/rust/failure/src/error/error_impl_small.rs
@@ -0,0 +1,132 @@
+use std::heap::{Heap, Alloc, Layout};
+
+use core::mem;
+use core::ptr;
+
+use Fail;
+use backtrace::Backtrace;
+
+pub(crate) struct ErrorImpl {
+ inner: &'static mut Inner,
+}
+
+// Dynamically sized inner value
+struct Inner {
+ backtrace: Backtrace,
+ vtable: *const VTable,
+ failure: FailData,
+}
+
+unsafe impl Send for Inner { }
+unsafe impl Sync for Inner { }
+
+extern {
+ type VTable;
+ type FailData;
+}
+
+#[allow(dead_code)]
+struct InnerRaw<F> {
+ header: InnerHeader,
+ failure: F,
+}
+
+#[allow(dead_code)]
+struct InnerHeader {
+ backtrace: Backtrace,
+ vtable: *const VTable,
+}
+
+struct TraitObject {
+ #[allow(dead_code)]
+ data: *const FailData,
+ vtable: *const VTable,
+}
+
+impl<F: Fail> From<F> for ErrorImpl {
+ fn from(failure: F) -> ErrorImpl {
+ let backtrace = if failure.backtrace().is_none() {
+ Backtrace::new()
+ } else {
+ Backtrace::none()
+ };
+
+ unsafe {
+ let vtable = mem::transmute::<_, TraitObject>(&failure as &Fail).vtable;
+
+ let ptr: *mut InnerRaw<F> = match Heap.alloc(Layout::new::<InnerRaw<F>>()) {
+ Ok(p) => p as *mut InnerRaw<F>,
+ Err(e) => Heap.oom(e),
+ };
+
+ // N.B. must use `ptr::write`, not `=`, to avoid dropping the contents of `*ptr`
+ ptr::write(ptr, InnerRaw {
+ header: InnerHeader {
+ backtrace,
+ vtable,
+ },
+ failure,
+ });
+
+ let inner: &'static mut Inner = mem::transmute(ptr);
+
+ ErrorImpl { inner }
+ }
+ }
+}
+
+impl ErrorImpl {
+ pub(crate) fn failure(&self) -> &Fail {
+ unsafe {
+ mem::transmute::<TraitObject, &Fail>(TraitObject {
+ data: &self.inner.failure as *const FailData,
+ vtable: self.inner.vtable,
+ })
+ }
+ }
+
+ pub(crate) fn failure_mut(&mut self) -> &mut Fail {
+ unsafe {
+ mem::transmute::<TraitObject, &mut Fail>(TraitObject {
+ data: &mut self.inner.failure as *const FailData,
+ vtable: self.inner.vtable,
+ })
+ }
+ }
+
+ pub(crate) fn backtrace(&self) -> &Backtrace {
+ &self.inner.backtrace
+ }
+
+ pub(crate) fn downcast<T: Fail>(self) -> Result<T, ErrorImpl> {
+ let ret: Option<T> = self.failure().downcast_ref().map(|fail| {
+ unsafe {
+ // drop the backtrace
+ let _ = ptr::read(&self.inner.backtrace as *const Backtrace);
+ // read out the fail type
+ ptr::read(fail as *const T)
+ }
+ });
+ match ret {
+ Some(ret) => {
+ // forget self (backtrace is dropped, failure is moved
+ mem::forget(self);
+ Ok(ret)
+ }
+ _ => Err(self)
+ }
+ }
+}
+
+
+#[cfg(test)]
+mod test {
+ use std::mem::size_of;
+
+ use super::ErrorImpl;
+
+ #[test]
+ fn assert_is_one_word() {
+ assert_eq!(size_of::<ErrorImpl>(), size_of::<usize>());
+ }
+}
diff --git a/third_party/rust/failure/src/error/mod.rs b/third_party/rust/failure/src/error/mod.rs
new file mode 100644
index 0000000000..842dbbae0c
--- /dev/null
+++ b/third_party/rust/failure/src/error/mod.rs
@@ -0,0 +1,248 @@
+use core::fmt::{self, Display, Debug};
+
+use {Causes, Fail};
+use backtrace::Backtrace;
+use context::Context;
+use compat::Compat;
+
+#[cfg(feature = "std")]
+use box_std::BoxStd;
+
+#[cfg_attr(feature = "small-error", path = "./error_impl_small.rs")]
+mod error_impl;
+use self::error_impl::ErrorImpl;
+
+#[cfg(feature = "std")]
+use std::error::Error as StdError;
+
+
+/// The `Error` type, which can contain any failure.
+///
+/// Functions which accumulate many kinds of errors should return this type.
+/// All failures can be converted into it, so functions which catch those
+/// errors can be tried with `?` inside of a function that returns this kind
+/// of error.
+///
+/// In addition to implementing `Debug` and `Display`, this type carries `Backtrace`
+/// information, and can be downcast into the failure that underlies it for
+/// more detailed inspection.
+pub struct Error {
+ imp: ErrorImpl,
+}
+
+impl<F: Fail> From<F> for Error {
+ fn from(failure: F) -> Error {
+ Error {
+ imp: ErrorImpl::from(failure)
+ }
+ }
+}
+
+impl Error {
+ /// Creates an `Error` from `Box<std::error::Error>`.
+ ///
+ /// This method is useful for comparability with code,
+ /// which does not use the `Fail` trait.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use std::error::Error as StdError;
+ /// use failure::Error;
+ ///
+ /// fn app_fn() -> Result<i32, Error> {
+ /// let x = library_fn().map_err(Error::from_boxed_compat)?;
+ /// Ok(x * 2)
+ /// }
+ ///
+ /// fn library_fn() -> Result<i32, Box<StdError + Sync + Send + 'static>> {
+ /// Ok(92)
+ /// }
+ /// ```
+ #[cfg(feature = "std")]
+ pub fn from_boxed_compat(err: Box<dyn StdError + Sync + Send + 'static>) -> Error {
+ Error::from(BoxStd(err))
+ }
+
+ /// Return a reference to the underlying failure that this `Error`
+ /// contains.
+ pub fn as_fail(&self) -> &dyn Fail {
+ self.imp.failure()
+ }
+
+ /// Returns the name of the underlying fail.
+ pub fn name(&self) -> Option<&str> {
+ self.as_fail().name()
+ }
+
+ /// Returns a reference to the underlying cause of this `Error`. Unlike the
+ /// method on `Fail`, this does not return an `Option`. The `Error` type
+ /// always has an underlying failure.
+ ///
+ /// This method has been deprecated in favor of the [Error::as_fail] method,
+ /// which does the same thing.
+ #[deprecated(since = "0.1.2", note = "please use 'as_fail()' method instead")]
+ pub fn cause(&self) -> &dyn Fail {
+ self.as_fail()
+ }
+
+ /// Gets a reference to the `Backtrace` for this `Error`.
+ ///
+ /// If the failure this wrapped carried a backtrace, that backtrace will
+ /// be returned. Otherwise, the backtrace will have been constructed at
+ /// the point that failure was cast into the `Error` type.
+ pub fn backtrace(&self) -> &Backtrace {
+ self.imp.failure().backtrace().unwrap_or(&self.imp.backtrace())
+ }
+
+ /// Provides context for this `Error`.
+ ///
+ /// This can provide additional information about this error, appropriate
+ /// to the semantics of the current layer. That is, if you have a
+ /// lower-level error, such as an IO error, you can provide additional context
+ /// about what that error means in the context of your function. This
+ /// gives users of this function more information about what has gone
+ /// wrong.
+ ///
+ /// This takes any type that implements `Display`, as well as
+ /// `Send`/`Sync`/`'static`. In practice, this means it can take a `String`
+ /// or a string literal, or a failure, or some other custom context-carrying
+ /// type.
+ pub fn context<D: Display + Send + Sync + 'static>(self, context: D) -> Context<D> {
+ Context::with_err(context, self)
+ }
+
+ /// Wraps `Error` in a compatibility type.
+ ///
+ /// This type implements the `Error` trait from `std::error`. If you need
+ /// to pass failure's `Error` to an interface that takes any `Error`, you
+ /// can use this method to get a compatible type.
+ pub fn compat(self) -> Compat<Error> {
+ Compat { error: self }
+ }
+
+ /// Attempts to downcast this `Error` to a particular `Fail` type.
+ ///
+ /// This downcasts by value, returning an owned `T` if the underlying
+ /// failure is of the type `T`. For this reason it returns a `Result` - in
+ /// the case that the underlying error is of a different type, the
+ /// original `Error` is returned.
+ pub fn downcast<T: Fail>(self) -> Result<T, Error> {
+ self.imp.downcast().map_err(|imp| Error { imp })
+ }
+
+ /// Returns the "root cause" of this error - the last value in the
+ /// cause chain which does not return an underlying `cause`.
+ pub fn find_root_cause(&self) -> &dyn Fail {
+ self.as_fail().find_root_cause()
+ }
+
+ /// Returns a iterator over the causes of this error with the cause
+ /// of the fail as the first item and the `root_cause` as the final item.
+ ///
+ /// Use `iter_chain` to also include the fail of this error itself.
+ pub fn iter_causes(&self) -> Causes {
+ self.as_fail().iter_causes()
+ }
+
+ /// Returns a iterator over all fails up the chain from the current
+ /// as the first item up to the `root_cause` as the final item.
+ ///
+ /// This means that the chain also includes the fail itself which
+ /// means that it does *not* start with `cause`. To skip the outermost
+ /// fail use `iter_causes` instead.
+ pub fn iter_chain(&self) -> Causes {
+ self.as_fail().iter_chain()
+ }
+
+ /// Attempts to downcast this `Error` to a particular `Fail` type by
+ /// reference.
+ ///
+ /// If the underlying error is not of type `T`, this will return `None`.
+ pub fn downcast_ref<T: Fail>(&self) -> Option<&T> {
+ self.imp.failure().downcast_ref()
+ }
+
+ /// Attempts to downcast this `Error` to a particular `Fail` type by
+ /// mutable reference.
+ ///
+ /// If the underlying error is not of type `T`, this will return `None`.
+ pub fn downcast_mut<T: Fail>(&mut self) -> Option<&mut T> {
+ self.imp.failure_mut().downcast_mut()
+ }
+
+ /// Deprecated alias to `find_root_cause`.
+ #[deprecated(since = "0.1.2", note = "please use the 'find_root_cause()' method instead")]
+ pub fn root_cause(&self) -> &dyn Fail {
+ ::find_root_cause(self.as_fail())
+ }
+
+ /// Deprecated alias to `iter_causes`.
+ #[deprecated(since = "0.1.2", note = "please use the 'iter_chain()' method instead")]
+ pub fn causes(&self) -> Causes {
+ Causes { fail: Some(self.as_fail()) }
+ }
+}
+
+impl Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ Display::fmt(&self.imp.failure(), f)
+ }
+}
+
+impl Debug for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let backtrace = self.imp.backtrace();
+ if backtrace.is_none() {
+ Debug::fmt(&self.imp.failure(), f)
+ } else {
+ write!(f, "{:?}\n\n{:?}", &self.imp.failure(), backtrace)
+ }
+ }
+}
+
+impl AsRef<dyn Fail> for Error {
+ fn as_ref(&self) -> &dyn Fail {
+ self.as_fail()
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use std::io;
+ use super::Error;
+
+ fn assert_just_data<T: Send + Sync + 'static>() { }
+
+ #[test]
+ fn assert_error_is_just_data() {
+ assert_just_data::<Error>();
+ }
+
+ #[test]
+ fn methods_seem_to_work() {
+ let io_error: io::Error = io::Error::new(io::ErrorKind::NotFound, "test");
+ let error: Error = io::Error::new(io::ErrorKind::NotFound, "test").into();
+ assert!(error.downcast_ref::<io::Error>().is_some());
+ let _: ::Backtrace = *error.backtrace();
+ assert_eq!(format!("{:?}", io_error), format!("{:?}", error));
+ assert_eq!(format!("{}", io_error), format!("{}", error));
+ drop(error);
+ assert!(true);
+ }
+
+ #[test]
+ fn downcast_can_be_used() {
+ let mut error: Error = io::Error::new(io::ErrorKind::NotFound, "test").into();
+ {
+ let real_io_error_ref = error.downcast_ref::<io::Error>().unwrap();
+ assert_eq!(real_io_error_ref.to_string(), "test");
+ }
+ {
+ let real_io_error_mut = error.downcast_mut::<io::Error>().unwrap();
+ assert_eq!(real_io_error_mut.to_string(), "test");
+ }
+ let real_io_error = error.downcast::<io::Error>().unwrap();
+ assert_eq!(real_io_error.to_string(), "test");
+ }
+}