MDCKAPJFOWFR5HBN3CU6ZGKYXP3QND5H5IV53ZKT34HPTR3YAEDAC
KINDNEPN54H5ZHTPYMT7QX7JJEJ6TVQAK4O5YIFZWPKZH3D7455QC
S3AZSHGCYIPPQLNJBYKHCQWFPKRHRE2VTAWKVAL3AOLNJZHQARRQC
LNM226ITXRMWOSX6GOJ4HO72BWFRBDKQTEZMF4QUJUACUIOKIEJQC
EKYR4HDT6DHI7H5YMSHEBHXLPDCA2X2XNXYHDKHWGMPHNVTUBCMQC
GFUITBG5JGUCDMG34FEMPPJAZGQKURXA5L2RYS6YOQC4DIQGASMAC
DBYTNFJIVBGNURGIPWS3NJBI4XPF6IU6NY2BLBTJCECYVCGBWSNAC
MCPTFJMN333Z2GVL5J2KPLR6BJ3TAZKUGFORXNZ4YZBRXVQLCMFQC
EBCOKP4HQSTNUXR5PJQUWTOQEE3DGB6W3KKIN5TYP4FPWAS5ORHQC
TXHTORSMXMKDSGFNFIKQZYIY3KBDKJF2DJPA55NW4R6ZYBCQKRVQC
YTH3GCSKUG34XBAAVP65UA67C26K2JDDL2N6PGYLKL2GG3MGFU6AC
OQCFKTKCBTWGXL27ZLWQSL4L5VPREJAYN7MVCCR4GXW6WLWYOUHAC
YWW5TKMSPEGRZ52FQZ3SC4C3DEZ57U5XUO4LHZC34BJA7QR5NSCQC
OFA7R4NFSICEFZE2SLDK7IP3ZZH4MFWN2YIT756ZJ42W2QJHTOWQC
FJ7MWHMLIDTBGJJNKCNS5GIBQIJBUQRXLQEAFOCVZI7O4NA4XGSAC
6BNRWGF55J5M3YBWYNTWJCRJQSEHY7YRKOUBV43W7I2HCTFDJHUQC
GOPJFSDQLXOY7EGBNR26HON32UIMSC3IAWZZL57A277CMX2D4OOAC
2XZLORI35AOKD4YITN2XAVXDXZXRNUKNXJXPA2TTBAXYYLJB77GAC
GYNLSVK3MDYAOAKNOUXTC27IRIDEOUVSOEEG5LZ2PS3T4DEL6DQAC
KB6THMJJPQ56OLYYODIM5IVEF3IAPCAEC2HGH3C7LAEF24IW6XQQC
STVQHBZPF2AV3H5PVVSZZSP47R6OA3IDTN66VSGE3Z5DWS3U43IAC
XSZOCE4S65Y6NK5JBKQPDW4HEP5EAXYJPPFKJ6OJU32KNEAXGNHQC
WUKQQ2HKS3KGG4LBEMGX7SLQISJ3PSFCEKQNWNGJICQSALMSKD7AC
ZDN7BJ3JA3VL4AYWX3SV24GHP6NCAETJVAKAXKMIZTLHTWLUNMOQC
DI5NRQZB4J4AARWOX7L4NXCPNLPOTXFZTMTQZRVY2HNK62GVL5ZQC
CMUTTQVULRL5WISGIGHMKGLCKUG3YJRJCBIBNU7SMEJQXFQBAHWAC
XPE6XANXV2TTPCF7BO5RNYGAZVHA3OKDFETBOWVGG7TVRCLRKAEQC
FJF2WKUK6PNGAEJM5OGC2YHZVJLURWJ7TKVTOKC3XWSBO54QNIBAC
SEI4JZIPV4FTRNGOAMKREFHPTMLLLQCG6J7DQ3L7CM3GSZOC7IFAC
FD4FBI3AW3LE74XTQL5WTZ52KYXIYATW23YCPXV5QSJAUWTAY2XAC
ZKAEZKAMMQWPQIV6X2CFQUUOG7RBJOE3MNXLBH4J3ZASUYTCZJAQC
CITEDKPB6MKVZUEYEDE5ZKTNVY35HCOAXKDPYG7YLLEOVFNMSRXQC
UC2L4AE6COAZGVMLTIV4INSNKRT2RGCEE6IRLOBKCBJZ3IV7GCRAC
ZWBKKVT5TX2CSMBVEYZMQ6DLCXVHSD7SWFEKXWK6XKD6RP24MJJAC
6ZEY2NWHKGME25ZSTH6OYNG75JIOJECLVGY3KF4FIWSQBAVFRDAQC
GZZOJ7ZUSBPI3HXIV5UCFNMCDAMZPPLISY2UDV73FDN74HZ3AWJAC
X4XC4Q2MJC6Q45SOWNGIG2PWZFE4AG5E3M5ZW3OGV6ABUVC2XNGQC
EXRAFG37562NH775A4LDPP5FNKXLPLIZSJ3FCOBINUDKRFBJHCXAC
KOSCTMZC6VWQ5WST25FPATUAFCYG3JZGG3LF6MXSS42GPGHLDREQC
KVTZ5BUW7V7RZ3STMQXF6LXVLMGRXDBEOPRBTHX2O4HELTQ2467QC
3ZZ75E2AOF7DO3TMR422QV7ZXNYOQZTOGF67LVSCEMX6N75Y36LAC
W655S25G7CGI4XOZ2PKITKTH26VJ4QMZFRV2RPYNI4KIUJOIGVMAC
HHQUHNVMK5HPDJJ53MBD4IE2TDC3BMQOARPHRQAOO43AWG2LNMOAC
UPPVYBGC7MQBUCAAB6KW3R5KWHGASFTTXVUHEWRNP27SK3CI7UHQC
TOXJRHV7ZUPHWXCA4TAG3YRBTIPUZQ5BNX34D3VD2JAIYLRN6XSAC
RFSCYZWH7VQUGHAM374YUDGZGM5S4KT6NXWDMHXL4767SCRSL2DQC
A2YH3UCN3AEAXWW7IHTJBBQY4XRBSV2TBOX3N47ZZGKE6L7P7L5AC
A7XDW47SJ3ZYWRH64PLNI77XZTVX5FY6NX2LMT33L6BMUH3DYBMQC
NPOFDGQF4CE72IZBT5Y7KPIBHWPPNOEPBYD5RTUHSVUJ2W4XFRVQC
BA4YE6QGRTYONATHUP347OFUBUCWXQPNZ6Q5DIQ2DLJLRZJ6AC4AC
V2LGTLIQHXMNYYKNNHAOYFLM6S3IU3CSGJLDJBIKMF5UU32DZWVAC
DI4CW2M46SOKHZXATOP6HRLZB3A33FCWRFDQBIJHJY2BEDB537NQC
77T3TBBG5VN2Q4AUXHQVZTIFOSXDGTHW72J4MLX4P7LMYQURYZJAC
3LI5FAF5ULXOWBMTG4XCUOMUPVROSFDY6FWGE574OH4JGPMOPNVAC
T64LKJ2RTUDFYSJQI7KF4WHZYXZHNEGNOS7ZMMCRIQZ4YN5LOOMAC
CZP5PD5NYLDULLW43VOL6V75CH6DDEJO7H6JSGQSIV2WNSQF4A6QC
3XYTXGZS3CZ6H2DK6AQOLXN3BJM7N4RWRPQFQO67JMRWRJG6FHWQC
Z4YYQXEE4OQPF22I4LD7RVQIBKK67AHCYR6C35MANUCIC4P3EPYQC
W5YRNIBZIMTQLOKIBWBF7CHCIOLKXVHV7Y2AIKMKG7GCQSAVZKBAC
RIKD63GT7RFV3UAV4BYD57GFXKXALWUP6J7AAHB3M6JVAZ3WFTXAC
VWTWVVRECX62JABUZYFCTCPWTXXT3DB4635RIAGCKIQMGJ7VXRGAC
ZEYYSYM7QBZG4Q67AN3CHYZQWO2DVVHXRAK6NX44UQD6VO3JTK3AC
LR3QQRO4ZFYYIY4JJ7LJIO4VUK3EWESPIAPLPPIP4W7N75PSVQHQC
DFDCD3LPJCYCNINXBXGFAYD4CT2SBI4RBITE7OK5D5QPTIWWMQKAC
KCOCFOS6KMCTVS6K3WE6KOQSWC3QNWN2E36ASHQPP3Z3H4BHR3NQC
YNTEYSW7NVBWQLJU45XRK7AWQR5NWFOB4UUVVQ62ERZOO2QJJGAAC
LT5DF4XJ7RZIHKUTFXAVVMGMGTEOQA3F2LWK4MGMZM6FPVZXUHBQC
DCAJEW7O2H4N3I5EXTSBH7ALLV452CORUPJT3YQXY7QXQQIFDC4AC
JDCRIWCKVBGA2FL7PEIXATYG4INEISAGC7DDY46WPVQTEUB6PBNQC
MBJSV73XEUIBF7LU6MUYQJQLCRXYY7LXD7KZZFLLOCEDOKU2EAQAC
3YMIGCYC3YUOZP5OBNSTOIJOT6ZTEDDKNMR5YCAJRD5JNBYFETYAC
UBKNLKSJOZ6RR3BVEBTW2ID4NQ6DP34Z7HC6QA3755Q6YSTYSGEAC
ZHN3HE2M5YXFA24J733T6IHQO55CXAQWQD7XIVM37AH23TWLVSQAC
V65SHVVGO6ICRY4UZGNWCBK4DOWQWKARTJYOAWMMUW3WSRVMNKWQC
ZVYDUU7PMUEFB45PVGMWBXBU3IOOEWB3GMCJ5G5QSK5DKRYZBHUQC
K57REEWVDYAN7MA7OWR5CEROK536EK5SW5SVN3MT2J653P36NYZAC
VSLQNAQBAGOJC2IV55V3W755UIPN47J4RTCCLCABRFFFUU5LT2JQC
HO72KYBN3DYN6EC2RQUW4YP3CFBSY4X3ULYLFA2HQ36S5QGTGKIQC
6XBYIKVZHCOUS5XT2T3RQPCFG7SB6V33RLSKZFXTQMPINY5BMTTQC
AIP3SFGCT25VRARONGIYW6W2VK5WW3BBL6HFEWE3WVDGVH4JBXWAC
TEYHPVS3CWEWID4TOEBXRAYAWG5Q5Y7DIVJRCXSZPOBG745PXBNAC
WJ65BKIQTRTLNUGFCDLYFBCJKWFT4Y4FIPEOQOFKDQGAYMJKIMQAC
K3KDTBCJ2D6AHLKDKSV7KTKXOXO72KZ5CXBVLCYSKDNRCJ3EGDMQC
AOQSHDBY3FLBJBFEIJQDYHGQOBECTYRN3KPWJWQMCVWDTB6L2IRQC
RF4MODRCRWKMUG26O222X3ZY3MLE6X7BYZDWEQRLVUITTWYAGNUAC
KQXMNV3RMRPSJCQVW4I2HSCFJQ6ZDRLNMJOTQI4MODB6UYA3ONQQC
7JZIPWVKXY3QA5QMTP24WPR7KKMMVXIHAQ4EGHNGCE7H4CRKROCAC
BXFHQQPRDN25MCKA4CWNQ6YJEHMMRYOVIXCKA36WE4I4B4ZIZE5AC
WLYMZDSEPWVZKL7SEBWGTTXMM5MHIVTR4TPYVCEASATV5QNLPAMAC
WJWASFHAXBNMWHEXMKR53FLXPVUFVT44F2WKSJSA57V2UOZVSOJQC
4SNDY6U7TDCVRCARTEQ7JLATJFDMUMEFV2GSLKMQJY7RFNPU5HDQC
TJQE7LZGYT5FUB6LR2GGKIV3BHXAAOP2V2SMYNLUNCZNQ4JNF5PAC
62FAY63A6J5JJOX2RHKOWKFCJ6SHAPJT67CQ4ZJ7EXCPH6QVTW5QC
QHM7TVRG4QX2IU2VW2G4GDGCE2PZ7HKRIHMF3BEBGND2BHZ5ANGQC
6KL7TFY4VYQ67TCMYG53KQV55EP6PHHN73BFVW6VSDI27CPHVY6QC
LGEY35AOE2SLV2QVSY277GADTDDS2S74ZBJY5XQIRHJJC2NQ6OKAC
TVNP3QMGLXAKM4ESJ46RO7JR5AOVQDEVHSQOAGBZMR4UPMYKDPNQC
BWTGJOX32366LU752LXMM3IBPZH5J5N4F25QY4S64AEK725OKUYAC
This crate is a fork of [`anyhow`] by @dtolnay with a support for customized
`Reports`. For more details on customization checkout the docs on
This crate is a fork of [`anyhow`] with a support for customized
error reports. For more details on customization checkout the docs on
- [`jane-eyre`]: A a report handler crate that exists purely for the pun.
Currently just re-exports `color-eyre`.
- [`jane-eyre`]: A report handler crate that exists purely for the pun.
Currently just re-exports `color-eyre`.
Use Eyre if you don't care what error type your functions return, you just
want it to be easy. This is common in application code. Use [thiserror] if you
are a library that wants to design your own dedicated error type(s) so that on
failures the caller gets exactly the information that you choose.
Use `eyre` if you don't think you'll do anything with an error other than
report it. This is common in application code. Use `thiserror` if you think
you need an error type that can be handled via match or reported. This is
common in library crates where you don't know how your users will handle
your errors.
There are two main incompatibilities that you might encounter when porting a
codebase from `anyhow` to `eyre`:
- type inference errors when using `eyre!`
- `.context` not being implemented for `Option`
#### Type Inference Errors
The type inference issue is caused by the generic parameter, which isn't
present in `anyhow::Error`. Specifically, the following works in anyhow:
```rust
use anyhow::anyhow;
// Works
let val = get_optional_val().ok_or_else(|| anyhow!("failed to get value")).unwrap_err();
```
Where as with `eyre!` this will fail due to being unable to infer the type for
the Handler parameter. The solution to this problem, should you encounter it,
is to give the compiler a hint for what type it should be resolving to, either
via your return type or a type annotation.
```rust,compile_fail
use eyre::eyre;
// Broken
let val = get_optional_val().ok_or_else(|| eyre!("failed to get value")).unwrap();
// Works
let val: Report = get_optional_val().ok_or_else(|| eyre!("failed to get value")).unwrap();
```
use backtrace::Backtrace;
use eyre::EyreHandler;
use std::error::Error;
use std::{fmt, iter};
fn main() -> eyre::Result<()> {
// Install our custom eyre report hook for constructing our custom Handlers
install().unwrap();
// construct a report with, hopefully, our custom handler!
let mut report = eyre::eyre!("hello from custom error town!");
// manually set the custom msg for this report after it has been constructed
if let Some(handler) = report.handler_mut().downcast_mut::<Handler>() {
handler.custom_msg = Some("you're the best users, you know that right???");
}
// print that shit!!
Err(report)
}
// define a handler that captures backtraces unless told not to
fn install() -> Result<(), impl Error> {
let capture_backtrace = std::env::var("RUST_BACKWARDS_TRACE")
.map(|val| val != "0")
.unwrap_or(true);
let hook = Hook { capture_backtrace };
eyre::set_hook(Box::new(move |e| Box::new(hook.make_handler(e))))
}
struct Hook {
capture_backtrace: bool,
}
impl Hook {
fn make_handler(&self, _error: &(dyn Error + 'static)) -> Handler {
let backtrace = if self.capture_backtrace {
Some(Backtrace::new())
} else {
None
};
Handler {
backtrace,
custom_msg: None,
}
}
}
struct Handler {
// custom configured backtrace capture
backtrace: Option<Backtrace>,
// customizable message payload associated with reports
custom_msg: Option<&'static str>,
}
impl EyreHandler for Handler {
fn debug(&self, error: &(dyn Error + 'static), f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
return fmt::Debug::fmt(error, f);
}
let errors = iter::successors(Some(error), |error| error.source());
for (ind, error) in errors.enumerate() {
write!(f, "\n{:>4}: {}", ind, error)?;
}
if let Some(backtrace) = self.backtrace.as_ref() {
writeln!(f, "\n\nBacktrace:\n{:?}", backtrace)?;
}
if let Some(msg) = self.custom_msg.as_ref() {
writeln!(f, "\n\n{}", msg)?;
}
Ok(())
}
}
pub trait StdError<H>
where
H: EyreHandler,
{
fn ext_report<D>(self, msg: D) -> Report<H>
pub trait StdError {
fn ext_report<D>(self, msg: D) -> Report
impl<H> StdError<H> for Report<H>
where
H: EyreHandler,
{
fn ext_report<D>(self, msg: D) -> Report<H>
impl StdError for Report {
fn ext_report<D>(self, msg: D) -> Report
impl<T, H> ContextCompat<T, H> for Option<T>
where
H: EyreHandler,
{
fn wrap_err<D>(self, msg: D) -> Result<T, Report<H>>
impl<T> ContextCompat<T> for Option<T> {
fn wrap_err<D>(self, msg: D) -> Result<T, Report>
object_drop: object_drop::<E, H>,
object_ref: object_ref::<E, H>,
#[cfg(feature = "std")]
object_mut: object_mut::<E, H>,
object_boxed: object_boxed::<E, H>,
object_downcast: object_downcast::<E, H>,
object_drop_rest: object_drop_front::<E, H>,
object_drop: object_drop::<E>,
object_ref: object_ref::<E>,
object_mut: object_mut::<E>,
object_boxed: object_boxed::<E>,
object_downcast: object_downcast::<E>,
object_drop_rest: object_drop_front::<E>,
object_drop: object_drop::<MessageError<M>, H>,
object_ref: object_ref::<MessageError<M>, H>,
#[cfg(feature = "std")]
object_mut: object_mut::<MessageError<M>, H>,
object_boxed: object_boxed::<MessageError<M>, H>,
object_downcast: object_downcast::<M, H>,
object_drop_rest: object_drop_front::<M, H>,
object_drop: object_drop::<MessageError<M>>,
object_ref: object_ref::<MessageError<M>>,
object_mut: object_mut::<MessageError<M>>,
object_boxed: object_boxed::<MessageError<M>>,
object_downcast: object_downcast::<M>,
object_drop_rest: object_drop_front::<M>,
object_drop: object_drop::<DisplayError<M>, H>,
object_ref: object_ref::<DisplayError<M>, H>,
#[cfg(feature = "std")]
object_mut: object_mut::<DisplayError<M>, H>,
object_boxed: object_boxed::<DisplayError<M>, H>,
object_downcast: object_downcast::<M, H>,
object_drop_rest: object_drop_front::<M, H>,
object_drop: object_drop::<DisplayError<M>>,
object_ref: object_ref::<DisplayError<M>>,
object_mut: object_mut::<DisplayError<M>>,
object_boxed: object_boxed::<DisplayError<M>>,
object_downcast: object_downcast::<M>,
object_drop_rest: object_drop_front::<M>,
object_drop: object_drop::<ContextError<D, E>, H>,
object_ref: object_ref::<ContextError<D, E>, H>,
#[cfg(feature = "std")]
object_mut: object_mut::<ContextError<D, E>, H>,
object_boxed: object_boxed::<ContextError<D, E>, H>,
object_downcast: context_downcast::<D, E, H>,
object_drop_rest: context_drop_rest::<D, E, H>,
object_drop: object_drop::<ContextError<D, E>>,
object_ref: object_ref::<ContextError<D, E>>,
object_mut: object_mut::<ContextError<D, E>>,
object_boxed: object_boxed::<ContextError<D, E>>,
object_downcast: context_downcast::<D, E>,
object_drop_rest: context_drop_rest::<D, E>,
object_drop: object_drop::<BoxedError, H>,
object_ref: object_ref::<BoxedError, H>,
#[cfg(feature = "std")]
object_mut: object_mut::<BoxedError, H>,
object_boxed: object_boxed::<BoxedError, H>,
object_downcast: object_downcast::<Box<dyn StdError + Send + Sync>, H>,
object_drop_rest: object_drop_front::<Box<dyn StdError + Send + Sync>, H>,
object_drop: object_drop::<BoxedError>,
object_ref: object_ref::<BoxedError>,
object_mut: object_mut::<BoxedError>,
object_boxed: object_boxed::<BoxedError>,
object_downcast: object_downcast::<Box<dyn StdError + Send + Sync>>,
object_drop_rest: object_drop_front::<Box<dyn StdError + Send + Sync>>,
object_drop: object_drop::<ContextError<D, Report<H>>, H>,
object_ref: object_ref::<ContextError<D, Report<H>>, H>,
#[cfg(feature = "std")]
object_mut: object_mut::<ContextError<D, Report<H>>, H>,
object_boxed: object_boxed::<ContextError<D, Report<H>>, H>,
object_downcast: context_chain_downcast::<D, H>,
object_drop_rest: context_chain_drop_rest::<D, H>,
object_drop: object_drop::<ContextError<D, Report>>,
object_ref: object_ref::<ContextError<D, Report>>,
object_mut: object_mut::<ContextError<D, Report>>,
object_boxed: object_boxed::<ContextError<D, Report>>,
object_downcast: context_chain_downcast::<D>,
object_drop_rest: context_chain_drop_rest::<D>,
struct ErrorVTable<H>
where
H: EyreHandler,
{
object_drop: unsafe fn(Box<ErrorImpl<(), H>>),
object_ref: unsafe fn(&ErrorImpl<(), H>) -> &(dyn StdError + Send + Sync + 'static),
#[cfg(feature = "std")]
object_mut: unsafe fn(&mut ErrorImpl<(), H>) -> &mut (dyn StdError + Send + Sync + 'static),
struct ErrorVTable {
object_drop: unsafe fn(Box<ErrorImpl<()>>),
object_ref: unsafe fn(&ErrorImpl<()>) -> &(dyn StdError + Send + Sync + 'static),
object_mut: unsafe fn(&mut ErrorImpl<()>) -> &mut (dyn StdError + Send + Sync + 'static),
object_boxed: unsafe fn(Box<ErrorImpl<(), H>>) -> Box<dyn StdError + Send + Sync + 'static>,
object_downcast: unsafe fn(&ErrorImpl<(), H>, TypeId) -> Option<NonNull<()>>,
object_drop_rest: unsafe fn(Box<ErrorImpl<(), H>>, TypeId),
object_boxed: unsafe fn(Box<ErrorImpl<()>>) -> Box<dyn StdError + Send + Sync + 'static>,
object_downcast: unsafe fn(&ErrorImpl<()>, TypeId) -> Option<NonNull<()>>,
object_drop_rest: unsafe fn(Box<ErrorImpl<()>>, TypeId),
unsafe fn object_drop<E, H>(e: Box<ErrorImpl<(), H>>)
where
H: EyreHandler,
{
unsafe fn object_drop<E>(e: Box<ErrorImpl<()>>) {
unsafe fn object_drop_front<E, H>(e: Box<ErrorImpl<(), H>>, target: TypeId)
where
H: EyreHandler,
{
unsafe fn object_drop_front<E>(e: Box<ErrorImpl<()>>, target: TypeId) {
#[cfg(feature = "std")]
unsafe fn context_downcast<D, E, H>(e: &ErrorImpl<(), H>, target: TypeId) -> Option<NonNull<()>>
unsafe fn context_downcast<D, E>(e: &ErrorImpl<()>, target: TypeId) -> Option<NonNull<()>>
pub(crate) struct ErrorImpl<E, H>
where
H: EyreHandler,
{
vtable: &'static ErrorVTable<H>,
pub(crate) handler: Option<H>,
pub(crate) struct ErrorImpl<E> {
vtable: &'static ErrorVTable,
pub(crate) handler: Option<Box<dyn EyreHandler>>,
impl<E, H> ErrorImpl<E, H>
where
H: EyreHandler,
{
fn erase(&self) -> &ErrorImpl<(), H> {
impl<E> ErrorImpl<E> {
fn erase(&self) -> &ErrorImpl<()> {
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::eyre;
use std::num::ParseIntError;
struct NonDefaultHandler;
impl EyreHandler for NonDefaultHandler {
#[allow(unused_variables)]
fn default(error: &(dyn StdError + 'static)) -> Self {
Self
}
fn debug(
&self,
_error: &(dyn StdError + 'static),
_f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
Ok(())
}
fn _parse(s: &str) -> Result<i32, ParseIntError> {
s.parse::<i32>()
}
fn _throw_error() -> Result<(), Report<NonDefaultHandler>> {
match _parse("abc") {
Ok(_) => Ok(()),
Err(e) => Err(eyre!(e).wrap_err("try parsing an actual number")),
}
}
//! This crate is a fork of [`anyhow`] by @dtolnay with a support for customized
//! `Reports`. For more details on customization checkout the docs on
//! This crate is a fork of [`anyhow`] with a support for customized
//! error reports. For more details on customization checkout the docs on
//! - [`jane-eyre`]: A a report handler crate that exists purely for the pun.
//! Currently just re-exports `color-eyre`.
//! - [`jane-eyre`]: A report handler crate that exists purely for the pun.
//! Currently just re-exports `color-eyre`.
//! Use Eyre if you don't care what error type your functions return, you just
//! want it to be easy. This is common in application code. Use [thiserror] if you
//! are a library that wants to design your own dedicated error type(s) so that on
//! failures the caller gets exactly the information that you choose.
//! Use `eyre` if you don't think you'll do anything with an error other than
//! report it. This is common in application code. Use `thiserror` if you think
//! you need an error type that can be handled via match or reported. This is
//! common in library crates where you don't know how your users will handle
//! your errors.
//! There are two main incompatibilities that you might encounter when porting a
//! codebase from `anyhow` to `eyre`:
//!
//! - type inference errors when using `eyre!`
//! - `.context` not being implemented for `Option`
//!
//! #### Type Inference Errors
//!
//! The type inference issue is caused by the generic parameter, which isn't
//! present in `anyhow::Error`. Specifically, the following works in anyhow:
//!
//! ```rust
//! # fn get_optional_val() -> Option<()> { None };
//! use anyhow::anyhow;
//!
//! // Works
//! let val = get_optional_val().ok_or_else(|| anyhow!("failed to get value")).unwrap_err();
//! ```
//!
//! Where as with `eyre!` this will fail due to being unable to infer the type for
//! the Handler parameter. The solution to this problem, should you encounter it,
//! is to give the compiler a hint for what type it should be resolving to, either
//! via your return type or a type annotation.
//!
//! ```rust,compile_fail
//! use eyre::eyre;
//!
//! # fn get_optional_val() -> Option<()> { None };
//! // Broken
//! let val = get_optional_val().ok_or_else(|| eyre!("failed to get value")).unwrap();
//!
//! // Works
//! let val: Report = get_optional_val().ok_or_else(|| eyre!("failed to get value")).unwrap();
//! ```
//!
mod alloc {
#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(not(feature = "std"))]
pub(crate) use alloc::boxed::Box;
#[cfg(feature = "std")]
pub(crate) use std::boxed::Box;
#[cfg(not(feature = "std"))]
pub(crate) use alloc::string::String;
// #[cfg(feature = "std")]
// pub(crate) use std::string::String;
}
/// to render the error and its cause chain yourself, it can be done something
/// like this:
///
/// ```
/// use eyre::{WrapErr, Result};
///
/// fn main() {
/// if let Err(err) = try_main() {
/// eprintln!("ERROR: {}", err);
/// err.chain().skip(1).for_each(|cause| eprintln!("because: {}", cause));
/// std::process::exit(1);
/// }
/// }
/// to render the error and its cause chain yourself, it can be done by defining
/// your own [`EyreHandler`] and [`hook`] to use it.
/// fn try_main() -> Result<()> {
/// # const IGNORE: &str = stringify! {
/// ...
/// # };
/// # Ok(())
/// }
/// ```
pub struct Report<H = DefaultHandler>
where
H: EyreHandler,
{
inner: ManuallyDrop<Box<ErrorImpl<(), H>>>,
/// [`EyreHandler`]: trait.EyreHandler.html
/// [`hook`]: fn.set_hook.html
pub struct Report {
inner: ManuallyDrop<Box<ErrorImpl<()>>>,
}
type ErrorHook =
Box<dyn Fn(&(dyn StdError + 'static)) -> Box<dyn EyreHandler> + Sync + Send + 'static>;
static HOOK: OnceCell<ErrorHook> = OnceCell::new();
/// Error indicating that `set_hook` was unable to install the provided ErrorHook
#[derive(Debug)]
pub struct InstallError;
impl core::fmt::Display for InstallError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("cannot install provided ErrorHook, a hook has already been installed")
}
/// In order to insert your own custom context and report format you must first
/// implement the `eyre::EyreHandler` trait.
/// To customize the format and content of error reports from `eyre` you must
/// first define a new `EyreHandler` type to capture and store the extra context
/// and to define the format of how to display the chain of errors and this
/// stored context. Once this type has been defined you must also define a global
/// hook used to construct these handlers whenever `Report`s are constructed.
/// # use eyre::Chain;
/// # use std::error::Error;
/// use indenter::indented;
/// use std::error::Error;
/// use std::{fmt, iter};
///
/// fn main() -> eyre::Result<()> {
/// // Install our custom eyre report hook for constructing our custom Handlers
/// install().unwrap();
///
/// // construct a report with, hopefully, our custom handler!
/// let mut report = eyre::eyre!("hello from custom error town!");
///
/// // manually set the custom msg for this report after it has been constructed
/// if let Some(handler) = report.handler_mut().downcast_mut::<Handler>() {
/// handler.custom_msg = Some("you're the best users, you know that right???");
/// }
///
/// // print that shit!!
/// Err(report)
/// }
///
/// // define a handler that captures backtraces unless told not to
/// fn install() -> Result<(), impl Error> {
/// let capture_backtrace = std::env::var("RUST_BACKWARDS_TRACE")
/// .map(|val| val != "0")
/// .unwrap_or(true);
///
/// let hook = Hook { capture_backtrace };
///
/// eyre::set_hook(Box::new(move |e| Box::new(hook.make_handler(e))))
/// }
///
/// struct Hook {
/// capture_backtrace: bool,
/// }
/// pub struct Handler {
/// backtrace: Backtrace,
/// impl Hook {
/// fn make_handler(&self, _error: &(dyn Error + 'static)) -> Handler {
/// let backtrace = if self.capture_backtrace {
/// Some(Backtrace::new())
/// } else {
/// None
/// };
///
/// Handler {
/// backtrace,
/// custom_msg: None,
/// }
/// }
/// }
///
/// struct Handler {
/// // custom configured backtrace capture
/// backtrace: Option<Backtrace>,
/// // customizable message payload associated with reports
/// custom_msg: Option<&'static str>,
/// // ...
/// # #[allow(unused_variables)]
/// # fn default(error: &(dyn Error + 'static)) -> Self {
/// # let backtrace = Backtrace::new();
/// # Self { backtrace }
/// # }
/// # fn debug(
/// # &self,
/// # error: &(dyn Error + 'static),
/// # f: &mut core::fmt::Formatter<'_>,
/// # ) -> core::fmt::Result {
/// # use core::fmt::Write as _;
/// # if f.alternate() {
/// # return core::fmt::Debug::fmt(error, f);
/// # }
/// # write!(f, "{}", error)?;
/// # if let Some(cause) = error.source() {
/// # write!(f, "\n\nCaused by:")?;
/// # let multiple = cause.source().is_some();
/// # for (n, error) in Chain::new(cause).enumerate() {
/// # writeln!(f)?;
/// # if multiple {
/// # write!(indented(f).ind(n), "{}", error)?;
/// # } else {
/// # write!(indented(f), "{}", error)?;
/// # }
/// # }
/// # }
/// # let backtrace = &self.backtrace;
/// # write!(f, "\n\nStack backtrace:\n{:?}", backtrace)?;
/// # Ok(())
/// # }
/// fn debug(&self, error: &(dyn Error + 'static), f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// if f.alternate() {
/// return fmt::Debug::fmt(error, f);
/// }
///
/// let errors = iter::successors(Some(error), |error| error.source());
///
/// for (ind, error) in errors.enumerate() {
/// write!(f, "\n{:>4}: {}", ind, error)?;
/// }
///
/// if let Some(backtrace) = self.backtrace.as_ref() {
/// writeln!(f, "\n\nBacktrace:\n{:?}", backtrace)?;
/// }
///
/// if let Some(msg) = self.custom_msg.as_ref() {
/// writeln!(f, "\n\n{}", msg)?;
/// }
///
/// Ok(())
/// }
pub trait EyreHandler: Sized + Send + Sync + 'static {
/// Default construct a `Handler` when constructing a `Report`.
pub fn set_hook(hook: ErrorHook) -> Result<(), InstallError> {
HOOK.set(hook).map_err(|_| InstallError)
}
fn capture_handler(error: &(dyn StdError + 'static)) -> Box<dyn EyreHandler> {
let hook = HOOK
.get_or_init(|| Box::new(DefaultHandler::default_with))
.as_ref();
hook(error)
}
impl dyn EyreHandler {
/// This method provides a reference to the error being wrapped to support conditional
/// capturing of context like `backtrace` depending on whether the source error already
/// captured one.
pub fn is<T: EyreHandler>(&self) -> bool {
// Get `TypeId` of the type this function is instantiated with.
let t = core::any::TypeId::of::<T>();
// Get `TypeId` of the type in the trait object (`self`).
let concrete = self.type_id();
// Compare both `TypeId`s on equality.
t == concrete
}
/// ```rust
/// use backtrace::Backtrace;
/// use eyre::EyreHandler;
/// # use eyre::Chain;
/// use std::error::Error;
///
/// pub struct Handler {
/// backtrace: Backtrace,
/// }
///
/// impl EyreHandler for Handler {
/// # #[allow(unused_variables)]
/// fn default(error: &(dyn Error + 'static)) -> Self {
/// let backtrace = Backtrace::new();
///
/// Self { backtrace }
/// }
///
/// // ...
/// # fn debug(
/// # &self,
/// # error: &(dyn Error + 'static),
/// # f: &mut core::fmt::Formatter<'_>,
/// # ) -> core::fmt::Result {
/// # use core::fmt::Write as _;
/// # if f.alternate() {
/// # return core::fmt::Debug::fmt(error, f);
/// # }
/// # write!(f, "{}", error)?;
/// # if let Some(cause) = error.source() {
/// # write!(f, "\n\nCaused by:")?;
/// # let multiple = cause.source().is_some();
/// # for (n, error) in Chain::new(cause).enumerate() {
/// # writeln!(f)?;
/// # if multiple {
/// # write!(indenter::indented(f).ind(n), "{}", error)?;
/// # } else {
/// # write!(indenter::indented(f), "{}", error)?;
/// # }
/// # }
/// # }
/// # let backtrace = &self.backtrace;
/// # write!(f, "\n\nStack backtrace:\n{:?}", backtrace)?;
/// # Ok(())
/// # }
/// }
/// ```
fn default(err: &(dyn StdError + 'static)) -> Self;
pub fn downcast_mut<T: EyreHandler>(&mut self) -> Option<&mut T> {
if self.is::<T>() {
unsafe { Some(&mut *(self as *mut dyn EyreHandler as *mut T)) }
} else {
None
}
}
}
#[allow(unused_variables)]
fn default(error: &(dyn StdError + 'static)) -> Self {
let backtrace = backtrace_if_absent!(error);
Self { backtrace }
}
pub trait WrapErr<T, E, H>: context::private::Sealed<H>
where
H: EyreHandler,
{
pub trait WrapErr<T, E>: context::private::Sealed {
pub trait ContextCompat<T, H>: context::private::Sealed<H>
where
H: EyreHandler,
{
pub trait ContextCompat<T>: context::private::Sealed {
| doesn't satisfy `Error: eyre::kind::TraitKind<_>`
| doesn't satisfy `Error: std::convert::Into<eyre::Report<_>>`
| doesn't satisfy `Error: eyre::kind::TraitKind`
| doesn't satisfy `Error: std::convert::Into<eyre::Report>`