I have a struct which owns a Vec and has an optional reference to a parent struct of its own type. I want a iterator that iterates over the items and then if there is a parent recursively iterate.
I currently have the following, but it allocates on the heap and uses dynamic dispatch:
struct Struct1 {
items: Vec<(String, i32)>,
parent: Option<Rc<Struct1>>
}
impl Struct1 {
pub fn keys<'a>(&'a self) -> Box<dyn Iterator<Item = &'a str> + 'a> {
let iter = self.items.iter().map(|(key, _)| key.as_str());
if let Some(child) = &self.parent {
Box::new(iter.chain(child.keys()))
} else {
Box::new(iter)
}
}
}
Is there a alternative way to write the keys() implementation which doesn't allocate on the heap or use dynamic dispatch?
I am thinking of the following:
impl Struct1 {
fn keys<'a>(&'a self) -> impl Iterator<Item = &'a str> {
let iter = self.0.iter().map(|(key, _)| key.as_str());
if let Some(child) = &self.1 {
Either2::A(iter.chain(child.keys()))
} else {
Either2::B(iter)
}
}
}
pub enum Either2<A, B> {
A(A),
B(B),
}
impl<T, A: Iterator<Item = T>, B: Iterator<Item = T>> Iterator for Either2<A, B> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
match self {
Self::A(a) => a.next(),
Self::B(b) => b.next(),
}
}
}
Unfortunately this does not compile due to there being a recursive opaque type here impl Iterator<Item = &'a str>. And I can see why as the Either2::A is needed for the opaque type but also uses the opaque type.
Is there a way I could restructure the impl ... type reference to be recursive aware (possibly by using a type statement)? Or is there another way to rewrite the whole function to get it to work that doesn't involve intermediately collecting (and allocating) into a vec?