custom error implementation
#![feature(backtrace)]
type Error = Box<dyn std::error::Error+Send+Sync>;
use std::backtrace::{BacktraceStatus,Backtrace};
#[derive(Debug)]
pub struct ParseError {
kind: ParseErrorKind,
backtrace: Backtrace,
}
#[derive(Debug)]
pub enum ParseErrorKind {
InsufficientBytes { required: usize, received: usize }
}
impl std::error::Error for ParseError {
fn backtrace<'a>(&'a self) -> Option<&'a Backtrace> {
Some(&self.backtrace)
}
}
impl std::fmt::Display for ParseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.kind {
ParseErrorKind::InsufficientBytes { required, received } => {
write!(f, "required {} bytes while parsing but received {}", required, received)
}
}
}
}
fn parse(src: &[u8]) -> Result<u32,ParseError> {
if src.len() < 4 {
Err(ParseError {
backtrace: Backtrace::capture(),
kind: ParseErrorKind::InsufficientBytes { required: 4, received: src.len() }
})
} else {
Ok(u32::from_be_bytes([src[0],src[1],src[2],src[3]]))
}
}
fn main() -> Result<(),Error> {
let buf = vec![1,2,3,4,5,6,7,8];
println!["# desired main() error formatting (via Display + backtrace):\n"];
if let Err(e) = parse(&buf[0..3]) {
match std::error::Error::backtrace(&e) {
Some(bt) => match bt.status() {
BacktraceStatus::Captured => eprint!["{}\n{}", e, bt],
_ => eprint!["{}", e],
},
None => eprint!["{}", e],
}
}
println!["\n"];
println!["# default main() error formatting (via Debug):\n"];
parse(&buf[0..3])?;
Ok(())
}
output without backtraces:
$ cargo run -q
# desired main() error formatting (via Display + backtrace):
required 4 bytes while parsing but received 3
# default main() error formatting (via Debug):
Error: ParseError { kind: InsufficientBytes { required: 4, received: 3 }, backtrace: <disabled> }
output with backtraces:
$ RUST_BACKTRACE=full cargo run -q
# desired main() error formatting (via Display + backtrace):
required 4 bytes while parsing but received 3
0: err::parse
at ./main.rs:35:18
1: err::main
at ./main.rs:46:19
2: core::ops::function::FnOnce::call_once
at /rustc/9d9c2c92b834c430f102ea96f65119e37320776e/library/core/src/ops/function.rs:227:5
3: std::sys_common::backtrace::__rust_begin_short_backtrace
at /rustc/9d9c2c92b834c430f102ea96f65119e37320776e/library/std/src/sys_common/backtrace.rs:125:18
4: std::rt::lang_start::{{closure}}
at /rustc/9d9c2c92b834c430f102ea96f65119e37320776e/library/std/src/rt.rs:66:18
5: core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once
at /rustc/9d9c2c92b834c430f102ea96f65119e37320776e/library/core/src/ops/function.rs:259:13
std::panicking::try::do_call
at /rustc/9d9c2c92b834c430f102ea96f65119e37320776e/library/std/src/panicking.rs:379:40
std::panicking::try
at /rustc/9d9c2c92b834c430f102ea96f65119e37320776e/library/std/src/panicking.rs:343:19
std::panic::catch_unwind
at /rustc/9d9c2c92b834c430f102ea96f65119e37320776e/library/std/src/panic.rs:431:14
std::rt::lang_start_internal
at /rustc/9d9c2c92b834c430f102ea96f65119e37320776e/library/std/src/rt.rs:51:25
6: std::rt::lang_start
at /rustc/9d9c2c92b834c430f102ea96f65119e37320776e/library/std/src/rt.rs:65:5
7: main
8: __libc_start_main
9: _start
# default main() error formatting (via Debug):
Error: ParseError { kind: InsufficientBytes { required: 4, received: 3 }, backtrace: Backtrace [{ fn: "err::parse", file: "./main.rs", line: 35 }, { fn: "err::main", file: "./main.rs", line: 57 }, { fn: "core::ops::function::FnOnce::call_once", file: "/rustc/9d9c2c92b834c430f102ea96f65119e37320776e/library/core/src/ops/function.rs", line: 227 }, { fn: "std::sys_common::backtrace::__rust_begin_short_backtrace", file: "/rustc/9d9c2c92b834c430f102ea96f65119e37320776e/library/std/src/sys_common/backtrace.rs", line: 125 }, { fn: "std::rt::lang_start::{{closure}}", file: "/rustc/9d9c2c92b834c430f102ea96f65119e37320776e/library/std/src/rt.rs", line: 66 }, { fn: "core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once", file: "/rustc/9d9c2c92b834c430f102ea96f65119e37320776e/library/core/src/ops/function.rs", line: 259 }, { fn: "std::panicking::try::do_call", file: "/rustc/9d9c2c92b834c430f102ea96f65119e37320776e/library/std/src/panicking.rs", line: 379 }, { fn: "std::panicking::try", file: "/rustc/9d9c2c92b834c430f102ea96f65119e37320776e/library/std/src/panicking.rs", line: 343 }, { fn: "std::panic::catch_unwind", file: "/rustc/9d9c2c92b834c430f102ea96f65119e37320776e/library/std/src/panic.rs", line: 431 }, { fn: "std::rt::lang_start_internal", file: "/rustc/9d9c2c92b834c430f102ea96f65119e37320776e/library/std/src/rt.rs", line: 51 }, { fn: "std::rt::lang_start", file: "/rustc/9d9c2c92b834c430f102ea96f65119e37320776e/library/std/src/rt.rs", line: 65 }, { fn: "main" }, { fn: "__libc_start_main" }, { fn: "_start" }] }