Error Tree
error-tree is a Rust procedural macro crate designed to simplify the creation and management of complex error hierarchies in Rust applications. It allows you to define nested error enums in a straightforward and declarative manner, automatically generating From implementations and other boilerplate code to facilitate error handling across multiple layers of your application.
Features
- Simplified Error Definitions: Define multiple error enums with nested relationships in a concise syntax.
- Automatic
FromImplementations: Automatically generatesFromimplementations for error conversions between different error types, even across multiple layers. - Customizable
DisplayImplementations: Use the#[display("...")]attribute to define customDisplaymessages for your error variants. - Custom
PartialEqImplementations: Control equality comparisons using the#[cmp_neq]attribute for specific variants. - Support for Common Traits: Supports deriving common traits like
CloneandPartialEq.
Installation
Add error-tree to your Cargo.toml:
[]
= "0.4.0"
Usage
Import the error_tree macro and start defining your error enums using the error_tree! macro:
use error_tree;
error_tree!
This macro will generate:
- The
MyAppErrorenum with the specified variants. - Implementations of the
Fromtrait for converting from wrapped error types toMyAppError. - A
Displayimplementation based on the#[display("...")]attributes.
Example: Defining Nested Error Enums
You can define multiple error enums and specify relationships between them. The macro will automatically generate the necessary From implementations for error conversion.
use error_tree;
use io;
error_tree!
With this setup, you can convert an io::Error directly into an OuterError:
Automatic From Implementations
The macro generates From implementations that allow seamless conversion between your error types:
// This allows:
Customizing Display Messages
Use the #[display("...")] attribute to define custom messages for your error variants:
error_tree!
Controlling PartialEq Behavior
You can derive PartialEq for your error enums and control comparison behavior for specific variants using the #[cmp_neq] attribute:
error_tree!
let error1 = NonComparableError;
let error2 = NonComparableError;
assert_ne!; // Due to #[cmp_neq], these are not equal
Advanced Usage
Complex Error Hierarchies
error-tree excels at handling complex error hierarchies. Here's an example adapted from the crate's tests:
use error_tree;
use mpsc;
;
;
;
;
error_tree!
// Usage example
In this example:
- Multiple error enums are defined, representing different components of an audio capture system.
- The macro generates
Fromimplementations, allowing errors from low-level components (likeCpalDeviceNameError) to be converted into high-level errors (PassiveAudioCaptureError) automatically. - This simplifies error handling in functions that may return errors from different layers.
Tests and Examples
The crate includes several tests demonstrating its capabilities:
- Clone Derivation Test: Ensures that enums defined with
#[derive(Clone)]properly implement theClonetrait. - PartialEq Implementation Test: Verifies that custom
PartialEqimplementations respect the#[cmp_neq]attribute. - Display Trait Implementation Test: Checks that custom
Displaymessages are formatted correctly for different variants.
Limitations
- The macro assumes that the types used in your error variants are valid Rust types that implement necessary traits like
DebugandDisplaywhere appropriate. - For custom types used in wrapped variants, ensure that they implement
Debugif you want the defaultDisplayimplementation to work correctly.
Contributing
Contributions are welcome! Please submit issues or pull requests on the GitHub repository.
License
This project is licensed under the MIT License. See the LICENSE file for details.
Feel free to reach out if you have any questions or need assistance using error-tree.
Appendix: Understanding the Macro's Generated Code
To help you understand what the error_tree! macro generates, here's an overview based on the crate's code:
Error Enums and Variants
The macro processes your error enums and their variants, supporting:
- Basic Variants: Simple variants without data.
- Wrapped Variants: Variants that wrap another error type.
- Struct Variants: Variants with named fields.
From Implementations
For each wrapped variant, the macro generates From implementations to convert from the wrapped type to the enum containing it. It also generates transitive From implementations to allow direct conversion from low-level errors to top-level errors in your hierarchy.
Example generated code:
// Transitive conversion
Display Implementations
The macro generates Display implementations for your enums, using the #[display("...")] attribute if provided. If no #[display("...")] attribute is present, it defaults to displaying the variant name.
Custom PartialEq Implementations
If you derive PartialEq and use the #[cmp_neq] attribute on specific variants, the macro generates a custom PartialEq implementation that respects this attribute.
Attribute Handling
The macro carefully processes attributes to ensure that standard attributes like #[derive(...)] are preserved and applied correctly to the generated enums.
Conclusion
error-tree simplifies error handling in Rust applications by reducing boilerplate and providing a clear, declarative way to define complex error hierarchies. By automatically generating necessary implementations, it allows you to focus on your application's logic rather than repetitive error handling code.