pub struct AnErr<K, const DEPTH: usize = 3, const REASON_LEN: usize = 29>{
pub reasons: [Option<LiteStr<REASON_LEN>>; DEPTH],
pub locations: [Option<&'static Location<'static>>; DEPTH],
pub kinds: [Option<K>; DEPTH],
pub len: u8,
}Expand description
A compact, Copy, zero-allocation error type that records a parallel stack
of error kinds, source locations, and per-level human-readable reasons.
AnErr stores up to DEPTH levels of error context. Each level contains:
- an error kind of type
K, - the source location where the level was created,
- an optional reason specific to that level (
LiteStr<REASON_LEN>).
The kind enum provides the general error category while the per-level reason carries concrete details (e.g. a bad value, file path, token, etc.).
The type implements Copy and performs no heap allocation. Default memory
footprint is small and fully controllable via the generic parameters.
§Type Parameters
K: Error kind type. Must implementCopy + Clone + Debug + PartialEq + Eq.DEPTH: Maximum number of context levels (default3). Additional context beyond this limit is silently discarded.REASON_LEN: Maximum length of each individual reason in bytes (default29). Longer reasons are silently truncated.
§Construction
use an_error::{AnErr, an_err};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MyKind {
Parse,
Io,
Validation,
}
pub type MyError = AnErr<MyKind, 4, 64>;
fn parse() -> Result<(), MyError> {
Err(an_err!(MyKind::Parse, "unexpected token at byte {}", 42))
}
fn load(path: &str) -> Result<(), MyError> {
let inner = parse()
.map_err(|e| an_err!(MyKind::Io, "while loading config from {}", path => e))?;
Ok(())
}All constructors and the context method capture the call site via #[track_caller].
§Display
The Display implementation produces output of the following form:
--
• Trace (2 levels):
1. Io @ src/io.rs:42:10 while loading config from /etc/foo
2. Parse @ src/parser.rs:17:5 unexpected token at byte 42Each trace level shows its own reason (if present) immediately after the location.
§Invariants
Maintained by all constructors and context:
lenis always in1..=DEPTH.- For every
iin0..len,kinds[i]andlocations[i]areSome. reasons[i]isSomeonly if a non-empty reason was supplied for that level.
§Accessing the stack
In addition to the top-level convenience methods (kind(), location(), reason()),
you can access any level directly or iterate the entire trace.
§Direct access
let top_kind = err.kind(); // most recent
let top_loc = err.location();
let top_reason = err.reason();
let root_kind = err.root_kind(); // original error
let root_loc = err.root_location();
let root_reason = err.root_reason();
if let Some((kind, loc, reason)) = err.get(1) {
// second level (index 0 = top, index 1 = next, ...)
}§Iterating with trace()
The most common way to walk the full stack is with trace:
for (kind, location, reason) in err.trace() {
println!("{:?} @ {}:{}", kind, location.file(), location.line());
if let Some(r) = reason {
println!(" reason: {}", r);
}
}- Iteration order is most recent → oldest (same order as
Display). - The iterator implements
ExactSizeIterator, so you can call.len(), use it inforloops, etc. - No allocation — it just borrows the
AnErr.
Fields§
§reasons: [Option<LiteStr<REASON_LEN>>; DEPTH]Per-level reasons. Only the first len entries are valid.
None means no reason (or an empty reason) was provided for that level.
locations: [Option<&'static Location<'static>>; DEPTH]Parallel stack of source locations.
Only the first len entries are valid.
kinds: [Option<K>; DEPTH]Parallel stack of error kinds (one per call-stack level).
Only the first len entries are valid.
len: u8Current depth of the error trace (1 = original error).
Implementations§
Source§impl<K, const DEPTH: usize, const REASON_LEN: usize> AnErr<K, DEPTH, REASON_LEN>
impl<K, const DEPTH: usize, const REASON_LEN: usize> AnErr<K, DEPTH, REASON_LEN>
Sourcepub fn with_reason(kind: K, reason: LiteStr<REASON_LEN>) -> Self
pub fn with_reason(kind: K, reason: LiteStr<REASON_LEN>) -> Self
Creates a new error with the given kind and reason.
If the reason is empty, it is stored as None.
Sourcepub fn with_fmt(kind: K, args: Arguments<'_>) -> Self
pub fn with_fmt(kind: K, args: Arguments<'_>) -> Self
Creates a new error with the given kind and a formatted reason.
The formatted string is truncated if it exceeds REASON_LEN bytes.
Sourcepub fn context(&mut self, kind: K, new_reason: LiteStr<REASON_LEN>)
pub fn context(&mut self, kind: K, new_reason: LiteStr<REASON_LEN>)
Appends a new context level and optional reason to this error.
If new_reason is empty, no reason is stored for the new level.
If the maximum depth is already reached, the call is a no-op.
Sourcepub fn context_fmt(&mut self, kind: K, args: Arguments<'_>)
pub fn context_fmt(&mut self, kind: K, args: Arguments<'_>)
Appends a new context level with a formatted reason.
Used internally by the an_err! macro. The formatted string is
truncated if it exceeds REASON_LEN bytes.
Sourcepub fn trace(&self) -> TraceIter<'_, K, DEPTH, REASON_LEN>
pub fn trace(&self) -> TraceIter<'_, K, DEPTH, REASON_LEN>
Returns an iterator over the error trace, from most recent context down to the original error.
Each item is (kind, location, reason). The iterator borrows self
with zero copying.
Sourcepub fn get(
&self,
index: usize,
) -> Option<(K, &'static Location<'static>, Option<&LiteStr<REASON_LEN>>)>
pub fn get( &self, index: usize, ) -> Option<(K, &'static Location<'static>, Option<&LiteStr<REASON_LEN>>)>
Returns the data for a specific level in the error trace.
index == 0 is the most recent context (top of the stack / newest context!).
index == self.depth() - 1 is the root (original) error.
Returns None if index >= self.depth().
Sourcepub fn location(&self) -> Option<&'static Location<'static>>
pub fn location(&self) -> Option<&'static Location<'static>>
Returns the source location where the most recent error/context was created.
Sourcepub fn reason(&self) -> Option<&LiteStr<REASON_LEN>>
pub fn reason(&self) -> Option<&LiteStr<REASON_LEN>>
Returns the reason (if any) attached to the most recent error/context.
Sourcepub fn root_location(&self) -> Option<&'static Location<'static>>
pub fn root_location(&self) -> Option<&'static Location<'static>>
Returns the source location of the original (root) error.
Sourcepub fn root_reason(&self) -> Option<&LiteStr<REASON_LEN>>
pub fn root_reason(&self) -> Option<&LiteStr<REASON_LEN>>
Returns the reason (if any) attached to the root error.
Source§impl<K, const DEPTH: usize, const REASON_LEN: usize> AnErr<K, DEPTH, REASON_LEN>
impl<K, const DEPTH: usize, const REASON_LEN: usize> AnErr<K, DEPTH, REASON_LEN>
Sourcepub fn to_wire_bytes<const PATH_LEN: usize>(
&self,
kind_to_u16: impl Fn(K) -> u16,
buf: &mut [u8],
) -> Result<usize, ()>
pub fn to_wire_bytes<const PATH_LEN: usize>( &self, kind_to_u16: impl Fn(K) -> u16, buf: &mut [u8], ) -> Result<usize, ()>
Serialize this error into a fixed-size byte buffer for transmission.
The caller must provide a buffer that is at least Self::WIRE_SIZE::<PATH_LEN>() bytes long.
Returns the number of bytes actually written (always the same for a given PATH_LEN).
Recommended usage:
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)] // or #[repr(u16)] for >256 variants
pub enum MyKind { ... }
let mut buf = [0u8; AnErr::<MyKind, 3, 29>::wire_size::<80>()];
let written = my_error.to_wire_bytes::<80>(|k| k as u16, &mut buf);
let packet = &buf[..written];Trait Implementations§
Source§impl<K, const DEPTH: usize, const REASON_LEN: usize> Error for AnErr<K, DEPTH, REASON_LEN>
impl<K, const DEPTH: usize, const REASON_LEN: usize> Error for AnErr<K, DEPTH, REASON_LEN>
1.30.0 · Source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
1.0.0 · Source§fn description(&self) -> &str
fn description(&self) -> &str
use the Display impl or to_string()
Source§impl<K, const DEPTH: usize, const REASON_LEN: usize> PartialEq for AnErr<K, DEPTH, REASON_LEN>
impl<K, const DEPTH: usize, const REASON_LEN: usize> PartialEq for AnErr<K, DEPTH, REASON_LEN>
impl<K, const DEPTH: usize, const REASON_LEN: usize> Copy for AnErr<K, DEPTH, REASON_LEN>
impl<K, const DEPTH: usize, const REASON_LEN: usize> Eq for AnErr<K, DEPTH, REASON_LEN>
impl<K, const DEPTH: usize, const REASON_LEN: usize> StructuralPartialEq for AnErr<K, DEPTH, REASON_LEN>
Auto Trait Implementations§
impl<K, const DEPTH: usize, const REASON_LEN: usize> Freeze for AnErr<K, DEPTH, REASON_LEN>where
K: Freeze,
impl<K, const DEPTH: usize, const REASON_LEN: usize> RefUnwindSafe for AnErr<K, DEPTH, REASON_LEN>where
K: RefUnwindSafe,
impl<K, const DEPTH: usize, const REASON_LEN: usize> Send for AnErr<K, DEPTH, REASON_LEN>where
K: Send,
impl<K, const DEPTH: usize, const REASON_LEN: usize> Sync for AnErr<K, DEPTH, REASON_LEN>where
K: Sync,
impl<K, const DEPTH: usize, const REASON_LEN: usize> Unpin for AnErr<K, DEPTH, REASON_LEN>where
K: Unpin,
impl<K, const DEPTH: usize, const REASON_LEN: usize> UnsafeUnpin for AnErr<K, DEPTH, REASON_LEN>where
K: UnsafeUnpin,
impl<K, const DEPTH: usize, const REASON_LEN: usize> UnwindSafe for AnErr<K, DEPTH, REASON_LEN>where
K: UnwindSafe,
Blanket Implementations§
Source§impl<T> AsErrorSource for Twhere
T: Error + 'static,
impl<T> AsErrorSource for Twhere
T: Error + 'static,
Source§fn as_error_source(&self) -> &(dyn Error + 'static)
fn as_error_source(&self) -> &(dyn Error + 'static)
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.