Erratic /ɪˈrætɪk/
This library provides Error<S = Stateless>, an error type with optional dynamic dispatch,
enabling applications to handle errors uniformly across different contexts.
Quick Start
In most cases, Error can serve as a drop-in replacement for Box<dyn Error>.
Compared to the latter, it occupies only 1 usize, making the happy path faster.
use *;
Attaching Context & Payload
When constructing an error, you can optionally attach a static context and/or a dynamic payload. If attached, the memory is merged into a single allocation when the source error is materialized. If only a context is provided, no heap allocation occurs at all.
use *;
Binding State
When propagating an error that requires special handling, you can attach a generic state to it. If the state is small enough and neither the source error, context, nor payload is attached, the state is inlined without any heap allocation.
use *;
When no runtime state is actually stored, errors can be cheaply converted between different state types.
This means infrastructure errors cross any number of layers with a single allocation, domain errors avoid
the heap entirely, and both share the same Error<S> type. All compose orthogonally.
The ? operator covers the most common cases, notably including conversion from Error to Error<S>:
impl Error->Errorimpl Error->Error<S>Error->Error<S>
Stateful errors are meant to be handled explicitly. Several utility methods are provided:
erase_error()?: Propagate the error.extract_state()?: Take the state out, or propagate the error.map_state()?: Transform the state with a closure.lift_state()?: Transform viaFrom<S>.
Backtrace
When the backtrace feature is enabled and backtrace capture is configured via
environment variables, Error<S> automatically captures a backtrace if there isn't
already one in the source chain. The backtrace will be appended after the error chain during debug
formatting, unless the minus sign, e.g. {:-?}, is specified to suppress it.
Representation
If the error contains only a source, the error message is inherited from the source. Otherwise, the error message is constructed from other attached components.
<error> ::= <source>
| <state>": "<context><payload>
| <state>": "<context>
| <state>": "<payload>
| <context><payload>
| <context>
| <payload>
| <state>
By default, only the top-level error is shown during formatting. To display the full error chain, format with alternate or debug specifiers.
{}: Displays only the top-level error.{:#}: Displays the full error chain.{:?}: Displays the full error chain with backtrace (if captured).{:#?}: Displays all information in a struct-like format.
The error chain is defined as follows:
<chain> ::= <error>
| <error>"\n -> "<chain>
Layout
Type-wise, Error<S> is an internally tagged union, and it requires pointers to be aligned to 4 bytes,
freeing up the lower 2 bits to encode its discriminant. Pointer tagging in this crate fully follows
strict provenance, and is verified by Miri.
(32-bit platform, little-endian)
(Context Only)
[......00|........|........|........]
\
`rodata-> [Context]
(Allocation Required)
[......01|........|........|........]
\
`heap-> [VTable|State|Error|Payload|Context]
(Small State Only)
[00000010| ~ State ~ ]
Contributing
Contributions are warmly welcomed! Whether you have a bug report, feature request, or an improvement in mind, feel free to open an issue or submit a pull request. All ideas—big or small—help make this library better for everyone.