Size unknown when storing a struct parameterized with a future

I am trying to store a tokio::Timeout struct within a structure. My intent is for the structure to own it. I see that Timeout<T> is bounded with Sized, but my thought was Timeout would have already satisfied the compiler.

use std::future::Future;
use tokio::time::{error::Elapsed, timeout, Timeout};
struct SockTimeout {
    pub timeout: Timeout<dyn Future<Output = ()>>,
}

#[tokio::main]
async fn main() {
    let when = Duration::from_millis(2000);

    let my_struct = SockTimeout {
        timeout: timeout(when, async {}),
    };
}
error[E0277]: the size for values of type `(dyn Future<Output = ()> + 'static)` cannot be known at compilation time
   --> src/main.rs:30:18
    |
30  |     pub timeout: Timeout<dyn Future<Output = ()>>,
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `(dyn Future<Output = ()> + 'static)`
note: required by a bound in `tokio::time::Timeout`
   --> /Users/steve/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.19.2/src/time/timeout.rs:135:24
    |
135 |     pub struct Timeout<T> {
    |                        ^ required by this bound in `tokio::time::Timeout`

The only way I have found around this issue is to turn SockTimeout into a template. I have tried Box‘ing Timeout, but the same issue persists. What am I fundamentally missing here?

>Solution :

Boxing the Timeout won’t help because Timeout<T> requires that T: Sized, not just that Timeout<T>: Sized. Instead you need to box the future.

You may also need to pin it:

struct SockTimeout {
    pub timeout: Timeout<Pin<Box<dyn Future<Output = ()>>>>,
}

#[tokio::main]
async fn main() {
    let when = Duration::from_millis(2000);

    let my_struct = SockTimeout {
        timeout: timeout(when, Box::pin(async {})),
    };
}

Leave a Reply