#error #automatic #enums #macro #err #mac #io-error

err_mac

A simple no dependency macro for creating error enums with automatic From implementations

1 unstable release

0.1.0 Feb 6, 2025

#578 in Rust patterns

Download history 138/week @ 2025-02-04 9/week @ 2025-02-11

147 downloads per month

MIT license

7KB

err_mac

A simple no dependency macro for creating error enums with automatic From implementations.

Features

  • Automatically implements From traits for wrapped error types
  • Supports both unit variants and struct variants
  • Implements std::fmt::Display using the Debug implementation
  • Works seamlessly with the ? operator for error propagation

Installation

Add this to your Cargo.toml:

[dependencies]
err_mac = "0.1.0"

Usage

The macro create_err_with_impls! takes:

  1. Optional attributes for the enum (e.g., #[derive(Debug)])
  2. Visibility modifier and enum name
  3. A list of unit variants, optionally with wrapped types
  4. A semicolon (;)
  5. A list of struct variants with named fields

Basic Example

use err_mac::create_err_with_impls;

// Define errors that our application might wrap
#[derive(Debug)]
struct DatabaseError;

#[derive(Debug)]
struct ValidationError;

// Create our error enum
create_err_with_impls!(
    #[derive(Debug)]
    pub AppError,
    // Unit variants without wrapped types
    InvalidInput,
    NotFound,
    // Variants with wrapped error types
    Database(DatabaseError),
    Validation(ValidationError),
    Io(std::io::Error),
    // Struct variants after the semicolon
    ;
    InvalidRange {
        min: i32,
        max: i32
    }
);

// The macro enables ergonomic error handling with '?'
fn do_something() -> Result<(), AppError> {
    // These will automatically convert using the generated From impls
    save_to_database()?; // Returns Result<(), DatabaseError>
    validate_input()?;   // Returns Result<(), ValidationError>

    // You can also construct errors directly
    if something_wrong {
        return Err(AppError::InvalidRange { min: 0, max: 100 });
    }
    Ok(())
}

Generated Code

For the example above, the macro generates:

#[derive(Debug)]
pub enum AppError {
    InvalidInput,
    NotFound,
    Database(DatabaseError),
    Validation(ValidationError),
    Io(std::io::Error),
    InvalidRange { min: i32, max: i32 },
}

// Automatic From implementations for wrapped types
impl From<DatabaseError> for AppError {
    fn from(v: DatabaseError) -> Self {
        Self::Database(v)
    }
}

impl From<ValidationError> for AppError {
    fn from(v: ValidationError) -> Self {
        Self::Validation(v)
    }
}

impl From<std::io::Error> for AppError {
    fn from(v: std::io::Error) -> Self {
        Self::Io(v)
    }
}

// Display implementation
impl std::fmt::Display for AppError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{:?}", self)
    }
}

No runtime deps