Skip to content

Commit

Permalink
Merge pull request #24 from mcmah309/err_trail
Browse files Browse the repository at this point in the history
Err_trail
  • Loading branch information
mcmah309 authored Dec 23, 2024
2 parents 2ffec06 + e89549b commit a39afb0
Show file tree
Hide file tree
Showing 38 changed files with 872 additions and 52 deletions.
20 changes: 12 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,15 @@ jobs:
toolchain: stable
profile: minimal
override: true
- name: Build
run: cargo build --verbose
- name: Run std tests
run: cargo test --verbose --tests
- name: Run no_std tests
run: rustup target add x86_64-unknown-linux-gnu && cd test_no_std && cargo run
- name: Run feature flags tests
run: cargo test --tests --features tracing && cargo test --tests --features log
- name: Build error_set
run: cd error_set && cargo build --verbose
- name: Build err_trail
run: cd err_trail && cargo build --verbose
- name: Run std tests error_set
run: cd error_set && cargo test --verbose --tests
- name: Run error_set no_std tests
run: rustup target add x86_64-unknown-linux-gnu && cd error_set/test_no_std && cargo run
- name: Run error_set feature flags tests
run: cd error_set && cargo test --tests --features tracing && cargo test --tests --features log
- name: Run err_trail feature flags tests
run: cd err_trail && cargo test --tests --features tracing && cargo test --tests --features log
44 changes: 1 addition & 43 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,44 +1,2 @@
[package]
name = "error_set"
description = "An error set macro that simplifies error management by providing a streamlined method for defining errors and easily converting between them. Inspired by Zig's error set type."
categories = ["rust-patterns", "no-std"]
keywords = ["error", "error-handling", "macro", "error-set"]
version = "0.8.3"
edition = "2021"
license = "Apache-2.0"
documentation = "https://docs.rs/error_set"
repository = "https://github.com/mcmah309/error_set"
rust-version = "1.81"

[dependencies]
error_set_impl = { version = "=0.8.3", path = "impl" }

# features
tracing = { version = "0.1", optional = true }
log = { version = "0.4", optional = true }
defmt = { version = "0.3", optional = true }

[dev-dependencies]
trybuild = "^1.0.91"
tracing-test = { version = "0.2", features = ["no-env-filter"] }
lazy_static = "1"

[workspace]
members = ["impl", "test_no_std"]


[features]
default = []
# Enables support for the tracing crate. Adds methods to `Result` that are applied on `Err` - e.g. `result.warn(...)`.
tracing = ["dep:tracing"]
# Enables support for the log crate. Adds methods to `Result` that are applied on `Err` - e.g. `result.warn(...)`.
log = ["dep:log"]
# Enables support for the defmt crate, which works with no_std. Adds methods to `Result` that are applied on `Err` - e.g. `result.warn(...)`.
defmt = ["dep:defmt"]
# Enables support for the log/tracing/defmt api, without pulling in any crates. Allowing a downstream to choose the appropriate crate.
context_stub = []

[package.metadata.docs.rs]
all-features = false
features = ["tracing"]
rustdoc-args = ["--cfg", "docsrs"]
members = ["error_set", "error_set_impl", "error_set/test_no_std", "err_trail"]
28 changes: 28 additions & 0 deletions err_trail/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[package]
name = "err_trail"
description = "Add context to errors through logging"
version = "0.8.3"
edition = "2021"
license = "Apache-2.0"
documentation = "https://docs.rs/err_trail"
repository = "https://github.com/mcmah309/error_set"

[dependencies]
tracing = { version = "0.1", optional = true }
log = { version = "0.4", optional = true }
defmt = { version = "0.3", optional = true }

[dev-dependencies]
tracing-test = { version = "0.2", features = ["no-env-filter"] }
lazy_static = "1"

[features]
default = ["stub"]
# Enables support for the tracing crate. Adds methods to `Result` that are applied on `Err` - e.g. `result.warn(...)`.
tracing = ["dep:tracing"]
# Enables support for the log crate. Adds methods to `Result` that are applied on `Err` - e.g. `result.warn(...)`.
log = ["dep:log"]
# Enables support for the defmt crate, which works with no_std. Adds methods to `Result` that are applied on `Err` - e.g. `result.warn(...)`.
defmt = ["dep:defmt"]
# Enables support for the log/tracing/defmt api, without pulling in any crates. Allowing a downstream to choose the appropriate crate.
stub = []
File renamed without changes.
142 changes: 142 additions & 0 deletions err_trail/src/defmt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#![allow(unused_variables)]

use defmt::Format;

mod sealed {
pub trait Sealed {}
}

