What is the type of an async function?

pub trait GenericAsyncRunner{
    fn return_run_function(&self) -> ?;
}
pub enum AsyncRunError{}


pub struct SpecificAsyncRunner{}

impl SpecificAsyncRunner{
    async fn run(&self) -> Result<u32, AsyncRunError> {
        todo!()
    }
}

impl GenericAsyncRunner for SpecificAsyncRunner {
    fn return_run_function(&self) -> ? {
        todo!()
    }
}

I want to get a pointer to the async run function, at runtime. In practice I'll have let generic_async_runner = Box<dyn GenericAsyncRunner> and I want generic_async_runner.return_run_function().await. I could downcast but in practice there will be lots of different SomethingAsyncRunner so downcasting would have to try to downcast to all of them.

Can I rewrite async fn run() -> Result<u32, AsyncRunError> into a desugared version that returns a Future? In this way I can have a concrete type to put in ? on the code above.

It desugars to

fn run() -> impl Future<Output = Result<u32, AsyncRunError>>

Which doesn't help you on stable, because there's no way to name the opaque impl Trait types yet.

On nightly you can work around it with TAIT.

/* some details omitted */
pub trait GenericAsyncRunner{
    type Run: Future<Output=Result<u32, AsyncRunError>>;
    fn return_run_function() -> fn() -> Self::Run;
}

// This TAIT is effectively giving a name to your opaque type
type SpecificAsyncType = impl Future<Output=Result<u32, AsyncRunError>>;
impl SpecificAsyncRunner {
    // The TAIT is defined by this implementation.  We can't use the `async fn`
    // sugar, or it interferes with the "defining use".  So instead we use a
    // normal function containing an `async` block.
    fn run() -> SpecificAsyncType {
        async { todo!() }
    }
}

impl GenericAsyncRunner for SpecificAsyncRunner {
    // Now we can name the opaque type
    type Run = SpecificAsyncType;
    fn return_run_function() -> fn() -> Self::Run {
        Self::run
    }
}

can I use a boxed future instead to avoid impl and nightly? If so, how?

Yes, you can box up the Futures instead. (I thought you were trying to avoid that; guess I misread.)

ideally I'd like to not use Box but it's better than nightly.

Take a look: Rust Playground why it asks for Pin here? I tried actually running the function

Oh sorry, you do need the Pin (and then use Box::pin instead of Box::new).

Updated playground.

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.