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?