Skip to content

Feature proposal: Implement PeekingNext on std::vec::IntoIter & more #1045

@cchudant

Description

@cchudant

Current PeekingNext trait is only implemented for std iterators that can be copied easily. This is done using the peeking_next_by_clone! macro in the implementation, and affects:

  • ::std::slice::Iter for Vec/Slices/arrays iterators by ref.
  • ::std::str::Chars, ::std::str::CharIndices, ::std::str::Bytes for String/str iterators by ref
  • ::std::option::Iter, ::std::result::Iter for option/result iterators by ref.
  • ::std::iter::Empty empty iterator, and ::std::iter::Rev combinator.
  • alloc::collections::linked_list::Iter for std linkedlist iterator by ref.
  • alloc::collections::vec_deque::Iter for std vecdeque iterator by ref.

These all are implemented by cloning the iterator everytime next is called, which means that you can't use this trick for all of the owned and mut variants of these std iterators.

The missing PeekingNext implementations on the std iterators, particularily std::vec::IntoIter, makes peeking_next_while and other PeekingNext apis sometimes require put_back/peekable where we would not ideally need it.

let operations: Vec<Operation> = todo!();
let ordered_operation_events: Vec<Event> = todo!();
// ordered_operation_events is ordered so that for each operation, there are 0 or multiple consecutive events associated with it in ordered_operation_events.

let ordered_operation_events = ordered_operation_events.into_iter().peekable(); // right now you have to use .peekable() here, which is redundant

// put back the events into the operation objects
for (i, operation) in operations.iter_mut().enumerate() {
  operation.events.clear();
  operation.events.extend(ordered_operation_events.peeking_take_while(|ev| ev.operation_index == i)); 
}

This .peekable() combinator is a shame, because in theory we don't really have to do that. The IntoIter implementation knows (at least internally) which item it's going to return next. It's not a huge deal, but I've run into this a number of times, and it has bothered me enough to create this issue, I guess.

There is actually a way to get the next element in the IntoIter; using iter.as_slice()

It would work like this:

impl<I> PeekingNext for std::vec::IntoIter {
  fn peeking_next<F: FnOnce(&Self::Item) -> bool>(&mut self, accept: F) -> Option<Self::Item> {
    if accept(self.as_slice().first()) {
      self.next()
    }
  }
}

This way, it's actually possible to implement PeekingNext for all of these iterators:

Other that unfortunately require unstable features

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions