An error handling library with under 50 lines of code and no dependencies, that
keeps track of the source location of every error. ``DebugErr`` identifies the
crate name, file name and line number of every error event.
### The Basics
To build an error:
```ignore
use debug_err::{DebugErr, src};
pub fn divide(num: f32, denom: f32) -> Result<f32, DebugErr> {
if denom == 0.0 { Err(src!("Denominator must not be zero.")) }
Ok(num / denom)
}
```
### Coercing other error types to ``DebugErr``
This extracts the message from another error type
```ignore
use debug_err::{DebugErr, src};
let num: f32 = "abc".parse().map_err(|e| src!("Failed to parse with error '{e}'"))?;
```
### Coercing ``DebugErr`` to other error types.
The cleanest method is just to directly use ``DebugErr`` in your library, and
construct and return errors of this type, but if you still need to build your own
error types then,
```
use {
debug_err::{DebugErr, src},
std::fmt,
};
#[derive(Clone, Debug)]
pub struct OwnError(DebugErr);
// Uses ``DebugErr``'s ``Display`` implementation.
impl fmt::Display for OwnError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
// This is used to coerce ``DebugErr`` into one's own type using the ``?`` operator,
// so that ``DebugErr`` doesn't have to be coerced explicitly.
impl From<DebugErr> for OwnError {
fn from(debug: DebugErr) -> Self { OwnError(debug) }
}
// and then at the error construction site,
type Result<T> = std::result::Result<T, OwnError>;
pub fn divide(num: f32, denom: f32) -> Result<f32> {
if denom == 0.0 { return Err(src!("Denominator must not be zero."))? }
Ok(num / denom)
}
pub fn parse(num: &str) -> Result<f32> {
let f: f32 = num.parse().map_err(|e| src!("Failed to parse '{num}' with error: {e}"))?;
Ok(f)
}
```