shepmaster / snafu

Easily assign underlying errors into domain-specific errors while adding context
https://docs.rs/snafu/
Apache License 2.0
1.4k stars 60 forks source link

Whatever is not async compatible #322

Closed bryanlarsen closed 2 years ago

bryanlarsen commented 2 years ago

Following the instructions on the front page, I have

#[derive(Debug, Snafu)]
pub enum Error {
    #[snafu(whatever, display("{message}"))]
    Whatever {
        message: String,
        #[snafu(source(from(Box<dyn std::error::Error>, Some)))]
        source: Option<Box<dyn std::error::Error>>,
    },

This results in the error:

error: future cannot be sent between threads safely
  --> src/main.rs:45:61
   |
45 |       async fn get(&self, key: &str) -> Result<String, Error> {
   |  _____________________________________________________________^

...  |
   | |_____^ future created by async block is not `Send`
   |
   = help: the trait `Send` is not implemented for `(dyn snafu::Error + 'static)`
note: future is not `Send` as this value is used across an await
  --> src/main.rs:46:12

Removing the Whatever block from my error enum fixes the message. I wasn't using whatever! in my async function but it was annoying stripping it from the rest of my code.

I'm a rust newbie, so problem is likely PBKAC, but in case it might affect others I raised an issue. I've now purged whatever usage, so I'm fine with you closing the issue if that's appropriate.

shepmaster commented 2 years ago

When reporting an issue, it’s useful to produce an MRE.

When next I have time to investigate this issue, I’ll spend it on reproducing the problem. Then the next time i have, I can work on addressing the problem.

shepmaster commented 2 years ago

Should work if you adjust the trait object to be Send / Sync:

use snafu::{prelude::*, whatever};

#[derive(Debug, Snafu)]
pub enum Error {
    #[snafu(whatever, display("{message}"))]
    Whatever {
        message: String,
        #[snafu(source(from(Box<dyn std::error::Error + Send + Sync>, Some)))]
        source: Option<Box<dyn std::error::Error + Send + Sync>>,
    },
}

fn create() -> Result<(), Error> {
    whatever!("Broken")
}

fn main() {
    fn is_send(_: impl Send) {}
    is_send(create());
}

See also Sending trait objects between threads in Rust

bryanlarsen commented 2 years ago

Yes, that works. I don't know if it should be added to the documentation or not.

Thanks.

hellow554 commented 2 years ago

I stumbled across this today as well.

It should definitly added to the guide at https://github.com/shepmaster/snafu/blob/ba92e751f17e7095453c2178b890f305567fd682/src/lib.rs#L167-L185 because that's where I (and everyone else?) copied the code from to use whatever along with other errors.

shepmaster commented 2 years ago

Feedback welcome on #331

shepmaster commented 2 years ago

Published in https://crates.io/crates/snafu/0.7.1