Giter VIP home page Giter VIP logo

anyhow's People

Contributors

aaron1011 avatar amesgen avatar arekpiekarz avatar arthur-milchior avatar brambonne avatar cyborus04 avatar dtolnay avatar eoger avatar hbina avatar jfirebaugh avatar johnschug avatar kolloch avatar kornelski avatar lukaskalbertodt avatar lzybkr avatar m3dzik avatar ralfjung avatar repi avatar stepancheg avatar thomcc avatar timvisee avatar yaahc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

anyhow's Issues

Backtrace enabling prose is confusing

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...

`downcast_ref` on `anyhow::Error` vs `&dyn std::error::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));
}

How to combine this with io::Error?

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.

Unhelpful compiler advice when using context

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.

It doesn't print the whole chain, only the last context

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.

Second type parameter for `Context` is redundant

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, ()>.

pass source error to with_context closure?

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 Options. Maybe error_context? POC here: https://github.com/miquels/anyhow/commit/4a79660fa0588c097b9ae3d143bb7e54b928b97b

Nightly time bomb

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.

Consider using pointers and &raw operator in object_downcast implementation

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?

(The original reasoning I used when looking at this code)

Is non-recursive downcasting supported?

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:

  • Using downcast_ref on a top-level error returns if any sub-Error came from an Internal
  • Trying to print everything leading up to the 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?

Prettier error printing

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.

Consider providing format_err! as an alias for anyhow!

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!?

Document Unsafe usage

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:

Some(unsafe { &mut *(&mut self.inner.error as *mut () as *mut E) })

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):

let erased = mem::transmute::<Box<ErrorImpl<E>>, Box<ErrorImpl<()>>>(inner);

Might just be me not understanding, but at first walk through I don't know whether this code is safe to use or not.

Adding context breaks type inference

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.

Explicit constructor from Box<dyn Error + Send + Sync>

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.

another possible member of the Context trait

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.

Feature idea: a macro to add context to a function

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)

Error do not implement Serialize Deserialize

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?

Add Clone support

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.

Have anyhow::Error implement std::error::Error?

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!

reversed printing

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

Anyhow macro small issue

If call macro as: anyhow!("{} not found") - there are no compilation error that argument must be provided for string interpolation. Like in format macro.

Consider adding Chain::downcast_ref

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;
    }
}

Displaying a whole Chain

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.

impl From<NoneError> for anyhow::Error

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?

Add no_std + alloc support

It seems that alloc should be sufficient for exposing a basic stripped down version of the existing API.

Is it possible to go back to an `Box<dny Error>`?

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?

[i18n] How to translate the default anyhow messages?

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!

Context defined for Option<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.....

A more ergonomic way for adding context that needs formatting

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.

Add ensure macro?

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?

std::thread::Result has problems with ?ing to anyhow::Error

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.

`?` on surf::Exception

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.

error[E0432]: unresolved import `std::backtrace` when building with rustc 1.38.0-dev

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?).

Collaborate on a "core::Error" crate with snafu

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.

? does not coerce Box<dyn Error + Send + Sync + 'static> to anyhow::Error

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 for dyn 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(())
}

Providing newtype macro

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.

Use non-thread safe structs as errors?

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!

Why doesn't `anyhow::Error` implement `std::error::Error`?

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?

Would this be worth exploring adding to std?

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 merged
  • std::error could be a very good default for various Err, Error, and E type parameters
  • std::error in a future edition could be added to the prelude as just error

downcasting on individual context layers

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.

Why does Error require Send (and Sync)?

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.

Consider implementing DoubleEndedIterator for Chain

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.

support wrapping error_chain Error's ? / document that Send+Sync are required on top of std::error::Error

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?

Usage of `bail!(error)` loses the context of `error`

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.