Skip to content

Commit

Permalink
feat: Add consume_with
Browse files Browse the repository at this point in the history
  • Loading branch information
mcmah309 committed Dec 28, 2024
1 parent b422e74 commit 4bc6836
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 4 deletions.
52 changes: 50 additions & 2 deletions err_trail/src/tracing_log_stub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ mod sealed {
docsrs,
doc(cfg(any(feature = "tracing", feature = "log", feature = "stub")))
)]
pub trait ErrContext<T, E: Display>: sealed::Sealed {
pub trait ErrContext<T, E>: sealed::Sealed {
/// If [Err], logging context as an "error".
fn error_context(self, context: impl Display) -> Result<T, E>;
/// If [Err], logging context as an "warn".
Expand All @@ -22,6 +22,20 @@ pub trait ErrContext<T, E: Display>: sealed::Sealed {
/// If [Err], lazily logging the result of [f] as an "warn".
fn with_warn_context<F: FnOnce(&E) -> D, D: Display>(self, f: F) -> Result<T, E>;

/// Consumes the [Err] of a Result. If [Err], lazily logging the result of [f] as an "error".
/// Represents a bad state in which the current process cannot continue.
fn consume_with_error<F: FnOnce(&E) -> D, D: Display>(self, f: F) -> Option<T>;
/// Consumes the [Err] of a Result. If [Err], lazily logging the result of [f] as an "warn".
/// Represents a bad state in which the current process can continue.
fn consume_with_warn<F: FnOnce(&E) -> D, D: Display>(self, f: F) -> Option<T>;
}

/// For logging a [Result] when [Err] is encountered and [E] is [Display]
#[cfg_attr(
docsrs,
doc(cfg(any(feature = "tracing", feature = "log", feature = "stub")))
)]
pub trait ErrContextDisplay<T,E: Display>: ErrContext<T,E> + sealed::Sealed {
/// Consumes the [Err] of a Result. If [Err], logging the display of the error as an "error".
/// Represents a bad state in which the current process cannot continue.
fn consume_as_error(self) -> Option<T>;
Expand Down Expand Up @@ -50,7 +64,7 @@ pub trait NoneContext<T>: sealed::Sealed {
//************************************************************************//

impl<T, E> sealed::Sealed for Result<T, E> {}
impl<T, E: Display> ErrContext<T, E> for Result<T, E> {
impl<T, E> ErrContext<T, E> for Result<T, E> {
#[inline]
fn error_context(self, context: impl Display) -> Result<T, E> {
if self.is_err() {
Expand Down Expand Up @@ -97,7 +111,41 @@ impl<T, E: Display> ErrContext<T, E> for Result<T, E> {
self
}

//************************************************************************//

#[inline]
fn consume_with_error<F: FnOnce(&E) -> D, D: Display>(self, f: F) -> Option<T> {
match self {
Ok(value) => Some(value),
Err(err) => {
#[cfg(feature = "tracing")]
tracing::error!("{}", f(&err));
#[cfg(feature = "log")]
log::error!("{}", f(&err));
None
}
}
}

#[inline]
fn consume_with_warn<F: FnOnce(&E) -> D, D: Display>(self, f: F) -> Option<T> {
match self {
Ok(value) => Some(value),
Err(err) => {
#[cfg(feature = "tracing")]
tracing::warn!("{}", f(&err));
#[cfg(feature = "log")]
log::warn!("{}", f(&err));
None
}
}
}
}

//************************************************************************//

impl<T, E: Display> ErrContextDisplay<T, E> for Result<T, E> {
#[inline]
fn consume_as_error(self) -> Option<T> {
match self {
Ok(value) => Some(value),
Expand Down
40 changes: 38 additions & 2 deletions err_trail/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#[cfg(feature = "tracing")]
#[cfg(test)]
mod tracing {
use err_trail::{ErrContext, NoneContext};
use err_trail::{ErrContext, ErrContextDisplay, NoneContext};
use tracing_test::traced_test;

#[traced_test]
Expand Down Expand Up @@ -40,6 +40,24 @@ mod tracing {
assert!(logs_contain("A warning occurred: `warning`"));
}

#[traced_test]
#[test]
fn test_consume_with_error() {
let result: Result<(), &str> = Err("");
let _ = result.consume_with_error(|_| "consumed with error");

assert!(logs_contain("consumed with error"));
}

#[traced_test]
#[test]
fn test_consume_with_warn() {
let result: Result<(), &str> = Err("");
let _ = result.consume_with_warn(|_| "consumed with warn");

assert!(logs_contain("consumed with warn"));
}

#[traced_test]
#[test]
fn test_consume_as_error() {
Expand Down Expand Up @@ -98,7 +116,7 @@ mod tracing {
#[cfg(feature = "log")]
#[cfg(test)]
mod log {
use err_trail::{ErrContext, NoneContext};
use err_trail::{ErrContext, ErrContextDisplay, NoneContext};
use lazy_static::lazy_static;
use log::{Level, Metadata, Record};
use std::sync::{Arc, Mutex};
Expand Down Expand Up @@ -180,6 +198,24 @@ mod log {
assert!(logs_contain("A warning occurred: `warning`"));
}

#[test]
fn test_consume_with_error() {
clear_logs();
let result: Result<(), &str> = Err("");
let _ = result.consume_with_error(|_| "consumed with error");

assert!(logs_contain("consumed with error"));
}

#[test]
fn test_consume_with_warn() {
clear_logs();
let result: Result<(), &str> = Err("");
let _ = result.consume_with_warn(|_| "consumed with warn");

assert!(logs_contain("consumed with warn"));
}

#[test]
fn test_consume_as_error() {
clear_logs();
Expand Down

0 comments on commit 4bc6836

Please sign in to comment.