Scanmut 0.2.0 - efficient Vec mutation

https://crates.io/crates/scanmut

Scanmut is a library adding two types for mutating a Vec; Inserter and Remover. These are some quite versatile operators, allowing you to insert/remove multiple elements in a single scan over the Vec. You can use this to do things like efficiently inserting a slice, draining conditionally, or accessing the underlying Vec elements while you are mutating.

There is one caveat though; the Inserter requires monotonically non-increasing indices while the Remover requires monotonically increasing indices.

Besides the base types, there's a handful extension methods building on top of those with common stuff like inserting a slice or iterator.

The library has no dependencies and is no-std compatible.

After this, I got inspired to extend and improve the library, so it's slightly leaner now and much more thoroughly tested than 0.1.

2 comments · 93% upvoted · other discussions

comments

tending

Questions about your examples:

  • As a newb, not sure what cloned is? Familiar with clone.
  • I most commonly want to do this when I'm evaluating a predicate for every element. It's rare I know the exact indexes I want up front. Is there a way to do that?
Noctune [OP]

As a newb, not sure what cloned is? Familiar with clone.

This method: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.cloned

This is neccessary because [1, 2, 3].iter() is an iterator of &usize and I need them to be an iterator of usize. It's equivalent to iter.map(|item| item.clone()).

I most commonly want to do this when I'm evaluating a predicate for every element. It's rare I know the exact indexes I want up front. Is there a way to do that?

Like this unstable function?: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.drain_filter

It's possible, but I now realize it's a bit ugly. Something like this:

let mut remover = Remover::new(&mut vec); while let Some(current) = remover.current() { if predicate(current) { remover.remove(); } else { let index = remover.index(); remover.move_to(index + 1); } }

I think I'll work on adding something to support this more directly.