2

I'm trying to implement an iterator adapter that is similar to C++ ranges' std::views::split, but I got lost in the Rust type system and lifetimes.

More specifically, I want to have a function iter_split that takes an iterator and a separator and produces a series of iterators such that a new iterator starts when the original iterator outputs the separator. It's better to illustrate it by the following example:

let v = vec![1, 2, 3, 0, 1, 2, 0, 4, 5, 0];
for inner_iter in iter_split(v.iter(), &0) {
    inner_iter.for_each(|x| print!("{} ", x));
    println!();
}

The expected output is

1 2 3 
1 2 
4 5 

I tried to define it as follows (it's more like a pseudocode at this point):

struct Split<I, T> {
    iter: I,
    sep: T,
}

impl<I, T> Split<I, T> {
    fn new(iter: I, sep: T) -> Split<I, T> {
        Split { iter, sep }
    }
}

impl<I, T> Iterator for Split<I, T>
where
    I: Iterator<Item = T>,
    T: std::cmp::PartialEq,
{
    type Item = /* ??? */;

    fn next(&mut self) -> Option<Self::Item> {
        let inner_iter = self.iter.by_ref().take_while(|x| x != self.sep).peekable();
        match inner_iter.peek() {
            None => None,
            Some(_) => Some(inner_iter),
        }
    }
}

fn iter_split<'a, I, T>(iter: I, sep: T) -> Split<I, T>
where
    I: Iterator<Item = T>,
    T: std::cmp::PartialEq,
{
    Split::new(iter, sep)
}

This approach has several issues:

  • I don't know what to write as the type for Item: it should be something like Peekable<TakeWhile<...>>, but since I pass the iterator (and the separator, technically) by reference, I should also take care of their lifetimes, and I'm not used to them yet.
  • I can't use a closure since I won't be able to return it just like it. This, however, can at least be alleviated by defining another adaptor that behaves like TakeWhile but instead of checking a predicate, compares the output with the separator.

It seems that I probably can solve some of them using Box, but I'm not sure. Can I do it without boxes?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
nightuser
  • 664
  • 4
  • 13
  • https://docs.rs/itertools/latest/itertools/trait.Itertools.html#method.group_by – Shepmaster Dec 06 '21 at 19:33
  • Probably a duplicate of [How do I write an iterator that returns references to itself?](https://stackoverflow.com/q/30422177/155423) / [Can I write an Iterator that mutates itself and then yields a reference into itself?](https://stackoverflow.com/q/25702909/155423) – Shepmaster Dec 06 '21 at 19:38
  • 1
    @Shepmaster thanks, I completely forgot about the `group_by`. I'll probably look into the code. Regarding your second point, it seems that this question is indeed a duplicate of the one you linked. – nightuser Dec 06 '21 at 19:45

0 Answers0