I’m writing a “coiterator” trait in rust (and a bunch of adapters for it):
pub trait Consumer<Item> {
type Output;
fn eat(&mut self, item: Item) -> Option<()>;
fn finish(self) -> Self::Output;
fn pair_with_iterator(mut self, iterator: impl IntoIterator<Item = Item>) -> Self::Output
where
Self: Sized,
{
for item in iterator {
if self.eat(item).is_none() {
break;
}
}
self.finish()
}
...
}
Think of eat
as the dual of Iterator::next
and finish
as the dual of IntoIterator::into_iter
. Now, if I have a Consumer<T>
and a Consumer<&T>
then I can combine them to process the same items in parallel. For example, you might have one type that collects an iterator into a HashSet
and another that just counts the number of items. I know how to write that using just iterators but consider the following general implementation:
struct Parallel<C, D> {
by_move: C,
by_ref: D,
}
// this is wrong, T should not need to live for 'static
impl<T: 'static, C: Consumer<T>, D: for<'a> Consumer<&'a T>> Consumer<T> for Parallel<C, D> {
type Output = (C::Output, <D as Consumer<&'static T>>::Output);
fn eat(&mut self, item: T) -> Option<()> {
self.by_ref.eat(&item)?;
self.by_move.eat(item)
}
fn finish(self) -> Self::Output {
(self.by_move.finish(), self.by_ref.finish())
}
}
But as in the comment, the lifetime bounds are not what they should be. The underlying issue is that there’s no way (I think) to represent that <D as Consumer<&'a T>>::Output
should not depend on the lifetime 'a
. I have also considered the following fixes, but I don’t think any of these work:
- Make
Item
an associated type rather than an input type toConsumer
. Then you just cannot haveD
that accepts&'a T
for multiple'a
and I don’t see how to implementeat
forParallel
. D as Consumer<&'static T>
could have, instead of'static
, whatever the lifetime ofT
is, but I again think there’s no way to express that. Similarly for a hypothetical'zero
or'temp
lifetime (the opposite of'static
) so thatT: 'zero
would be automatic for anyT
.- Replace
'static
by some generic lifetime'b
, but then it would be unconstrained.
Is there a way to write a more general version of this impl
that doesn’t need the bound on T
?