Help with WMI crate async_query() within trait implementation

Hello all! I am attempting to use the WMI crate's async_query() within a #[async_trait] implementation. This results in a compiler error (below). However, if I use the same code within a struct function, everything works. I'm still getting my barrings on Rust, so I might be missing something obvious here.

Working example:

#[tokio::test]
async fn can_query_wmi_async() -> Result<()>  {
    let com_con = COMLibrary::new()?;
    let wmi_con = WMIConnection::new(com_con.into())?;

    let results: Vec<UserProfile> = wmi_con.async_query().await?;
    for result in results {
        println!("{result:#?}");
    }

    Ok(())
}

Non-working with Trait impl:

#[async_trait]
trait TestWmiTrait {
    async fn do_query() -> Result<()>;
}

struct TestWmi;

#[async_trait]
impl TestWmiTrait for TestWmi {
    async fn do_query() -> Result<()> {
        let com_con = COMLibrary::new()?;
        let wmi_con = WMIConnection::new(com_con.into())?;

        let results: Vec<UserProfile> = wmi_con.async_query().await?;

        for result in results {
            println!("{result:#?}");
        }

        Ok(())
    }
}

Results in:

crates\bds_host\src\account\windows.rs:441:43
    |
441 |           async fn do_query() -> Result<()> {
    |  ___________________________________________^
442 | |             let com_con = COMLibrary::new()?;
443 | |             let wmi_con = WMIConnection::new(com_con.into())?;
444 | |
...   |
451 | |             Ok(())
452 | |         }
    | |_________^ future created by async block is not `Send`
    |
    = help: within `[async block@crates\bds_host\src\account\windows.rs:441:43: 452:10]`, the trait `Send` is not implemented for `NonNull<c_void>`
note: future is not `Send` as this value is used across an await
   --> crates\bds_host\src\account\windows.rs:445:67
    |
443 |             let wmi_con = WMIConnection::new(com_con.into())?;
    |                 ------- has type `wmi::WMIConnection` which is not `Send`
444 |
445 |             let results: Vec<UserProfile> = wmi_con.async_query().await?;
    |                                                                   ^^^^^ await occurs here, with `wmi_con` maybe used later
...
452 |         }
    |         - `wmi_con` is later dropped here
    = note: required for the cast from `Pin<Box<[async block@crates\bds_host\src\account\windows.rs:441:43: 452:10]>>` to `Pin<Box<(dyn Future<Output = std::result::Result<(), anyhow::Error>> + Send + 'async_trait)>>

What am I missing here to get this working?

1 Like

async_trait is trying to be helpful and places a Send bound on the returned future by default, because most of the time, you do want your futures to be Send.

However, yours isn't – how to solve it is explicitly in the docs.

2 Likes

Thank you, exactly what I needed!