0

I'm trying to figure out how to handle lifetimes properly to allow for a zero-copy group by iterator. The plan is to have the GroupBy struct own a peekable iterator, check the next element, and then yield a GroupByInner struct which iterates from a mutable reference of that iterator while the peeked key is true. However, I'm fighting lifetime issues and am not sure how to proceed.

I've attached some of the code below

use std::iter::Iterator;
use std::iter::Peekable;

struct GroupByInner<'a, I, K, V>
where
    I: 'a + Iterator<Item = (K, V)>,
    K: PartialEq,
{
    key: K,
    it: &'a mut Peekable<I>,
}

impl<'a, I, K, V> GroupByInner<'a, I, K, V>
where
    I: 'a + Iterator<Item = (K, V)>,
    K: PartialEq + Clone,
{
    fn new(p: &'a mut Peekable<I>) -> Option<Self> {
        let ok = p.peek().map(|&(ref k, _)| k.clone());
        match ok {
            Some(k) => Some(GroupByInner { key: k, it: p }),
            None => None,
        }
    }
}

impl<'a, I, K, V> Iterator for GroupByInner<'a, I, K, V>
where
    I: 'a + Iterator<Item = (K, V)>,
    K: PartialEq,
{
    type Item = V;

    fn next(&mut self) -> Option<Self::Item> {
        let isMatched = match self.it.peek() {
            Some(&(ref k, _)) => k == &self.key,
            _ => false,
        };
        if isMatched {
            self.it.next().map(|x| x.1)
        } else {
            None
        }
    }
}

#[test]
fn test_GBI() {
    let v = vec![(1, 2), (1, 3), (1, 4), (2, 2), (3, 2)];
    let mut it = v.into_iter().peekable();
    for _ in 0..2 {
        let gbi = GroupByInner::new(&mut it).unwrap();
        for (i, v) in gbi.enumerate() {
            assert_eq!(i, v - 2);
        }
    }
}

struct GroupBy<I, K, V>
where
    I: Iterator<Item = (K, V)>,
    K: PartialEq,
{
    it: Peekable<I>,
}

impl<I, K, V> GroupBy<I, K, V>
where
    I: Iterator<Item = (K, V)>,
    K: PartialEq,
{
    fn new(it: I) -> Self {
        GroupBy::<I, K, V> { it: it.peekable() }
    }
}

impl<'a, I, K, V> Iterator for &'a mut GroupBy<I, K, V>
where
    I: Iterator<Item = (K, V)>,
    K: PartialEq + Clone,
{
    type Item = GroupByInner<'a, I, K, V>;

    fn next(&mut self) -> Option<Self::Item> {
        GroupByInner::new(&mut self.it)
    }
}

#[test]
fn test_GB() {
    let v = vec![(1, 2), (1, 3), (1, 4), (2, 2), (3, 2)];
    let mut it = v.into_iter();
    for sit in GroupBy::new(it) {
        for (i, v) in sit.enumerate() {
            assert_eq!(i, v - 2);
        }
    }
}

fn main() {}

This blows up with the following error:

error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
  --> src/main.rs:85:27
   |
85 |         GroupByInner::new(&mut self.it)
   |                           ^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 84:45...
  --> src/main.rs:84:46
   |
84 |       fn next(&mut self) -> Option<Self::Item> {
   |  ______________________________________________^
85 | |         GroupByInner::new(&mut self.it)
86 | |     }
   | |_____^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:85:27
   |
85 |         GroupByInner::new(&mut self.it)
   |                           ^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the body at 84:45...
  --> src/main.rs:84:46
   |
84 |       fn next(&mut self) -> Option<Self::Item> {
   |  ______________________________________________^
85 | |         GroupByInner::new(&mut self.it)
86 | |     }
   | |_____^
note: ...so that types are compatible (expected std::iter::Iterator, found std::iter::Iterator)
  --> src/main.rs:84:46
   |
84 |       fn next(&mut self) -> Option<Self::Item> {
   |  ______________________________________________^
85 | |         GroupByInner::new(&mut self.it)
86 | |     }
   | |_____^

How does one go about this? Am I doing it all wrong?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Refefer
  • 541
  • 4
  • 11
  • Not sure why you were having issues. Added the two imports and an empty main function. – Refefer Jun 20 '17 at 17:32
  • *Not sure why you were having issues* — because [you changed your code](https://stackoverflow.com/posts/44658098/revisions) between the different versions. (`&'a`) – Shepmaster Jun 20 '17 at 17:38
  • You may be be interested in Itertools' [`group_by`](https://docs.rs/itertools/0.6.0/itertools/trait.Itertools.html#method.group_by) – Shepmaster Jun 20 '17 at 18:00
  • @Refefer, BTW, if this code worked, in the case when you didn't iterate over first group and just skipped to the next, iterator will not advance and you'll end up with the first group again. – red75prime Jun 20 '17 at 18:17

0 Answers0