real-async-trait-rs icon indicating copy to clipboard operation
real-async-trait-rs copied to clipboard

dyn real_async_trait?

Open eholk opened this issue 2 years ago • 2 comments

Is there a way to make a dyn Trait object out of a type that impls a trait annotated with #[real_async_trait]?

I'd like to be able to do something like:

#[real_async_trait]
trait Foo {
    async fn foo();
}

struct Bar {
    maybe_foo: Option<Box<dyn Foo>>,
}

When I try to do this, however, I get an error saying I need to specify the associated type for Foo::foo.

eholk avatar Mar 16 '22 21:03 eholk

Well, since every implementation gets its own future types, no real-async-trait traits are object safe unless you box the futures, which you cannot guarantee every implementation will do. It should in theory be possible to require that the futures be boxed when creating an async trait object and hence be the same size and thereby object safe (like the regular async-trait crate does), but it's nontrivial and we might have to wait for the language to implement async traits first. Or, we can manually generate code for both an object safe trait and a regular trait, and then implement the regular trait for types which already implement the object safe trait. But AFAIK the only way now to make dyn async traits is to use async-trait.

4lDO2 avatar Jun 11 '22 16:06 4lDO2

We could probably do this by having real_async_trait generate a bridge trait, although perhaps opt-in with something like #[real_async_trait(dyn)]. In my example, we'd generate something like this to go with it:

trait DynFoo {
    fn foo(&self) -> Box<dyn Future<Output = ()>>;
}

impl<T: Foo> DynFoo for T {
    fn foo(&self) -> Box<dyn Future<Output = ()>> {
        Box::new(<Self as Foo>::foo(self))
    }
}

Although until there's more language support if you need this then using async-trait is probably the best option.

eholk avatar Jun 20 '22 22:06 eholk