1

I am using a Rust generator and it was working fine with nightly 1.29.0:

#![feature(generators, generator_trait)]

use std::ops::{Generator, GeneratorState};

fn main() {
    let mut generator: Box<dyn Generator<Yield = u64, Return = &str>> = Box::new(move || {
        yield 1;
        return "foo";
    });

    unsafe {
        match generator.resume() {
            GeneratorState::Yielded(1) => {
                println!("Yielded");
            }
            _ => panic!("unexpected return from resume"),
        }
        match generator.resume() {
            GeneratorState::Complete("foo") => {
                println!("Completed");
            }
            _ => panic!("unexpected return from resume"),
        }
    }
}

However, nightly version 1.34.0 requires the Generator to be wrapped in Pin, but when I wrap Generator into Pin, the code doesn't work anymore.

#![feature(generators, generator_trait)]

use std::ops::{Generator, GeneratorState};
use std::pin::Pin;

fn main() {
    let mut generator: Box<dyn Generator<Yield = u64, Return = &str>> = Box::new(move || {
        yield 1;
        return "foo";
    });

    match Pin::new(&mut generator).resume() {
        GeneratorState::Yielded(1) => {
            println!("Yielded");
        }
        _ => panic!("unexpected return from resume"),
    }
    match Pin::new(&mut generator).resume() {
        GeneratorState::Complete("foo") => {
            println!("Completed");
        }
        _ => panic!("unexpected return from resume"),
    }
}

And the code gives the following error.

error[E0599]: no method named `resume` found for type `std::pin::Pin<&mut std::boxed::Box<dyn std::ops::Generator<Yield = u64, Return = &str>>>` in the current scope
  --> src/main.rs:12:36
   |
12 |     match Pin::new(&mut generator).resume() {
   |                                    ^^^^^^
   |
   = note: the method `resume` exists but the following trait bounds were not satisfied:
           `std::boxed::Box<dyn std::ops::Generator<Yield = u64, Return = &str>> : std::ops::Generator`

When I remove the type of the generator, it works fine:

let mut generator = Box::new(move || {
        yield 1;
        return "foo"
});

I have a few questions:

  • Why does wrapping the Generator in Pin give the error in the latest version?
  • What's the use of using the Pin for the generator (as it prevents the value of a pointer from being moved), I don't understand the relation between Pin and Generator?
  • Why does the code work when we remove the type for generator variable?
  • Why is the resume method no longer unsafe?
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
A-B
  • 487
  • 2
  • 23

1 Answers1

4

Why does generator code that was working in nightly Rust 1.29 give an error in Nightly 1.34.0?

Because this is a nightly, unstable feature which may change at any time and it changed.

See also:

Why does wrapping the Generator in Pin give the error in the latest version?

As the error message states, Box<dyn Generator<Yield = u64, Return = &str>> doesn't implement Generator.

See also:

What's the use of using the Pin for the generator?

Why is the resume method no longer unsafe?

The resume method was unsafe because you could introduce memory unsafety if the generator had a self-referential variable and it was moved between two calls to resume. Pin prevents the move, thus removing the unsafety. This is a classic example of wrapping unsafe logic in an API that only exposes a safe interface.

See also:

Why does the code work when we remove the type for generator variable?

Because it's no longer a trait object (Box<dyn Generator>) but just a boxed concrete generator.

See also:


I'd write this as

#![feature(generators, generator_trait)]

use std::ops::{Generator, GeneratorState};

fn main() {
    let mut generator = Box::pin(move || {
        yield 1;
        "foo"
    });

    match generator.as_mut().resume() {
        GeneratorState::Yielded(1) => println!("Yielded"),
        _ => panic!("unexpected return from resume"),
    }
    match generator.as_mut().resume() {
        GeneratorState::Complete("foo") => println!("Completed"),
        _ => panic!("unexpected return from resume"),
    }
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366