diff --git a/Cargo.toml b/Cargo.toml index 4c03a1c1..555bc5ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,8 +16,10 @@ features = ["docs"] rustdoc-args = ["--cfg", "feature=\"docs\""] [features] -default = ["fs", "cookie-secure"] +default = ["error_anyhow", "fs", "cookie-secure"] docs = ["unstable"] +error_anyhow = ["anyhow"] +error_eyre = ["eyre", "stable-eyre"] unstable = [] hyperium_http = ["http"] async_std = ["fs"] @@ -25,6 +27,8 @@ cookie-secure = ["cookie/secure"] fs = ["async-std"] [dependencies] +# features: error_anyhow +anyhow = { version = "1.0.26", optional = true } # features: async_std async-std = { version = "1.6.0", optional = true } futures-lite = "1.11.1" @@ -32,8 +36,6 @@ async-channel = "1.5.1" # features: hyperium/http http = { version = "0.2.0", optional = true } - -anyhow = "1.0.26" cookie = { version = "0.14.0", features = ["percent-encode"] } infer = "0.2.3" pin-project-lite = "0.1.0" @@ -44,6 +46,11 @@ serde_urlencoded = "0.7.0" rand = "0.7.3" serde_qs = "0.7.0" base64 = "0.13.0" +backtrace = "0.3.50" + +# features: error_anyhow +eyre = { version = "0.6.1", optional = true } +stable-eyre = { version = "0.2.1", optional = true } [dev-dependencies] http = "0.2.0" diff --git a/src/error.rs b/src/error.rs index 00adc706..212d9623 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,10 +1,18 @@ //! HTTP error types +use std::convert::TryInto; use std::error::Error as StdError; use std::fmt::{self, Debug, Display}; use crate::StatusCode; -use std::convert::TryInto; + +#[cfg(all(not(backtrace), feature = "error_eyre"))] +use stable_eyre::BacktraceExt; + +#[cfg(feature = "error_anyhow")] +use anyhow::Error as BaseError; +#[cfg(feature = "error_eyre")] +use eyre::Report as BaseError; /// A specialized `Result` type for HTTP operations. /// @@ -14,7 +22,7 @@ pub type Result = std::result::Result; /// The error type for HTTP operations. pub struct Error { - error: anyhow::Error, + error: BaseError, status: crate::StatusCode, type_name: Option<&'static str>, } @@ -29,7 +37,7 @@ impl Error { where S: TryInto, S::Error: Debug, - E: Into, + E: Into, { Self { status: status @@ -51,7 +59,7 @@ impl Error { status: status .try_into() .expect("Could not convert into a valid `StatusCode`"), - error: anyhow::Error::msg(msg), + error: BaseError::msg(msg), type_name: None, } } @@ -96,7 +104,7 @@ impl Error { /// compiled on a toolchain that does not support backtraces, or /// if executed without backtraces enabled with /// `RUST_LIB_BACKTRACE=1`. - #[cfg(backtrace)] + #[cfg(all(backtrace, feature = "error_anyhow"))] pub fn backtrace(&self) -> Option<&std::backtrace::Backtrace> { let backtrace = self.error.backtrace(); if let std::backtrace::BacktraceStatus::Captured = backtrace.status() { @@ -106,12 +114,24 @@ impl Error { } } - #[cfg(not(backtrace))] + #[cfg(all(not(backtrace), feature = "error_anyhow"))] #[allow(missing_docs)] pub fn backtrace(&self) -> Option<()> { None } + #[cfg(all(backtrace, feature = "error_eyre"))] + #[allow(missing_docs)] + pub fn backtrace(&self) -> Option<&std::backtrace::Backtrace> { + self.error.backtrace() + } + + #[cfg(all(not(backtrace), feature = "error_eyre"))] + #[allow(missing_docs)] + pub fn backtrace(&self) -> Option<&backtrace::Backtrace> { + self.error.backtrace() + } + /// Attempt to downcast the error object to a concrete type. pub fn downcast(self) -> std::result::Result where @@ -158,7 +178,7 @@ impl Debug for Error { } } -impl> From for Error { +impl> From for Error { fn from(error: E) -> Self { Self::new(StatusCode::InternalServerError, error) } diff --git a/tests/error.rs b/tests/error.rs index 4cf97923..cc425505 100644 --- a/tests/error.rs +++ b/tests/error.rs @@ -71,6 +71,19 @@ fn option_ext() { assert_eq!(err.status(), StatusCode::NotFound); } +#[cfg(feature = "error_eyre")] +#[test] +fn eyre_error_into_http_types_error() { + let eyre_error = eyre::Error::new(std::io::Error::new(std::io::ErrorKind::Other, "irrelevant")); + let http_types_error: Error = eyre_error.into(); + assert_eq!(http_types_error.status(), StatusCode::InternalServerError); + + let eyre_error = eyre::Error::new(std::io::Error::new(std::io::ErrorKind::Other, "irrelevant")); + let http_types_error: Error = Error::new(StatusCode::ImATeapot, eyre_error); + assert_eq!(http_types_error.status(), StatusCode::ImATeapot); +} + +#[cfg(feature = "error_anyhow")] #[test] fn anyhow_error_into_http_types_error() { let anyhow_error =