Skip to content

Some bounds in circular_tuple_windows are unnecessary (I think) #1084

@sgtatham

Description

@sgtatham

The circular_tuple_windows method requires the input iterator to be Clone and also ExactSizeIterator, as well as the item type being Clone.

I recently wanted circular tuple windows of size 2, on an iterator which did not have those additional traits. I implemented it myself using the following code (far less generic than yours, but enough for my purpose at the time), which only requires the item type to be Clone and the iterator itself to be Sized. Extract the first item from the iterator (if any), clone it and put it at the end again (if any), and then take ordinary tuple_windows of the result.

pub trait MyItertools: Iterator {
    fn cyclic_pairs(mut self) -> impl Iterator<Item = (Self::Item, Self::Item)>
    where
        Self::Item: Clone,
        Self: Sized,
    {
        let first = self.next();
        let first_again = first.clone(); // even if it's None
        first
            .into_iter()
            .chain(self)
            .chain(first_again.into_iter())
            .tuple_windows()
    }
}

An extended version of the same technique would surely work to implement circular tuple windows of other sizes without those additional constraints on the iterator.

It's not quite as simple as extending this implementation, because of edge cases when the input list is very short. (If I try to make tuple windows of length 4 by extracting up to 3 initial elements and chaining another copy of them at the end, then I get no output windows at all for a length-1 list, whereas the official circular_tuple_windows would give a tuple (a,a,a,a), so some special cases would be needed to decide how many copies of the initial elements to chain at the end.)

So, would it be possible to replace the implementation of circular_tuple_windows so as to avoid those extra requirements?

If this seems like a good idea in principle, and has no subtle gotchas that you can foresee, I'd be happy to attempt the main implementation. I don't know that my Rust is good enough to get all the outlying parts right, though. (For example, you'd presumably want to propagate ExactSizeIterator from the input if the input has it, and no doubt there are other things of that kind I haven't thought of.)

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