Skip to content

Commit

Permalink
crate: add features to switch Error backend
Browse files Browse the repository at this point in the history
Allows end users to choose between anyhow and eyre.

Co-Authored-By: Jacob Rothstein <[email protected]>
  • Loading branch information
Fishrock123 and jbr committed Oct 27, 2020
1 parent 18b86df commit f7fd481
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 10 deletions.
13 changes: 10 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,26 @@ 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"]
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"
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"
Expand All @@ -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"
Expand Down
34 changes: 27 additions & 7 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -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.
///
Expand All @@ -14,7 +22,7 @@ pub type Result<T> = std::result::Result<T, Error>;

/// The error type for HTTP operations.
pub struct Error {
error: anyhow::Error,
error: BaseError,
status: crate::StatusCode,
type_name: Option<&'static str>,
}
Expand All @@ -29,7 +37,7 @@ impl Error {
where
S: TryInto<StatusCode>,
S::Error: Debug,
E: Into<anyhow::Error>,
E: Into<BaseError>,
{
Self {
status: status
Expand All @@ -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,
}
}
Expand Down Expand Up @@ -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() {
Expand All @@ -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<E>(self) -> std::result::Result<E, Self>
where
Expand Down Expand Up @@ -158,7 +178,7 @@ impl Debug for Error {
}
}

impl<E: Into<anyhow::Error>> From<E> for Error {
impl<E: Into<BaseError>> From<E> for Error {
fn from(error: E) -> Self {
Self::new(StatusCode::InternalServerError, error)
}
Expand Down
13 changes: 13 additions & 0 deletions tests/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down

0 comments on commit f7fd481

Please sign in to comment.