I have an iterator trait which uses Generic Associated Types to allow the returned values to reference data owned by the iterator:
pub trait MyIterator {
type T<'a>
where
Self: 'a;
fn next<'b>(&'b mut self) -> Option<Self::T<'b>>;
}
An example implementation looks like this:
struct FooIterator<'counter> {
data: Vec<String>,
counter: &'counter AtomicU32,
index: usize
}
impl<'counter> MyIterator for FooIterator<'counter> {
type T<'d> = &'d str
where
Self: 'd;
fn next<'e>(&'e mut self) -> Option<Self::T<'e>> {
self.counter.fetch_add(1, Ordering::SeqCst);
self.index += 1;
Some(&self.data[self.index])
}
}
Now, I would like to have a factory that returns impl MyIterator objects without making the implementing types public. However, I can't figure out how to write the lifetimes.
My first attempt was:
struct Factory {
data: Vec<String>,
counter: AtomicU32,
}
impl Factory {
fn new() -> Self {
Factory {
data: vec!["a".to_string(), "b".to_string(), "c".to_string(), "d".to_string()],
counter: AtomicU32::new(0),
}
}
fn create<'f>(&'f self) -> impl MyIterator<T<'_> = &'_ str> {
FooIterator {
data: self.data.clone(),
counter: &self.counter,
index: 0
}
}
}
However, that results in a double borrowing error when trying to use the returned iterator, as can be seen here: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=6490de8f21539537764d8f628454c5c1
Next I tried using a Higher Rank Trait Bound, which seems like it should work, but I can't get the following to compile, because it seems that 'g is not in scope in the where clause (https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=beb46184de6f96bf83b64e838da4a335):
fn create<'f>(&'f self) -> impl for<'g> MyIterator<T<'g> = &'g str> + 'f where 'f: 'g {
FooIterator {
data: self.data.clone(),
counter: &self.counter,
index: 0
}
}
Without the return impl MyIterator the code works fine, but I don't want to expose the FooIterator type. See this playground: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=2c595c136077791a692ea6e0a41c057c