Infinitive iteration with back option

I have some vector, and want to navigate there +1/-1 directions, and when the end of array reached, switch to the begin of index (on next) and same for back action - but to the last one (e.g. by len).

As found in docs, I should create new Iterator for every new session, but I won't :slight_smile:
Is any completed trait to not implement my own bugs for this trivial feature?

  • p.s. rev is not an option for back action because reorder the index, when I want just to make search in text buffer like Firefox does by cmd+F action.

try cycle?

Iterator in std::iter - Rust


Example:

2 Likes

Thank you, almost done, but:

assert_eq!(it.next(), Some(&1)); // user at #1 position (by next)
    
let mut it = a.iter().rev().cycle(); // user activates back
assert_eq!(it.next(), Some(&3)); // index always started from end, not from #1 to #0

don't know how to explain, but I need the prev as opposite to next, not reverse all the index..

you mean ++/-- in cpp, like this?

for(;;) {
  if(forward) {
    iter++;
  }else{
    iter--;
  }
}

But I not found iter-- you want in std::iter.

1 Like

You probably want to implement your own DoubleEndedIterator for the indices. Or at least, I don't know a way to do it with what's in std offhand. (And I didn't check itertools.)

I'm not sure what the exact behaviors you want are though.

// Say we're cycling through 0..3

assert_eq!(iter.next_back(), Some(three_or_zero));

// ...

assert_eq!(iter.next(), Some(2));
assert_eq!(iter.next_back(), Some(two_or_one));
2 Likes

I think he's looking for BidirectionalIterator in C++, which I don't think Rust have in std.

2 Likes

you mean ++/-- in cpp, like this?

Yes, meant something like increment/decrement for the current state

DoubleEndedIterator is finitive, and return None on iteration complete. I exactly would like to use Cycle as 99% does that I want, but not the back/next_back method.

Thoughts make 2 holders for Cycle - 1 default and 1 reverse, plus current object copy:

struct Iter {
    next: Cycle<IntoIter<Value>>,
    prev: Cycle<IntoIter<Value>>, // reverse
    state: Value // current
}

impl Iter {
    fn forward(&self) {} // do `next()` for `next` until current Value, then `next` one more
    fn back(&self) {} // same for `prev`
}

maybe screwed idea, because newbie, I think it's trash, but.. should work

Thanks for your links.

Maybe iterator trait is just low-level trait, and I should extend it with the app logic as above, even it looks trivial to be not implemented yet.

Actually, you've found one of the biggest difference of fundamental concepts between C++ and Rust!

Conceptually in C++ iterators are cursors pointing something in somewhere. You can move the cursor forward, sometimes backward, and get the value currently pointed by the cursor.

But in Rust iterators are some kind of queue conceptually. You can pop values from its front, sometimes from its back. It doesn't make sense to get the value the iterator currently pointing as the queue logically holds the entire values not popped yet. You can't pop same value twice from the queue as it may violate the ownership rule.

6 Likes

I don’t know any particular trait to set an example… but as one point of comparison, you could look at the (unstable) cursor API of std::collections::linked_list, I guess?

3 Likes

Thanks, guys

I won't use nightly version for linked_list just because upgrade required for app users.

Finally, created this function in few rows.
If somebody want working example, here is the source:

struct Cursor {
    current: usize,
    last: usize,
}

impl Cursor {
    pub fn back(&mut self) {
        self.current = if self.current > 0 {
            self.current - 1
        } else {
            self.last
        }
    }

    pub fn next(&mut self) {
        self.current = if self.current < self.last {
            self.current + 1
        } else {
            0
        }
    }

    pub fn as_index(&self) -> usize {
        if self.current > 0 {
            self.current - 1
        } else {
            0
        }
    }
}

pub struct Model<T> {
    cursor: Cursor,
    vector: Vec<T>,
}

impl<T> Model<T> {
    pub fn new(vector: Vec<T>) -> Self {
        Self {
            cursor: Cursor {
                current: 0,
                last: vector.len(),
            },
            vector,
        }
    }

    pub fn back(&mut self) -> Option<&T> {
        self.cursor.back();
        self.vector.get(self.cursor.as_index())
    }

    pub fn next(&mut self) -> Option<&T> {
        self.cursor.next();
        self.vector.get(self.cursor.as_index())
    }
}
  • it will infinitively move the Cursor by one step for Vec<T> , according to direction
  • should I make it as the new crate? surprise me if does not exist yet.
1 Like

I've found two crates for bidirectional iterators, just in case you might find them helpful:

You're welcome to publish your own. I think it's a nice and useful thing to have.

1 Like

I think the closest counterpart to Rust iterators in C++ is the ranges library. Although it still uses the begin/end "cursor" interface at the lowest levels, as far as I understand.

1 Like