-
Notifications
You must be signed in to change notification settings - Fork 338
Description
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::Iterfor Vec/Slices/arrays iterators by ref.::std::str::Chars,::std::str::CharIndices,::std::str::Bytesfor String/str iterators by ref::std::option::Iter,::std::result::Iterfor option/result iterators by ref.::std::iter::Emptyempty iterator, and::std::iter::Revcombinator.alloc::collections::linked_list::Iterfor std linkedlist iterator by ref.alloc::collections::vec_deque::Iterfor 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:
std::vec::IntoIter(Vec owned iterator) via [iter.as_slice])https://doc.rust-lang.org/std/vec/struct.IntoIter.html#method.as_slice)std::vec::Drain(Vec drain iterator) via [iter.as_slice])https://doc.rust-lang.org/std/vec/struct.Drain.html#method.as_slice)- This one is really exciting, because when
drain_iter.keep_restwill be stable, this would allow us to use thepeeking_take_whileAPI while keeping the peeked item in the source vec. Really cool!
- This one is really exciting, because when
std::string::Drain(String drain iterator) viaas_str.std::array::IntoIter([T; N] owned iterator) viaas_slice
Other that unfortunately require unstable features
- VecDeque into iter and iter mut require (as_slices) which is unstable 😔
std::slice::IterMut(&mut [T] mut iterator, vec mut iterator) via [iter.as_mut_slice])https://doc.rust-lang.org/std/slice/struct.IterMut.html#method.as_mut_slice)