Skip to content

Commit

Permalink
Merge pull request #17 from knox-networks/0.9.x
Browse files Browse the repository at this point in the history
* Renamed `Reportable` to `ThinContext`, the ZST value is now an associated type:
https://github.com/knox-networks/bigerror/blob/cda942ed9ac62fa0a02f9c1fcf4de0d7227b7b78/bigerror/src/lib.rs#L32-L36

* Added `bigerror-derive` to allow deriving `ThinContext`:
  https://github.com/knox-networks/bigerror/blob/cda942ed9ac62fa0a02f9c1fcf4de0d7227b7b78/bigerror/src/context.rs#L105-L107
  Note: `#[bigerror(crate)]` is only needed inside the `bigerror` crate, normal impls will use it like so:
  ```rust
  #[derive(ThinContext)]
  pub struct MyError;
  ```
* Renamed `ThinContext::with_*`  to use `ThinContext::attach_*`: cda942e

* Removed old `reportable`, `from_report`, and `to_report` macros
  • Loading branch information
mkatychev authored Oct 15, 2024
2 parents f9ba001 + face767 commit d5bffbf
Show file tree
Hide file tree
Showing 9 changed files with 330 additions and 407 deletions.
36 changes: 20 additions & 16 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
[package]
name = "bigerror"
version = "0.8.2"
[workspace]
members = [
"bigerror", "bigerror_derive",
]
resolver = "2"

[workspace.package]
version = "0.9.0"
edition = "2021"
description = "handle big errors ¯\\_(ツ)_/¯"
license = "MIT"
documentation = "https://docs.rs/bigerror"
repository = "https://github.com/knox-networks/bigerror"

[features]
default = ["std"]
std = ["error-stack/std", "error-stack/anyhow"]
spantrace = ["error-stack/spantrace"]
eyre = ["error-stack/eyre"]
serde = ["error-stack/serde"]
hooks = ["error-stack/hooks"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
error-stack = "0.4.1"
thiserror = "1"
[workspace.dependencies]
derive_more = { version = "1", features = ["display"] }
tracing = "0.1"
proc-macro2 = "1.0.74"
quote = "1.0.35"
error-stack = "0.5"
syn = "2.0.46"
bigerror-derive = { path = "./bigerror_derive", version = "0.1.0" }

[workspace.lints.clippy]
unexpected_cfgs = "allow"
24 changes: 24 additions & 0 deletions bigerror/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "bigerror"
version.workspace = true
edition.workspace = true
description.workspace = true
license.workspace = true
documentation.workspace = true
repository.workspace = true

[features]
default = ["std"]
std = ["error-stack/std", "error-stack/anyhow"]
spantrace = ["error-stack/spantrace"]
eyre = ["error-stack/eyre"]
serde = ["error-stack/serde"]
hooks = ["error-stack/hooks"]


[dependencies]
error-stack.workspace = true
tracing.workspace = true
bigerror-derive.workspace = true
derive_more.workspace = true

40 changes: 18 additions & 22 deletions src/attachment.rs → bigerror/src/attachment.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
use std::{fmt, time::Duration};

use tracing::error;

use derive_more as dm;
pub use error_stack::{self, Context, Report, ResultExt};
pub use thiserror;

use crate::reportable;

pub trait Display: fmt::Display + fmt::Debug + Send + Sync + 'static {}

Expand All @@ -32,7 +28,7 @@ impl<A: Debug> fmt::Display for Dbg<A> {
}

// simple key-value pair attachment
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Eq)]
pub struct KeyValue<K, V>(pub K, pub V);

