dtolnay / anyhow Goto Github PK
View Code? Open in Web Editor NEWFlexible concrete Error type built on std::error::Error
License: Apache License 2.0
Flexible concrete Error type built on std::error::Error
License: Apache License 2.0
For logging errors ergonomically, it would be nice to be able to Display
a Chain
. The impl Display for Error
only formats the highest level error, so it's in many use cases just a context without the cause.
When context is present, it prints in reverse order
ERROR svd2rust: In peripheral `PLIC` <-- this is context
Caused by:
0: In cluster `targets[%s]`
1: In register `threshold`
2: Parsing field #0
3: In field `priority`
4: Expected content in <enumeratedValues> tag, found none <-- this is error
Hi! I'm new to rust, so sorry if this is a stupid question. I'm writing a single-threaded app, and I'm using a custom struct as an error with anyhow. This was working fine until I added an Rc<RefCell<Foo>>
field. After that, I got an error when I try to downcast the error to my type. Looking at the declarations, it seems all the downcast
need the downcasted type to be Send
. Since my program is single-threaded, I don't think that's needed in my case, so is there a way to downcast an error to a type which isn't thread-safe?
Thanks!
As NoneError
doesn't impl std::error::Error
at this moment in time, would it be reasonable to add a From
impl for it to anyhow::Error
in some fashion?
This example code:
use anyhow::{anyhow, Result as AResult};
fn main() -> AResult<()> {
std::thread::spawn( move || { Ok(anyhow!("test error")) }).join()??;
Ok(())
}
Errors with:
error[E0277]: the size for values of type `dyn std::any::Any + std::marker::Send` cannot be known at compilation time
--> src/main.rs:5:70
|
5 | std::thread::spawn( move || { Ok(anyhow!("test error")) }).join()??;
| ^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `dyn std::any::Any + std::marker::Send`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: required because of the requirements on the impl of `std::error::Error` for `std::boxed::Box<dyn std::any::Any + std::marker::Send>`
= note: required because of the requirements on the impl of `std::convert::From<std::boxed::Box<dyn std::any::Any + std::marker::Send>>` for `anyhow::Error`
= note: required by `std::convert::From::from`
error[E0277]: the trait bound `dyn std::any::Any + std::marker::Send: std::error::Error` is not satisfied
--> src/main.rs:5:70
|
5 | std::thread::spawn( move || { Ok(anyhow!("test error")) }).join()??;
| ^ the trait `std::error::Error` is not implemented for `dyn std::any::Any + std::marker::Send`
|
= note: required because of the requirements on the impl of `std::error::Error` for `std::boxed::Box<dyn std::any::Any + std::marker::Send>`
= note: required because of the requirements on the impl of `std::convert::From<std::boxed::Box<dyn std::any::Any + std::marker::Send>>` for `anyhow::Error`
= note: required by `std::convert::From::from`
error[E0277]: `dyn std::any::Any + std::marker::Send` cannot be shared between threads safely
--> src/main.rs:5:70
|
5 | std::thread::spawn( move || { Ok(anyhow!("test error")) }).join()??;
| ^ `dyn std::any::Any + std::marker::Send` cannot be shared between threads safely
|
= help: the trait `std::marker::Sync` is not implemented for `dyn std::any::Any + std::marker::Send`
= note: required because of the requirements on the impl of `std::marker::Sync` for `std::ptr::Unique<dyn std::any::Any + std::marker::Send>`
= note: required because it appears within the type `std::boxed::Box<dyn std::any::Any + std::marker::Send>`
= note: required because of the requirements on the impl of `std::convert::From<std::boxed::Box<dyn std::any::Any + std::marker::Send>>` for `anyhow::Error`
= note: required by `std::convert::From::from`
error: aborting due to 3 previous errors
Judging from the error messages, the reason is that the error value of std::thread::Result
doesn't implement std::error::Error
(!). Is there any suggested workarounds? I'd almost expect .map_err(|e| anyhow!(e))
to work for wrapping the error value to anyhow::Error
, but it doesn't.
Have you though about adding an ensure!
macro as well in the same vein as the one in failure?
We use failure
today and with quite a bit of ensure!
which I find makes quite compact and explicit code, and has a nice naming connection to assert!
.
Would you be open to adding ensure!
to this crate?
First, this crate is awesome. I feel like Rust's error story is starting to feel really ergonomic.
This crate looks like a very nice Error type to reach for when working with a leaf/application crate.
Have you thought about working towards adding it to std
?
anyhow::Error
could be added as std::error
( as a pseudo-primitive ) via the same hack that i32
and std::i32
are mergedstd::error
could be a very good default for various Err
, Error
, and E
type parametersstd::error
in a future edition could be added to the prelude as just error
We are looking into migrating from failure
crate to a combination of thiserror
+anyhow
. The way we have our error handling set up is that we can go through the chain of errors and "cross-cast" them into a trait object of our own (say, &dyn ExtraInfo
).
The way this is done is through a registry of "casting" functions which would cast to a specific type T: ExtraInfo
, then coerce to &dyn ExtraInfo
.
One use-case we need to support is to allow this mechanism to work with "contexts" (we might not need this use-case anymore since anyhow::Error
could be embedded as a #[source]
into structured errors). For failure
case, we do that by "registering" downcasting functions twice: once for type T
and once for Context<T>
.
However, anyhow
does not expose "context" type. On the other hand, it seems to support downcasting to type inside the "context error" directly via downcast_ref
on the &anyhow::Error
. But for some reason (I mean... given the internals of anyhow::Error
it is not surprising -- it's quite sophisticated piece of machinery!), it doesn't work when done via &dyn std::error::Error
. Test case:
#[derive(Debug, thiserror::Error, PartialEq)]
#[error("some error")]
struct SomeError(usize);
fn main() {
let error = anyhow::Error::msg("error");
let error = error.context(SomeError(123));
// Works 😅
assert_eq!(error.downcast_ref::<SomeError>().unwrap(), &SomeError(123));
let error: &dyn std::error::Error = &*error;
// Fails 😞
assert_eq!(error.downcast_ref::<SomeError>().unwrap(), &SomeError(123));
}
This is a very useful crate for prototyping, even libraries, but library authors often like to provide advanced features like getting error kind or structured context. However, in early phase of library development, these extra features might be a burden.
A nice way to resolve it is to have a newtype encapsulating anyhow::Error
, which can be changed at any time. One most likely wants to forward fmt::Debug
and fmt::Display
traits. This requires boilerplate, though.
I propose adding a newtype!($name:ident) => { pub struct $name(anyhow::Error); ... }
macro which generates such newtype and delegates the relevant traits to it. Alternatively, it could be attribute-like proc macro on unit structs, allowing to add derives and control visibility.
Adding context seems to break type inference. For example:
use anyhow::{Context, Result};
fn main() -> Result<()> {
let x = "k";
let y: u32 = x.parse().context("context")?;
println!("{}", y);
Ok(())
}
gives
error[E0284]: type annotations required: cannot resolve `<_ as std::str::FromStr>::Err == _`
--> src\main.rs:5:20
|
5 | let y: u32 = x.parse().context("context")?;
|
obviously using turbofish syntax works, like:
let y = x.parse::<u32>().context("context")?;
but it is surprising behaviour. Might be a compiler limitation but I still wanted to mention it.
We may sometimes want errors that are printed inside-out from lowest level to highest.
for e in error.chain().rev() {
println!("{}", e);
}
This may requires some buffering but that's fine, the caller would be doing it anyway in this situation.
Anyhow claims to support wrapping any implementor of std::error::Error, but error_chain's impl seems incompatible:
error[E0277]: `(dyn std::error::Error + std::marker::Send + 'static)` cannot be shared between threads safely
--> src/cli/main.rs:66:25
|
66 | utils::current_dir()?;
| ^ `(dyn std::error::Error + std::marker::Send + 'static)` cannot be shared between threads safely
|
= help: the trait `std::marker::Sync` is not implemented for `(dyn std::error::Error + std::marker::Send + 'static)`
= note: required because of the requirements on the impl of `std::marker::Sync` for `std::ptr::Unique<(dyn std::error::Error + std::marker::Send + 'static)>`
= note: required because it appears within the type `std::boxed::Box<(dyn std::error::Error + std::marker::Send + 'static)>`
= note: required because it appears within the type `std::option::Option<std::boxed::Box<(dyn std::error::Error + std::marker::Send + 'static)>>`
= note: required because it appears within the type `error_chain::State`
= note: required because it appears within the type `rustup::errors::Error`
= note: required because of the requirements on the impl of `std::convert::From<rustup::errors::Error>` for `anyhow::Error`
= note: required by `std::convert::From::from`
rust-lang-deprecated/error-chain#240 is presumably the underlying cause, but perhaps anyhow could do something on it's end via specialisation or using ?Send and ?Sync or something?
We've been using a little minimal crate for our modest error handling purposes, and one thing that turned out very useful was context_with
:
fs::read_to_string(&path).context_with("cannot open",&path)?;
which is entirely equivalent to:
fs::read_to_string(&path).with_context(|| format!("cannot open {:?}", path))?;
I am not entirely sure of the name context_with
(maybe context_debug
?) but it's certainly a nice convenience in the common case where the error needs to refer to the string, path, etc that was the source of the trouble.
As I read https://github.com/rust-lang/rfcs/blob/master/text/2504-fix-error.md and https://doc.rust-lang.org/std/backtrace/index.html RUST_BACKTRACE will also enable backtraces. Perhaps the backtrace enabling prose could either say something like 'enabled per the backtrace module' and link to it, or cover both variables : as it is, I had some cognitive dissonance when I read it and had to go grep the anyhow source to see what custom thing it was doing etc...
When printing anyhow’s Result type (e.g. on return from fn main
) the error is formatted as Error: xyz
. I was wondering if it is possible to customise this formatting. Additionally, Clap has its own error formatting it uses for argument parsing errors and the like. Is it somehow possible to make error printing consistent across Clap and anyhow, and perhaps other crates too?
Thanks.
Hi, I would like to be able to downcast on the just the topmost layer of the context stack. Looking through the API, it doesn't appear that this is possible. It's nearly possible by using the underlying std::error::Error provided downcasting, instead of the anyhow downcasting, but anyhow wraps the context in a private ContextError. Even if it were public, I still don't think it would be possible since I know the C
context type I want, but not the E
error type.
I think I can work around this in a good enough way for my usecase by comparing my_anyhow_error.downcast_ref::<MyType>().unwrap().to_string()
to my_anyhow_error.to_string()
, which gives me a pretty good indication that the first instance of MyType in the stack is the topmost context layer, but I'm curious if it might be a generally useful feature for anyhow.
Hi,
I get following errors if I try to compile anyhow 1.0.12 with rustc 1.38.0 itself compiled in dev
channel:
error[E0432]: unresolved import `std::backtrace`
--> src/backtrace.rs:2:21
|
2 | pub(crate) use std::backtrace::Backtrace;
| ^^^^^^^^^ could not find `backtrace` in `std`
error[E0432]: unresolved import `std::backtrace`
--> src/context.rs:7:10
|
7 | use std::backtrace::Backtrace;
| ^^^^^^^^^ could not find `backtrace` in `std`
strohel@edgy ~/projekty/anyhow $ rustc --version
rustc 1.38.0-dev
It seems to be caused by the fact that cargo:rustc-cfg=backtrace
is errorneously enabled in build.rs
. If I do a simple change
diff --git a/build.rs b/build.rs
index dcc19c6..65541b4 100644
--- a/build.rs
+++ b/build.rs
@@ -34,6 +34,6 @@ fn rustc_version() -> Option<Compiler> {
};
Some(Compiler {
- nightly: version.contains("nightly") || version.contains("dev"),
+ nightly: version.contains("nightly"),
})
}
then the crate compiles and tests pass (but that probably isn't the right thing to do).
Perhaps presence of std::backtrace
can be tested more directly (maybe even without build.rs
?).
Hi, I need to put a anyhow::Result
in a struct that derive the traits serde::Serialize
and serde::Desrilize
but anyhow::Error
do not implement these traits so is impossible to derive them in my struct.
There is a way around? These traits will ever be implemented?
There are a few uses of unsafe which don't indicate why it is safe to use them, when I read through the code. I can see there are a few tests written but it would be nice to see a bit of documentation about why the unsafe
parts are actually safe to use.
Lines like this make me feel a little spooked out without a comment:
Line 300 in 89df7af
Also looking at the code, I'm not sure why it's important to erase the type here (but assuming it's to deal with some compiler thing):
Line 96 in 89df7af
Might just be me not understanding, but at first walk through I don't know whether this code is safe to use or not.
See title. It's not clear to me. The documentation says:
Error requires that the error is Send, Sync, and 'static.
I can see that ;) But there is no explanation. I haven't found one in the source code either.
In a different issue where the suggestions was made that
anyhow could do something on it's end via specialisation or using ?Send and ?Sync or something
The response was:
I would prefer not to make a change for this
Again, no explanation. May I ask why this requirement exists?
I am asking because I am dealing with an error type that -- legitimately, in my opinion -- has a variant that contains a PoisonError
which in turn wraps a MutexGuard
. The latter does not implement Send
, rendering anyhow
useless with those error types, from what I can tell.
Hi,
I'm trying to figure out a way of asserting a specific error (with a specific message) in a unit test.
Is there a recommended/idiomatic way of writing such a test.
Thanks
Brad
So I'm using actix-web 2 and would like to do something like this:
use anyhow::Result;
#[actix_rt::main]
async fn main() -> Result<()> {
HttpServer::new(|| App::new().bind("0.0.0.0:8080"))?.run().await
}
but that doesn't work as anyhow's Result is incompatible and doesn't offer any conversion methods that I can see to be interoperable with io::Result.
What would be a good way to resolve this? I'd generally like to use anyhow here but because anyhow::Result
can't be implicitly converted from a io::Result
there is no ergonomic way I see here.
I am currently looking at https://docs.rs/tower-hyper/0.1.1/tower_hyper/server/struct.Server.html which has the following trait bound S::Error: Into<Box<dyn Error + Send + Sync>>,
Is there currently a way to converting back to a Box<dyn Error + Send + Sync>
? I have briefly looked at the implementation and it seems we would need to implement Error
for ErrorImpl
.
Then we could do something like
impl Into<Box<dyn StdError + Send + Sync + 'static>> for Error {
fn into(self) -> Box<dyn StdError + Send + Sync + 'static> {
Box::new(self.inner)
}
}
The problem is that the type was thrown away, and it is unclear to me how it should be implemented.
Any ideas?
I like to log the Display version of an error instead of the Debug version, because it's then all on one line which I like better for logfiles. However there is currently no way to log the original error. I would like to be able to do:
let content = fs::read(&path)
.with_context(|e| format!("failed to read instrs from {}: {}", path.display(), e));
It's probably too late to change with_context
to take an argument - besides, it would not make sense for Option
s. Maybe error_context
? POC here: https://github.com/miquels/anyhow/commit/4a79660fa0588c097b9ae3d143bb7e54b928b97b
Currently, one has to use with_context
to pass a string that is built out of several components:
function_returning_result()
.with_context(|| format!("failed to fetch something with id {}", id))?
It would be a nice ergonomic improvement, if we could do:
function_returning_result()
.context("failed to fetch something with id {}", id)?
I am unaware of a way in Rust to do functions with variadic arguments but something that should be possible is:
function_returning_result()
.context(format_args!("failed to fetch something with id {}", id))?
format_args!
avoids heap-allocations, hence it should be fine to invoke this outside of a closure.
Thoughts?
Likely there are even better ways of doing that.
My main usecase is passing a string to context
that includes arguments from the current scope.
It is common in crates that take the anyhow approach of loosely typed dynamic error types to return Result<T, Box<dyn Error + Send + Sync + 'static>>
.
Like anyhow, this type is convenient to use - automatically coercing from impl Error
and even String
.
But, when trying to interop with this common return value using ?
the compiler stumbles with:
the trait
std::marker::Sized
is not implemented fordyn std::error::Error + std::marker::Send + std::marker::Sync
Here is a minimum reproducible case:
use anyhow;
fn dyn_error() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
Ok(())
}
fn anyhow_error() -> Result<(), anyhow::Error> {
dyn_error()?;
Ok(())
}
This would be a convenient way to express attempting a downcast against every error in the chain.
if let Some(io) = error.chain().downcast_ref::<io::Error>() {
...
}
// roughly equivalent to:
for cause in error.chain() {
if let Some(io) = cause.downcast_ref::<io::Error>() {
...
break;
}
}
I was in a situation recently where I was doing:
match some_result {
Ok(()) => {}
Err(e) => {
if !err_is_ok(e) {
bail!(e);
}
}
}
in this case e
was actually of type anyhow::Error
so a return Err(e)
would have worked just fine, but I was surprised when this bail!()
lost the context of the error of e
, presumably because it called .to_string()
on the result and lost all the context information.
Hi.
I have a small application using anyhow
which can raise errors like this:
Error: Não foi possível ler arquivo 'algum-arquivo.txt'
Caused by:
No such file or directory (os error 2)
however, it would be nice to show the following translation to our users:
Oops, ocorreu um erro: Não foi possível ler arquivo 'algum-arquivo.txt'
Causa do erro:
No such file or directory (os error 2)
So, is there any option to translate it dynamically without changing the original anyhow
sources?
TIA for any help!
This is mostly a question but may also be a feature request, I'm not sure! I tried to give migrating Cargo itself from failure
to anyhow
a spin today. Compiler-wise the transition was quite easy but the tests are turning up some nasty issues that are taking some time to debug! One of them here is related to the behavior documented here.
In failure
I believe downcast_ref
only attempted the downcast on the single error itself with no recursion, so Cargo ended up accidentally relying on that behavior. It looks like anyhow
is working differently though.
Cargo has a few use cases which are actually expressed a bit more succinctly with the recursive behavior (such as seeing if a spurious network failure happened, which no longer needs to loop).
A current use case of Cargo, however, relies on not recursively downcasting. Cargo has a (in retrospect weird) convention where given a chain of errors it may only print some of them instead of all of them. The intention is that cargo build
prints only what you need with an error, while cargo build --verbose
will always print the entire error. A good example of this is that cargo build
will not print out the full error if rustc itself fails (e.g. a compiler error), but cargo build --verbose
will print out the full compiler invocation command line.
Today Cargo uses a "marker error" called Internal
which is just a type-level marker indicating "this error and below are only printed in --verbose
mode".
There's a few places in Cargo that attempt to check for this when iterating through the chain of errors, but the behavior change with anyhow
is what's causing issues now. For example:
downcast_ref
on a top-level error returns if any sub-Error
came from an Internal
Internal
means that if there's any Internal
none of them get printed.Does anyhow
support a use case like the Internal
idea? Is there a way to downcast, but not recursively, so to act on differences in the error causal chain?
Currently anyhow::Error is not Clone, which makes the crate hard (or even impossible) to use with some mock crates in tests, e.g. mock-it.
If call macro as: anyhow!("{} not found") - there are no compilation error that argument must be provided for string interpolation. Like in format macro.
Failure provides great (Error, ErrorKind) solution that combines some of the advantages of the using Error (anyhow like) and the custom failure (thiserror) that is very useful for complex libraries.
https://rust-lang-nursery.github.io/failure/error-errorkind.html
Can it be achieved with anyhow/thiserror in some way?
anyhow::Error
does not implement std::error::Error
, which leads to confusion when using anyhow with code that expects a Result<_, std::error::Error>
.
I noticed that the same applies to failure::Error
in the failure crate.
What is the reason for that? What prevents anyhow::Error
from implementing std::error::Error
?
... and thanks for all your awesome Rust crates!
I'm not sure if this is anyhow's fault, or the compiler's fault.
When using .context, I get the following error:
error[E0599]: no method named `context` found for type `std::result::Result<(), anyhow::error::Error>` in the current scope
--> src/main.rs:83:13
|
83 | context(format!("failure in {} with nesting", c.name))?;
| ^^^^^^^ method not found in `std::result::Result<(), anyhow::error::Error>`
|
= help: items from traits can only be used if the trait is in scope
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
|
19 | use anyhow::context::Context;
That last line is awful advice, as that just leads to:
error[E0603]: module `context` is private
--> src/main.rs:24:13
|
24 | use anyhow::context::Context;
| ^^^^^^^
The real fix is: use anyhow::Context
. I don't know how to fix this message, but I feel it would make anyhow more usable if it was fixed.
I was trying to use anyhow::Error
for implementing a FromStr
for a wrapper type with the following generic implementation:
impl<T, E> std::str::FromStr for StrList<T>
where
T: std::str::FromStr<Err = E>,
E: std::error::Error + Send + Sync + 'static,
{
type Err = anyhow::Error;
fn from_str(list_str: &str) -> Result<Self, Self::Err> {
todo!()
}
}
It turns out that this won't auto-implement it for a type where E
is anyhow::Error
, due to it not implementing std::error::Error
. Why is this the case?
The anyhow
crate works very well as a drop-in substitute for failure
. One notable API difference: the anyhow
crate uses anyhow!
instead of format_err!
. format_err!
seems like a more self-explanatory and generic name, and one more suited to #13 in the future as well. Would you consider providing format_err!
as an equivalent to anyhow!
?
I'm working on a simple app using async/await and Surf, and I can't seem to use it with anyhow.
Here's a minimal example:
async fn some_request() -> anyhow::Result<()> {
let _response = surf::get("https://www.rust-lang.org").await?;
Ok(())
}
cargo +beta check
complains with:
error[E0277]: the size for values of type `dyn std::error::Error + std::marker::Send + std::marker::Sync` cannot be known at compilation time
--> src/main.rs:8:64
|
8 | let response = surf::get("https://www.rust-lang.org").await?;
| ^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `dyn std::error::Error + std::marker::Send + std::marker::Sync`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: required because of the requirements on the impl of `std::error::Error` for `std::boxed::Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>`
= note: required because of the requirements on the impl of `std::convert::From<std::boxed::Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>>` for `anyhow::Error`
= note: required by `std::convert::From::from`
I can't tell if this is an issue with anyhow
, with surf
, with the .await
, or if I'm doing something wrong.
I'm having a look at the way the ErrorVTable
is implemented and I noticed the object_downcast()
method is used to go from &self.inner
to an &mut E
.
I know Error::downcast_mut()
requires a &mut self
so in the grand scheme of things this should still be safe, but in the two highlighted lines we get a mutable reference from an immutable reference without going through UnsafeCell
, however the docs explicitly state:
The
UnsafeCell<T>
type is the only legal way to obtain aliasable data that is considered mutable. In general, transmuting an&T
type into an&mut T
is considered undefined behavior.
Is this use of pointer casting sound as far as Rust's memory model is concerned? I know the nomicon says it's UB to transmute()
a &T
to an &mut T
, but does the same rule hold for pointer casts and field access?
Right now, the crate is checking in build.rs if nightly is present, and if it is, enables the backtrace cfg without asking the user, enabling the backtrace nightly feature: https://github.com/dtolnay/anyhow/blob/master/src/lib.rs#L174
Unstable Rust features can and often do change before stabilization though. This means that this crate is a time bomb for nightly users in the event of changes of the backtrace feature. Instead, this crate should make its backtrace support entirely opt-in for the user.
I remember with failure
there was a discussion on optimizing the backtrace handling. How does this look in anyhow
?
When working on snafu's no_std compatibility, it has become clear that the situation around the lack of a core::Error or alloc::Error is really suboptimal. Introducing a whole new Error trait in snafu just for no_std seemed like it could lead to similar problems that failure had by becoming incompatible with the ecosystem. For snafu the solution is for now that it won't publicly expose an Error trait for no_std at all, but use one behind the scenes to not lose out on any of snafu's feature. This works quite well. But recently there came up the idea that maybe there could be a core-error crate, that provides an Error trait for the no_std ecosystem that could be used by snafu, anyhow, fehler and others. The crate would also have a std feature that automatically reexports the std::error::Error instead, when the feature is activated, so all the errors in your crate graph automatically get smoothly upgraded / downgraded between the different Error traits without there being any problems. And if there ever is a core::error::Error trait, it could probably backwards compatibly switch to that without having to touch either fehler, snafu or anyhow's codebase.
Considering anyhow is also planning to support no_std, this could be a good way to collaborate on an Error trait for all these crates.
For example if we have:
let e = fs::read("/...").context(ReadFailed).unwrap_err();
match e.downcast_ref::<ReadFailed>() {
should this downcast succeed or fail?
It seems that alloc should be sufficient for exposing a basic stripped down version of the existing API.
For one, second parameter is not used anywhere in the trait.
For two, it creates weird effects, like Option<T>
implementing Context<T, Infallible>
while Result<T, Infallible>
is homomorphic to T
and Option<T>
is homomorphic to Result<T, ()>
.
Is there any appetite for implementing context
and with_context
for optional values? Our homegrown lib does this and we have become addicted to the convenience. (But we will outgrow homegrown ...)
I can do a PR if there's interest.....
I find myself often writing code like
fn parse_config(path: &Path) -> anyhow::Result<Config> {
let file = BufReader::new(File::open(path)?);
let config = serde_json::from_reader(file)?;
Ok(config)
}
And then using it like parse_config(path).context("failed to parse config")
. The issue is the .context
bit has to be repeated for every call. The alternative is to put it inside the parse_config
function, but this requires either repeating it at each ?
site, or creating a inner helper function
fn parse_config(path: &Path) -> anyhow::Result<Config> {
fn inner(path: &Path) {
let file = BufReader::new(File::open(path)?);
let config = serde_json::from_reader(file)?;
Ok(config)
}
inner(path).context("failed to parse config")
}
It would be nice to have a macro to do this for us
#[error_context("failed to parse config")]
fn parse_config(path: &Path) -> anyhow::Result<Config> {
let file = BufReader::new(File::open(path)?);
let config = serde_json::from_reader(file)?;
Ok(config)
}
Thoughts? Should this be a part of anyhow
or a seperate crate (I'm not aware of any crate for this currently)
Hello
I've noticed there's a (closed) issue about having a From<Box<dyn Error + Send + Sync>>
impl, that refers to wanting that from std
(#66)
But would it make sense to have an explicit constructor in the meantime? Eg. Error::from_box_error(..)
? That way one would have to write some kind of map_error(Error::from_box_error)?
instead of just ?
, but that's probably better than nothing.
According to this, the Display
impl prints the whole chain. But for me, eprintln!("{}", e);
only prints the last added context, which is not helpful at all because even the underlying OS error is not printed.
It only prints the whole chain when I iterate manually:
for e in e.chain() {
eprintln!("{}", e);
}
But this is just quick & dirty, it doesn't have the nice formatting (with "Caused by") and indentation as it should have according to the docs.
Something like
.context(concat!(file!(), ":", line!()))
but a bit more concise
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.