hobofan / ambassador

Delegation of trait implementations via procedural macros
Apache License 2.0
251 stars 13 forks source link

Async trait support #46

Closed ileixe closed 8 months ago

ileixe commented 1 year ago

Hi,

Are there any plans to support async trait like below? I wonder it's easily added or not.

#![feature(async_fn_in_trait)]

use ambassador::delegatable_trait;
use ambassador::Delegate;

pub struct Base {}

#[delegatable_trait]
pub trait Hello {
    async fn hello(&self);
}

impl Hello for Base {
    async fn hello(&self) {}
}

#[derive(Delegate)]
#[delegate(Hello)]
pub struct Dram {
    inner: Base,
}

fn main() {
    let d = Dram { inner: Base {} };

    d.hello();
}

Currently it failed with

error[E0308]: mismatched types
  --> src/main.rs:8:1
   |
8  | #[delegatable_trait]
   | ^^^^^^^^^^^^^^^^^^^^ expected `()`, found opaque type
...
17 | #[derive(Delegate)]
   |          -------- in this derive macro expansion
   |
note: while checking the return type of the `async fn`
  --> src/main.rs:14:27
   |
14 |     async fn hello(&self) {}
   |                           ^ checked the `Output` of this `async fn`, found opaque type
   = note: expected unit type `()`
            found opaque type `impl Future<Output = ()>`
   = note: this error originates in the macro `ambassador_impl_Hello` which comes from the expansion of the derive macro `Delegate` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider `await`ing on the `Future`
   |
8  | #[delegatable_trait].await
   |                     ++++++
help: consider using a semicolon here
   |
8  | #[delegatable_trait];
   |                     +

Thanks

dewert99 commented 8 months ago

Sorry for the slow response. I don't think it should be too hard to add support for this.

In the mean time, I think it does work to do:

use std::future::Future;
use ambassador::delegatable_trait;
use ambassador::Delegate;

pub struct Base {}

#[delegatable_trait]
pub trait Hello {
    fn hello(&self) -> impl Future<Output=()>;
}

impl Hello for Base {
    async fn hello(&self) {}
}

#[derive(Delegate)]
#[delegate(Hello)]
pub struct Dram {
    inner: Base,
}

fn main() {
    let d = Dram { inner: Base {} };

    d.hello();
}