Crate generic_err

Source
Expand description

§Generic Error

A simple utility to convert any error type that isn’t clonable into one that is, while preserving source information providing Serialize and Deserialize functionality. Magic?

§How it works

The GenericError<E> wrapper type just stores the Display and Debug implementations of the wrapped type, which is now always clonable and will serialize just fine. The GenericError<E> type kinda looks like this:

#[derive(Serialize, Deserialize, Clone)]
pub struct GenericError<T>
{
  display: String,
  debug: String,
  source: Option<GenericError>,
}

.. although many details have been omitted for brevity

See docs or the examples dir for usage

§Usage

use generic_err::GenericError;

#[derive(Debug, thiserror::Error)]
enum NonCloneError {
  #[error("Database is not connected")]
  DbNotConnected,
}

/// Send to DB, clone a bit
fn literally_everyday<T>(_stuff: T)
where
  T: Clone + serde::Serialize + serde::de::DeserializeOwned,
{
  todo!()
}

fn main() {
  let non_clone: Result<(), NonCloneError> = Err(NonCloneError::DbNotConnected);
  let non_clone_debug = format!("{:?}", non_clone);

  let now_cloneable: Result<(), GenericError<NonCloneError>> =
    non_clone.map_err(GenericError::from);
  let cloneable_debug = format!("{:?}", now_cloneable);

  assert_eq!(non_clone_debug, cloneable_debug);

  // See? Magic!
  literally_everyday(now_cloneable);
}

You can also use the Untyped variant of GenericError if that suits your needs better.

There are also extension traits for convenience:

use generic_err::GenericError;
use generic_err::Untyped;
use generic_err::prelude::*;

#[derive(Debug, thiserror::Error)]
enum NonCloneError {
  #[error("Database is not connected")]
  DbNotConnected,
}

/// Send to DB, clone a bit
fn literally_everyday<T>(_stuff: T)
where
  T: Clone + serde::Serialize + serde::de::DeserializeOwned,
{
  todo!()
}

fn main() {
  let non_clone: Result<(), NonCloneError> = Err(NonCloneError::DbNotConnected);
  let clonable: Result<(), GenericError<NonCloneError>> = non_clone.make_generic();

  // See? Magic!
  literally_everyday(clonable);

  let non_clonable: Result<(), NonCloneError> = Ok(());
  let clonable_untyped: Result<(), GenericError<Untyped>> = non_clonable.make_generic_untyped();

  literally_everyday(clonable_untyped);
}

Also, for types that don’t implement Debug, there are methods to suit your needs, e.g. GenericError::from_non_err.

Modules§

prelude
Only exports extension traits without polluting your namespace

Structs§

GenericError
Wrapper around any error T such that it is Clone, serde::Serialize, and serde::Deserialize by storing its initial Debug and Display representations as Strings.

Traits§

GenericErrorExt
This is an extension trait for the following impl:
GenericErrorRefExt
This is an extension trait for the following impl:

Type Aliases§

Untyped
A marker for GenericError that indicates it doesn’t have knowledge of the type it is wrapping