diff options
Diffstat (limited to 'rust/vendor/failure/src/context.rs')
-rw-r--r-- | rust/vendor/failure/src/context.rs | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/rust/vendor/failure/src/context.rs b/rust/vendor/failure/src/context.rs new file mode 100644 index 0000000..b5977e9 --- /dev/null +++ b/rust/vendor/failure/src/context.rs @@ -0,0 +1,180 @@ +use core::fmt::{self, Debug, Display}; + +use Fail; + +without_std! { + /// An error with context around it. + /// + /// The context is intended to be a human-readable, user-facing explanation for the + /// error that has occurred. The underlying error is not assumed to be end-user-relevant + /// information. + /// + /// The `Display` impl for `Context` only prints the human-readable context, while the + /// `Debug` impl also prints the underlying error. + pub struct Context<D: Display + Send + Sync + 'static> { + context: D, + } + + impl<D: Display + Send + Sync + 'static> Context<D> { + /// Creates a new context without an underlying error message. + pub fn new(context: D) -> Context<D> { + Context { context } + } + + /// Returns a reference to the context provided with this error. + pub fn get_context(&self) -> &D { + &self.context + } + + /// Maps `Context<D>` to `Context<T>` by applying a function to the contained context. + pub fn map<F, T>(self, op: F) -> Context<T> + where F: FnOnce(D) -> T, + T: Display + Send + Sync + 'static + { + Context { + context: op(self.context), + } + } + + pub(crate) fn with_err<E: Fail>(context: D, _: E) -> Context<D> { + Context { context } + } + } + + impl<D: Display + Send + Sync + 'static> Fail for Context<D> { } + + impl<D: Display + Send + Sync + 'static> Debug for Context<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.context) + } + } + + impl<D: Display + Send + Sync + 'static> Display for Context<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.context) + } + } + + #[test] + fn test_map() { + let ctx = Context::new("a string").map(|s| format!("{} with some more stuff", s)); + assert_eq!(ctx.context, String::from("a string with some more stuff")); + } +} + +with_std! { + use {Error, Backtrace}; + + /// An error with context around it. + /// + /// The context is intended to be a human-readable, user-facing explanation for the + /// error that has occurred. The underlying error is not assumed to be end-user-relevant + /// information. + /// + /// The `Display` impl for `Context` only prints the human-readable context, while the + /// `Debug` impl also prints the underlying error. + pub struct Context<D: Display + Send + Sync + 'static> { + context: D, + failure: Either<Backtrace, Error>, + } + + impl<D: Display + Send + Sync + 'static> Context<D> { + /// Creates a new context without an underlying error message. + pub fn new(context: D) -> Context<D> { + let failure = Either::This(Backtrace::new()); + Context { context, failure } + } + + /// Returns a reference to the context provided with this error. + pub fn get_context(&self) -> &D { + &self.context + } + + /// Maps `Context<D>` to `Context<T>` by applying a function to the contained context. + pub fn map<F, T>(self, op: F) -> Context<T> + where F: FnOnce(D) -> T, + T: Display + Send + Sync + 'static + { + Context { + context: op(self.context), + failure: self.failure, + } + } + + pub(crate) fn with_err<E: Into<Error>>(context: D, error: E) -> Context<D> { + let failure = Either::That(error.into()); + Context { context, failure } + } + } + + impl<D: Display + Send + Sync + 'static> Fail for Context<D> { + fn name(&self) -> Option<&str> { + self.failure.as_cause().and_then(|x| x.name()) + } + + fn cause(&self) -> Option<&dyn Fail> { + self.failure.as_cause() + } + + fn backtrace(&self) -> Option<&Backtrace> { + Some(self.failure.backtrace()) + } + } + + impl<D: Display + Send + Sync + 'static> Debug for Context<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}\n\n{}", self.failure, self.context) + } + } + + impl<D: Display + Send + Sync + 'static> Display for Context<D> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.context) + } + } + + enum Either<A, B> { + This(A), + That(B), + } + + impl Either<Backtrace, Error> { + fn backtrace(&self) -> &Backtrace { + match *self { + Either::This(ref backtrace) => backtrace, + Either::That(ref error) => error.backtrace(), + } + } + + fn as_cause(&self) -> Option<&dyn Fail> { + match *self { + Either::This(_) => None, + Either::That(ref error) => Some(error.as_fail()) + } + } + } + + impl Debug for Either<Backtrace, Error> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Either::This(ref backtrace) => write!(f, "{:?}", backtrace), + Either::That(ref error) => write!(f, "{:?}", error), + } + } + } + + #[test] + fn test_map() { + let ctx = Context::new("a string").map(|s| format!("{} with some more stuff", s)); + assert_eq!(ctx.context, String::from("a string with some more stuff")); + } +} + +impl<D> From<D> for Context<D> +where + D: Display + Send + Sync + 'static, +{ + fn from(display: D) -> Context<D> { + Context::new(display) + } +} |