impl<K: fmt::Display, V: fmt::Display> fmt::Display for KeyValue<K, V> {
Expand All @@ -42,7 +38,7 @@ impl<K: fmt::Display, V: fmt::Display> fmt::Display for KeyValue<K, V> {
}

impl<K: Display, V: Debug> KeyValue<K, Dbg<V>> {
pub fn dbg(key: K, value: V) -> Self {
pub const fn dbg(key: K, value: V) -> Self {
Self(key, Dbg(value))
}
}
Expand Down Expand Up @@ -76,13 +72,13 @@ impl<Id: Display, S: Display> fmt::Display for Field<Id, S> {
}

impl<Id: Display, S: Display> Field<Id, S> {
pub fn new(key: Id, status: S) -> Self {
pub const fn new(key: Id, status: S) -> Self {
Self { id: key, status }
}
}
/// wrapper attachment that is used to refer to the type of an object
/// rather than the value
#[derive(PartialEq)]
#[derive(PartialEq, Eq)]
pub struct Type(&'static str);

impl Type {
Expand Down Expand Up @@ -116,30 +112,29 @@ macro_rules! ty {
};
}

#[derive(Debug, thiserror::Error)]
#[error("already present")]
#[derive(Debug, dm::Display)]
#[display("already present")]
pub struct AlreadyPresent;
reportable!(AlreadyPresent);

#[derive(Debug, thiserror::Error)]
#[error("missing")]
#[derive(Debug, dm::Display)]
#[display("missing")]
pub struct Missing;

#[derive(Debug, thiserror::Error)]
#[error("unsupported")]
#[derive(Debug, dm::Display)]
#[display("unsupported")]
pub struct Unsupported;

#[derive(Debug, thiserror::Error)]
#[error("invalid")]
#[derive(Debug, dm::Display)]
#[display("invalid")]
pub struct Invalid;

#[derive(Debug, thiserror::Error)]
#[derive(Debug)]
pub struct Expectation<E, A> {
pub expected: E,
pub actual: A,
}

#[derive(Debug, thiserror::Error)]
#[derive(Debug)]
pub struct FromTo<F, T>(pub F, pub T);

#[allow(dead_code)]
Expand Down Expand Up @@ -243,6 +238,7 @@ pub fn hms_string(duration: Duration) -> String {
hms
}

#[must_use]
pub fn simple_type_name<T: ?Sized>() -> &'static str {
let full_type = std::any::type_name::<T>();
// Option<T>, [T], Vec<T>
Expand All @@ -256,8 +252,8 @@ pub fn simple_type_name<T: ?Sized>() -> &'static str {
// that the underlying `A` is being
// used as an index key for getter methods in a collection
// such as `HashMap` keys and `Vec` indices
#[derive(Debug, thiserror::Error)]
#[error("idx [{0}: {}]", simple_type_name::<I>())]
#[derive(Debug, dm::Display)]
#[display("idx [{0}: {}]", simple_type_name::<I>())]
pub struct Index<I: fmt::Display>(pub I);

#[cfg(test)]
Expand Down
121 changes: 46 additions & 75 deletions src/context.rs → bigerror/src/context.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,21 @@
use derive_more as dm;
use std::{path::Path, time::Duration};

use error_stack::Context;

use crate::{
attachment::{self, simple_type_name, Display, FromTo, Unsupported},
ty, AttachExt, Index, Report, Reportable,
ty, AttachExt, Index, Report, ThinContext,
};

use crate::{attachment::DisplayDuration, reportable, Field};
use crate::{attachment::DisplayDuration, Field};

/// Used to enacpsulate opaque `dyn std::error::Error` types
#[derive(Debug, thiserror::Error)]
#[error("{0}")]
pub struct BoxError(Box<dyn std::error::Error + 'static + Send + Sync>);
/// Used to enacpsulate opaque `dyn core::error::Error` types
#[derive(Debug, dm::Display)]
#[display("{_0}")]
pub struct BoxError(Box<dyn core::error::Error + 'static + Send + Sync>);
impl ::core::error::Error for BoxError {}

/// this is a [`BoxError`] that satistifes [`core::error::Error`]
/// using [`core::fmt::Debug`] and [`core::fmt::Display`]
#[derive(Debug, thiserror::Error)]
#[error("{0}")]
pub struct BoxCoreError(Box<dyn CoreError>);
#[derive(Debug, thiserror::Error)]
#[error("DecodeError")]
/// Represents errors emitted during while processing bytes into an object.
/// * byte types can can be represented by objects such as `&[u8]`, `bytes::Bytes`, and `Vec<u8>`
/// * used by codecs/serializers/deserializers
Expand All @@ -30,99 +25,86 @@ pub struct BoxCoreError(Box<dyn CoreError>);
/// * <https://docs.rs/tonic/latest/tonic/codec/trait.Encoder.html>
/// * <https://docs.rs/rkyv/latest/rkyv/ser/serializers/type.AllocSerializer.html>
/// * <https://docs.rs/serde/latest/serde/trait.Serializer.html>
#[derive(ThinContext)]
#[bigerror(crate)]
pub struct DecodeError;
reportable!(DecodeError);

/// Emitted while turning an object into bytes.
/// See [`DecodeError`] for more details.
#[derive(Debug, thiserror::Error)]
#[error("EncodeError")]
#[derive(ThinContext)]
#[bigerror(crate)]
pub struct EncodeError;
reportable!(EncodeError);

/// Emitted during an authorization/verification check
#[derive(Debug, thiserror::Error)]
#[error("AuthError")]
#[derive(ThinContext)]
#[bigerror(crate)]
pub struct AuthError;
reportable!(AuthError);

#[derive(Debug, thiserror::Error)]
#[error("NetworkError")]
#[derive(ThinContext)]
#[bigerror(crate)]
pub struct NetworkError;
reportable!(NetworkError);

/// Emitted while processing a string (UTF-8 or otherwise).
/// Usually associated with the [`std::str::FromStr`] trait and the `.parse::<SomeT>()` method
#[derive(Debug, thiserror::Error)]
#[error("ParseError")]
#[derive(ThinContext)]
#[bigerror(crate)]
pub struct ParseError;
reportable!(ParseError);

/// Represents the conversion of an `Option::<T>::None` into a [`Report`]
#[derive(Debug, thiserror::Error)]
#[error("NotFound")]
#[derive(ThinContext)]
#[bigerror(crate)]
pub struct NotFound;
reportable!(NotFound);

#[derive(Debug, thiserror::Error)]
#[error("DbError")]
#[derive(ThinContext)]
#[bigerror(crate)]
pub struct DbError;
reportable!(DbError);

/// An error that is related to filesystem operations such as those in [`std::fs`]
#[derive(Debug, thiserror::Error)]
#[error("FsError")]
#[derive(ThinContext)]
#[bigerror(crate)]
pub struct FsError;
reportable!(FsError);

/// Emitted during the startup/provisioning phase of a program
#[derive(Debug, thiserror::Error)]
#[error("SetupError")]
#[derive(ThinContext)]
#[bigerror(crate)]
pub struct SetupError;
reportable!(SetupError);

/// Emitted during transformations between [non scalar](https://en.wikipedia.org/w/index.php?title=Scalar_processor&useskin=vector#Scalar_data_type)
/// objects (such as structs, enums, and unions).
#[derive(Debug, thiserror::Error)]
#[error("ConversionError")]
#[derive(ThinContext)]
#[bigerror(crate)]
pub struct ConversionError;
reportable!(ConversionError);

#[derive(Debug, thiserror::Error)]
#[error("InvalidInput")]
#[derive(ThinContext)]
#[bigerror(crate)]
pub struct InvalidInput;
reportable!(InvalidInput);

#[derive(Debug, thiserror::Error)]
#[error("InvalidStatus")]
#[derive(ThinContext)]
#[bigerror(crate)]
pub struct InvalidStatus;
reportable!(InvalidStatus);

#[derive(Debug, thiserror::Error)]
#[error("InvalidState")]
#[derive(ThinContext)]
#[bigerror(crate)]
pub struct InvalidState;
reportable!(InvalidState);

/// Emitted during runtime, indicates problems with input/default settings
#[derive(Debug, thiserror::Error)]
#[error("ConfigError")]
#[derive(ThinContext)]
#[bigerror(crate)]
pub struct ConfigError;
reportable!(ConfigError);

/// Typically emitted by a `build.rs` failure
#[derive(Debug, thiserror::Error)]
#[error("BuildError")]
#[derive(ThinContext)]
#[bigerror(crate)]
pub struct BuildError;
reportable!(BuildError);

#[derive(Debug, thiserror::Error)]
#[error("{}", Field::new("timeout", DisplayDuration(*.0)))]
#[derive(Debug, dm::Display)]
#[display("{}", Field::new("timeout", DisplayDuration(self.0)))]
pub struct Timeout(pub Duration);
impl ::core::error::Error for Timeout {}

#[derive(Debug, thiserror::Error)]
#[error("AssertionError")]
#[derive(ThinContext)]
#[bigerror(crate)]
pub struct AssertionError;
reportable!(AssertionError);

pub trait CoreError: core::fmt::Debug + core::fmt::Display + Send + Sync + 'static {}

Expand All @@ -132,24 +114,13 @@ impl BoxError {
#[track_caller]
pub fn new<E>(err: E) -> Report<Self>
where
E: std::error::Error + 'static + Send + Sync,
E: core::error::Error + 'static + Send + Sync,
{
Report::new(Self(Box::new(err)))
}

#[track_caller]
pub fn from(err: Box<dyn std::error::Error + 'static + Send + Sync>) -> Report<Self> {
Report::new(Self(err))
}
}
impl BoxCoreError {
#[track_caller]
pub fn new<E: CoreError>(err: E) -> Report<Self> {
Report::new(Self(Box::new(err)))
}

#[track_caller]
pub fn from(err: Box<dyn CoreError>) -> Report<Self> {
pub fn from(err: Box<dyn core::error::Error + 'static + Send + Sync>) -> Report<Self> {
Report::new(Self(err))
}
}
Expand Down Expand Up @@ -191,7 +162,7 @@ impl NotFound {
}

pub fn with_index<T, K: Display>(key: K) -> Report<Self> {
Self::with_kv(Index(key), ty!(T))
Self::attach_kv(Index(key), ty!(T))
}
}

Expand Down
Loading

0 comments on commit d5bffbf

Please sign in to comment.