Yielding Iterators from Branched Sources

Between returning impl Iterator<...>, Box<dyn Iterator<...>>, and writing my own structs that implement Iterator, I've gotten myself confused. After quite some time trying, I'm unable to write something which on the surface should be obviously possible, namely:

How does one yield an Iterator of T that gets those T from potentially branching sources?

Here's a fabricated example:

enum Foo {
    A { a: Vec<u32> },
    B { a: Vec<u32>, b: Vec<u32> },
}

impl Foo {
    fn numbers(&self) -> impl Iterator<Item = &u32> {
        match self {
            Foo::A { a } => a.iter(),
            Foo::B { a, b } => a.iter().chain(b),
        }
    }
}

This doesn't compile, because the match branches are technically returning different types, due to how Rust implements iterators as distinct structs. Through what incantation can I get this (or something like it) to compile? Note:

  1. Don't fuss too much about the Vecs, the original sources could be any IntoIterator.
  2. The enum-struct fields could be distinct structs (and are in my real code).
  3. Box<dyn ... doesn't immediately work here due to the lifetime on self.
  4. Manually fusing the Vecs or doing an additional collect beforehand are not possible for me.

Am I missing something obvious? Please and thanks.

You can do box with

enum Foo {
    A { a: Vec<u32> },
    B { a: Vec<u32>, b: Vec<u32> },
}

impl Foo {
    fn numbers<'a>(&'a self) -> Box<dyn Iterator<Item = &'a u32> + 'a> {
        match self {
            Foo::A { a } => Box::new(a.iter()),
            Foo::B { a, b } => Box::new(a.iter().chain(b)),
        }
    }
}

Another way is to use Either from itertools.

1 Like

I'll try the Box again, I may have been missing the final added + 'a.

re: Either, in my example here there are only two branches, but generally we should consider the N-branch case, so a simple Left-Right wouldn't quite do it.

Some nested stuff like Either<Either<A, B>, Either<C, D>> can work.

3 Likes

You can derive wider enums implementing such traits with auto_enums.

2 Likes

Exactly what I was looking for, thank you very much. Rust continues to impress!

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.