/// For logging a [Result] when [Err] is encountered.
#[cfg_attr(docsrs, doc(cfg(feature = "defmt")))]
pub trait ErrContextDefmt<T, E>: sealed::Sealed {
/// If [Err], log context as "error".
fn error_context(self, context: impl Format) -> Result<T, E>;
/// If [Err], log context as "warn".
fn warn_context(self, context: impl Format) -> Result<T, E>;

/// If [Err], lazily log result of [f] as "error".
fn with_error_context<F: FnOnce(&E) -> D, D: Format>(self, f: F) -> Result<T, E>;
/// If [Err], lazily log result of [f] as "warn".
fn with_warn_context<F: FnOnce(&E) -> D, D: Format>(self, f: F) -> Result<T, E>;
}

/// For consuming a [Result]'s [Err] in [Format] when [Err] is encountered.
#[cfg_attr(docsrs, doc(cfg(feature = "defmt")))]
pub trait ErrContextConsumeDefmt<T, E: Format>: sealed::Sealed {
/// Consume [Err] of a [Result]. Log as "error".
fn consume_as_error(self) -> Option<T>;
/// Consume [Err] of a [Result]. Log as "warn".
fn consume_as_warn(self) -> Option<T>;
}

/// For logging an [Option] when [None] is encountered.
#[cfg_attr(docsrs, doc(cfg(feature = "defmt")))]
pub trait NoneContextDefmt<T>: sealed::Sealed {
/// If [None], log context as "error".
fn error_context(self, context: impl Format) -> Option<T>;
/// If [None], log context as "warn".
fn warn_context(self, context: impl Format) -> Option<T>;

/// If [None], lazily log result of [f] as "error".
fn with_error_context<F: FnOnce() -> D, D: Format>(self, f: F) -> Option<T>;
/// If [None], lazily log result of [f] as "warn".
fn with_warn_context<F: FnOnce() -> D, D: Format>(self, f: F) -> Option<T>;
}

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

impl<T, E> sealed::Sealed for Result<T, E> {}
impl<T, E> ErrContextDefmt<T, E> for Result<T, E> {
#[inline]
fn error_context(self, context: impl Format) -> Result<T, E> {
if self.is_err() {
defmt::error!("{}", context);
}
self
}

#[inline]
fn warn_context(self, context: impl Format) -> Result<T, E> {
if self.is_err() {
defmt::warn!("{}", context);
}
self
}

#[inline]
fn with_error_context<F: FnOnce(&E) -> D, D: Format>(self, f: F) -> Result<T, E> {
if let Err(err) = &self {
defmt::error!("{}", f(err));
}
self
}

#[inline]
fn with_warn_context<F: FnOnce(&E) -> D, D: Format>(self, f: F) -> Result<T, E> {
if let Err(err) = &self {
defmt::warn!("{}", f(err));
}
self
}
}

impl<T, E: Format> ErrContextConsumeDefmt<T, E> for Result<T, E> {
#[inline]
fn consume_as_error(self) -> Option<T> {
match self {
Ok(ok) => Some(ok),
Err(err) => {
defmt::error!("{}", err);
None
}
}
}

#[inline]
fn consume_as_warn(self) -> Option<T> {
match self {
Ok(ok) => Some(ok),
Err(err) => {
defmt::warn!("{}", err);
None
}
}
}
}

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

impl<T> sealed::Sealed for Option<T> {}
impl<T> NoneContextDefmt<T> for Option<T> {
#[inline]
fn error_context(self, context: impl Format) -> Option<T> {
if self.is_none() {
defmt::error!("{}", context);
}
self
}

#[inline]
fn warn_context(self, context: impl Format) -> Option<T> {
if self.is_none() {
defmt::warn!("{}", context);
}
self
}

#[inline]
fn with_error_context<F: FnOnce() -> D, D: Format>(self, f: F) -> Option<T> {
if self.is_none() {
defmt::error!("{}", f());
}
self
}

#[inline]
fn with_warn_context<F: FnOnce() -> D, D: Format>(self, f: F) -> Option<T> {
if self.is_none() {
defmt::warn!("{}", f());
}
self
}
}
11 changes: 11 additions & 0 deletions err_trail/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#![cfg_attr(not(any(test, feature = "tracing", feature = "log")), no_std)]

#[cfg(any(feature = "tracing", feature = "log", feature = "stub"))]
mod tracing_log_stub;
#[cfg(any(feature = "tracing", feature = "log", feature = "stub"))]
pub use tracing_log_stub::*;

#[cfg(feature = "defmt")]
mod defmt;
#[cfg(feature = "defmt")]
pub use defmt::*;
Loading

0 comments on commit a39afb0

Please sign in to comment.