Tallented-Code-bot
Tallented-Code-bot

Reputation: 65

How to represent an opaque type in a struct field

I am using the genawaiter crate for generator functions to implement single-threaded "multitasking". I have this code to create a new Thread, and pass a generator to it, but I am struggling to find how to represent the impl Future type that gen!() returns.

use genawaiter::rc::{gen, Gen};
use genawaiter::yield_;
struct Thread {
    function: genawaiter::rc::Gen<(), Option<Sprite>, /*What can go here?*/>,
}

struct Sprite {/*fields here*/}

fn main() {
    let thread1 = Thread {
        function: gen!({
            let object: Option<&mut Sprite> = yield_!(());
            // do stuff with `object`
            println!("Hi");
        }),
    };
}

The type that the gen!() macro returns is.

genawaiter::rc::Gen<(),Option<Sprite>,impl Future<Output = ()>>

If I try to set this as the type of the function field, I get this error message:

error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in path
  --> src/main.rs:20:55
   |
20 |     function: genawaiter::rc::Gen<(), Option<Sprite>, impl Future<Output = ()>>,
   |                                                       ^^^^^^^^^^^^^^^^^^^^^^^^

For more information about this error, try `rustc --explain E0562`.
error: could not compile `testing` due to previous error
struct EmptyFuture{}
impl Future for EmptyFuture {
    type Output = ();

    fn poll(
        self: std::pin::Pin<&mut Self>,
        cx: &mut std::task::Context<'_>,
    ) -> std::task::Poll<Self::Output> {
        std::task::Poll::Ready(())
    }
}

If I try putting this EmptyFuture struct in the function field, it also does not work, and I get this error message:

error[E0308]: mismatched types
  --> src/main.rs:27:19
   |
27 |            function: gen!({
   |   ___________________^____-
   |  |___________________|
   | ||
28 | ||             let object: Option<Sprite> = yield_!(());
29 | ||             println!("Hi");
30 | ||         }),
   | ||_________-^ expected struct `EmptyFuture`, found opaque type
   |  |_________|
   |            the found `async` block
   |
  ::: /home/calvin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/future/mod.rs:72:43
   |
72 |    pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
   |                                              ------------------------------- the found opaque type
   |
   = note: expected struct `genawaiter::rc::Gen<_, _, EmptyFuture>`
              found struct `genawaiter::rc::Gen<_, _, impl Future<Output = ()>>`
   = note: this error originates in the macro `gen` (in Nightly builds, run with -Z macro-backtrace for more info)

The only semi-relavant thing I could find on stackoverflow was this, but that is about a function /returning/ an opaque type.

How can I represent the opaque type in my struct? Also, does it make a difference whether it is an empty type (impl Future<Output = ()>) or some other struct(impl Future<Output = SomeStruct>)?

Edit:

I tried Box<dyn Future<Output = ()>>, and got this error:

error[E0277]: `(dyn Future<Output = ()> + 'static)` cannot be unpinned
   --> src/target/mod.rs:325:15
    |
325 |     function: genawaiter::rc::Gen<(), Option<Sprite>, Box<dyn Future<Output = ()>>>,
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unpin` is not implemented for `(dyn Future<Output = ()> + 'static)`
    |
    = note: consider using `Box::pin`
    = note: required because of the requirements on the impl of `Future` for `Box<(dyn Future<Output = ()> + 'static)>`
note: required by a bound in `genawaiter::rc::Gen`
   --> /home/calvin/.cargo/registry/src/github.com-1ecc6299db9ec823/genawaiter-0.99.1/src/rc/generator.rs:11:25
    |
11  | pub struct Gen<Y, R, F: Future> {
    |                         ^^^^^^ required by this bound in `genawaiter::rc::Gen`

For more information about this error, try `rustc --explain E0277`.

I followed the compiler suggestion and changed it to Pin<Box<dyn Future<Output = ()>>>, but now I am getting a similar error as before:

error[E0308]: mismatched types
  --> src/main.rs:28:19
   |
28 |            function: gen!({
   |   ___________________^____-
   |  |___________________|
   | ||
29 | ||             let object: Option<Sprite> = yield_!(());
30 | ||             println!("Hi");
31 | ||         }),
   | ||_________-^ expected struct `Pin`, found opaque type
   |  |_________|
   |            the found `async` block
   |
  ::: /home/calvin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/future/mod.rs:72:43
   |
72 |    pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
   |                                              ------------------------------- the found opaque type
   |
   = note: expected struct `genawaiter::rc::Gen<_, _, Pin<Box<(dyn Future<Output = ()> + 'static)>>>`
              found struct `genawaiter::rc::Gen<_, _, impl Future<Output = ()>>`
   = note: this error originates in the macro `gen` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0308`.

Upvotes: 4

Views: 810

Answers (1)

Aleksander Krauze
Aleksander Krauze

Reputation: 6061

You could try boxing trait object. That is use Box<dyn Future<Output = ()>>. This will cost you an allocation per created future, but it's the simplest solution. And practically the only one if you don't (or can't) name a type.

Upvotes: 2

Related Questions