Search code examples
rusttraitsrust-futures

How to store a future without boxing it


I want to do the following

struct Stored<F: Future<Output = ()>> {
    f: Option<F>,
}

impl<F: Future<Output = ()>> Stored<F> {
    fn store(&mut self, f: F) {
        let f = async {};
        self.f = Some(f);
    }
}

But it gives me the error:

expected type parameter `F`
      found opaque type `impl futures::Future<Output = ()>`
type parameters must be constrained to match other types

I could solve it boxing the future, but if the method store was the only place I stored this future, there would be no need to do that, because all the future blocks would be always the same type. How could I do it?


Solution

  • This doesn't work because F is a generic type provided from outside of the Stored type, but the actual type of the future is an unnamed type provided from within the store associated function (created by async {}). There is no possible way that F can be specified to be the correct type.

    The way this is usually handled is to create a dedicated, nameable type implementing Future. In this trivial case, that could be std::future::Ready<()>:

    struct Stored {
        f: Option<std::future::Ready<()>>,
    }
    
    impl Stored {
        fn store(&mut self) {
            self.f = Some(std::future::ready(()));
        }
    }
    

    If the type of the future actually does come from outside of the type, then you just need to adjust your code to use f directly instead of discarding it and using async {}:

    use std::future::Future;
    
    struct Stored<F> {
        f: Option<F>,
    }
    
    impl<F: Future> Stored<F> {
        fn store(&mut self, f: F) {
            self.f = Some(f);
        }
    }