Macro: transform function into state machine iterator?

def_fn_iter!((n: usize). {
   for i in 0 .. n
     yield_value(i);
   }
})

Consider the above pseudocode. It takes a plain Rust function. This Rust function uses yield_value inside it. We can mechanically transform this into an Iterator as follows:

  1. run everything up until the field Yield, this goes in the constructor of the Iterator

  2. for Iterator::next(), run until first yield(), return Some(v); if function terminates, return None

If we mechanically convert the function into a state machine, we can write iterators with yield_value.

Question: is there any Rust macro for doing something like this?

===

Pre-emptive answers:

This won't work if the yield_value is in a nested function. That's fine. We make it a requirement that the yield_value has to be lexically within the macro. Clojure's go block ( Clojure - Go Block Best Practices ) has the same limitation and it's fine.

See genawaiter:

let count_to_ten = gen!({
    for n in 0..10 {
        yield_!(n);
    }
});
5 Likes

I think I am missing something very simple. I have struct Foo. I want to define an iter for it, struct FooIter.

Is there a way to stuff the 'generator' from the crate above into a struct ?

As far as I can tell, the generated type is unnameable (due to embedded async blocks). To store that in a struct, you've got three choices:

  • As a boxed trait object: struct S(Box<dyn Iterator<Item=...>>);
  • As a generic parameter: struct S<Iter: Iterator>(Iter);
  • With a type alias (requires #![feature(type_alias_impl_trait)])

NB: I haven't actually used genawaiter myself

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.