I find myself rewriting the logic for adjusting the value of an index into a vector (with wrapping, or with rejection of movement beyond the ends), for the Nth time.
If you want to change the index by a negative amount, you end up converting back and forth between signed and unsigned types ... or you can create an enum to distinguish the forward and back directions, and then you have to deal with the behaviour at the boundaries.
It's fiddly and distracting. So I'm wondering if there is a neat idiom for this kind of thing, or some utilities that make it less fiddly.
In other words, can you suggest a better way of writing something like this:
Since the wrapper implements both Deref and DerefMut, you can use it like a regular Vec:
let mut ev = ExtVec::new();
ev.push(1);
ev.push(2);
let moved = ev.move_index(17, -98);
let x = ev[moved];
For a more general case, you could create a trait and implement it for Vec. This is known as the Extension Traits pattern. While useful, it does have some downsides, so it’s worth exploring more about this technique in various posts and discussions.
Wow, how miserably I failed to describe what my issue is!
All I want is a clean way of writing
(x + dx).rem_euclid(size)
for an unsigned type.
I only mentioned Vec and indices, because they are what imposes the need to do this with an unsigned type, and I expected legions of other people to have faced the need to wrap around indices before and thus have been irked by how ugly this triviality gets.
This is a question about a trivial mathematical operation, complicated be the introduction of unsigned types, rather than being about interfaces behind which that operation might be hidden.
Oooh, the *_signed methods had escaped my notice thus far. Thanks!
But I don't see one that helps me get something that is any more robust and concise than converting everything to isize, doing the calculation and converting back to usize:
fn wrap(x: usize, dx: isize, size: usize) -> usize {
(x as isize + dx).rem_euclid(size as isize) as usize
}