Skip to content

Trivial wrapper Generators waste space relative to wrapped Generators #114064

@anderspapitto

Description

@anderspapitto

I'm unclear if this is properly a bug or feature request - it's a missed optimization opportunity that IMO should be guaranteed.

I tried this code: (playground: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021)

#![feature(generators)]
#![feature(generator_trait)]

use core::pin::Pin;
use std::ops::Generator;
use std::ops::GeneratorState;
use std::mem;


pub fn mk_foo(x: bool) -> impl Generator {
    move || {
        if x {
            yield;
        }
    }
}

pub fn mk_bar(x: bool) -> impl Generator {
    let mut f = mk_foo(x);
    static move || {
        loop {
            match unsafe { Pin::new_unchecked(&mut f) }.resume(()) {
                GeneratorState::Yielded(_) => yield,
                GeneratorState::Complete(_) => return,
            }
        }
    }
}

pub fn mk_baz(x: bool) -> impl Generator {
    static move || {
        let mut f = mk_foo(x);
        loop {
            match unsafe { Pin::new_unchecked(&mut f) }.resume(()) {
                GeneratorState::Yielded(_) => yield,
                GeneratorState::Complete(_) => return,
            }
        }
    }
}

fn main() {
    let foo = mk_foo(true);
    let bar = mk_bar(true);
    let baz = mk_baz(true);
    println!(
        "sizes {} {} {}",
        mem::size_of_val(&foo),
        mem::size_of_val(&bar),
        mem::size_of_val(&baz),
    );
}

I expected to see this happen: sizes of foo, bar, baz should all be identical, because foo and baz simply forward to the underlying foo - they don't have any additional states. This makes the generator abstraction less zero-cost than it should be.

Instead, this happened: sizes are 2, 3 and 4 respectively.

Meta

rustc 1.73.0-nightly (8771282 2023-07-23)
binary: rustc
commit-hash: 8771282
commit-date: 2023-07-23
host: x86_64-unknown-linux-gnu
release: 1.73.0-nightly
LLVM version: 16.0.5

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions