Method to return future

Hey there,

I'm trying to figure out a method for a trait I have that can return Tokio's Timeout type having wrapped a channel recv. I understand that async closure types are anonymous and that this is obviously the root cause of my problems, so I assume I'm just going about things the wrong way.

Here's a sample with the problem:

trait SomeTrait {
    fn my_func(&self) -> Timeout<Pin<Box<dyn Future<Output = Option<u32>>>>>;
}

impl SomeTrait for u32 {
    fn my_func(&self) -> Timeout<Pin<Box<dyn Future<Output = Option<u32>>>>> {
        let (tx, mut rx) = channel::<u32>(1);
    
        let _ = tx.send(*self);
        
        async {
            timeout(Duration::from_millis(1000), rx.recv()).await
        }
    }
}

The problem reported is:

18 | /         async {
19 | |             timeout(Duration::from_millis(1000), rx.recv()).await
20 | |         }
   | |_________^ expected struct `tokio::time::Timeout`, found opaque type
   |
   = note:   expected struct `tokio::time::Timeout<Pin<Box<(dyn Future<Output = Option<u32>> + 'static)>>>`
           found opaque type `impl Future`

Code on Rust Playground.

Help most appreciated.

The way you create a pinned boxed future is with Box::pin, so given your return type, you would need to do this:

let inner = Box::pin(async move {
    rx.recv().await
});

timeout(Duration::from_millis(1000), inner)

Though you would usually not mention the Timeout type in a trait signature. If you don't do that, the return becomes:

Box::pin(async move {
    timeout(Duration::from_millis(1000), rx.recv().await)
})
1 Like

Thank you so much for the blazingly fast and helpful reply!

I'm not quite getting:

Though you would usually not mention the Timeout type in a trait signature. If you don't do that, the return becomes...

Could I push you to provide the type signature in that instance? The timeout function is going to want to return a Timeout type, right?

My updated code in the playground.

First you need to move the .await a bit:

Box::pin(async move {
    timeout(Duration::from_millis(1000), rx.recv()).await
})

Now all that is left is to fix the return type to:

Pin<Box<dyn Future<Output = Result<Option<u32>, Elapsed>>>>

or you can match on the timeout and do something sane if it times out.

1 Like

That's amazing - thank you so much. The code as a whole for anyone else reading this:

trait SomeTrait {
    fn my_func(&self) -> Pin<Box<dyn Future<Output = Result<Option<u32>, Elapsed>>>>;
}

impl SomeTrait for u32 {
    fn my_func(&self) -> Pin<Box<dyn Future<Output = Result<Option<u32>, Elapsed>>>> {
        let (tx, mut rx) = channel::<u32>(1);
    
        let _ = tx.send(*self);
        
        Box::pin(async move {
            timeout(Duration::from_millis(1000), rx.recv()).await
        })
    }
}