Writing an async function wrapper

Hey, im trying to write a wrapper for an async function. It should produce a new function and return that function to be called later on. You can see the playground on how exactly i imagine it to work. But the error im getting just confuses me. Can someone explain me what im doing wrong and maybe propose a fix? Thanks in advance!

Playground

Error:

error[E0308]: mismatched types
  --> src/main.rs:48:13
   |
48 |     let c = wrap_function(some_function);
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
   |
   = note: expected opaque type `impl for<'a> Future<Output = Result<Data, Error>>`
              found opaque type `impl Future<Output = Result<Data, Error>>`
   = help: consider `await`ing on both `Future`s
   = note: distinct uses of `impl Trait` result in different opaque types
note: the lifetime requirement is introduced here
  --> src/main.rs:31:28
   |
31 |     Func: Fn(&mut Conn) -> Fut + Send + Sync + 'static,
   |                            ^^^

There's currently a new feature on nightly which addresses exactly your problem. :slight_smile: Read here. Until this is on stable I recommend using this crate.

EDIT: Sorry, I was too fast... as the blog post also mentions you cannot yet put additional bounds to the future, but you obviously want that... but async_fn_traits should still solve your problem.

1 Like

If async_fn_traits solves your use case you should just use that, but for the sake of understanding...

This function:

async fn some_function(_conn: &mut Conn) -> Result<Data, Error> {

captures the input lifetime:

struct SomeUnnameableFuture<'a>(SomeUnnameableAsyncState<'a>);
impl Future for SomeUnnameableFuture<'_> {
    type Output = Result<Data, Error>;
    // ...
}

// Callers see an opaque `impl Future<Output=...>`
fn some_function<'c>(_conn: &'c mut Conn) -> SomeUnnameableFuture<'c> {

Note that for every input lifetime 'c, you get a different output type SomeUnnameableFuture<'c>. Even though they all only differ by the lifetime, they're still different types.

But then here:

fn wrap_function<Func, Fut, D>(
    func: Func,
) -> impl FnOnce(Conn) -> Pin<Box<dyn Future<Output = Conn> + Send >>
where
    Func: Fn(&mut Conn) -> Fut + Send + Sync + 'static,
    Fut: Future<Output = Result<D, Error>> + Send,
    D: Send,

Type parameters like Fut represent a single type, so the bounds only accept functions/closures that always return the same type.

"implementation of Fn is not general enough" is the relevant error. Sadly you more or less just have to have experience to know what it's talking about, and it comes after another less helpful[1] error to boot.

There's no solution that avoids type erasure (dyn _) yet, as far as I know.


  1. straight up unintelligible? ↩ī¸Ž

2 Likes

Hey, thank you the crate solved the problem. Also looking forward to the changes in the blog post.

1 Like

Thank you so much for explaining the error!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.