Is it possible to create a concrete Future type that wraps opaque Future types (no generics or trait objects)?

Hi
is it possible in Rust to wrap an opaque Future (async block, async fn, multiple concrete Future types) in a concrete Future type?

I need a trait to be dyn compatible but at the same time it should support to be called by async code. Therefore it cannot have async methods or contain generic parameters.

The method itself calls async function/methods which differ between implementations of that trait.

AFAIK by the restrictions of dyn compatibility the trait method must return a concrete type implementing the Future trait. But the issue is, that the wrapped Futures are opaque types and I found no way to pass them to the concrete type without trait objects or generic parameters.

One approach I initially tried was a struct accepting a function pointer retuning a Poll result, but I soon noticed that this can't work since you need to provide a closure capturing the wrapped Future and therefore the closure cannot be coerced to a function pointer.

Is there any known pattern in Rust to achieve this or is it simply impossible without using trait objects currently?

This problem is what the async_trait library is for. It uses Pin<Box<dyn Future>> as the “concrete Future type”, and you can also write this yourself, but async_trait does the transformation for you so that you can use convenient async fn syntax.

Okay, so it's necessary to use trait objects in such a case.
Thanks, I'll try out the library.

This is impossible without using trait objects. Since the trait type is opaque, you can't refer to it directly, and you have to refer to it by trait.

The two ways to use a trait as a real type in Rust are generics (optionally using the impl keyword as syntactic sugar) or trait objects which do dynamic dispatch at run time.

Unfortunately, as you encountered, you can not use generics in dyn-compatible traits without having to name the type somewhere else, so this approach is currently impossible. That leaves trait objects as the only option.

Each implementation of a future can have a different size depending on the number and of local variables, so it's a physical necessity for there to be some kind of indirection like Box<dyn Trait> to handle the size difference.

Thanks for your reply.

You meant at runtime, not compile time, right? It would be new to me that dynamic dispatch - in contrast to static dispatch with generics - can (sometimes?) happen at compile time. i.e. I thought using trait objects implies dispatch at runtime.

You are correct, fixed

You may be interested in the "Type Alias Impl Trait" (TAIT) unstable feature: Impl trait in type aliases - Impl trait initiative

As with all unstable features, it requires nightly and may change significantly before stabilization, or never be stabilized.