Pauan/rust-signals

Update an element inside MutableVec?

Closed this issue · 2 comments

Is it currently possible to modify an element of a MutableVec in place? Right now, it seems the only way to achieve this would be to clone the element and then replace it with set, e.g.:

let lock = my_mutable_vec.lock();
let mut item = lock.get(1).map(|inner| inner.clone()).unwrap();
item.value = new_value;
lock.set(1, old);

Would it be possible to add an update method which also sends a VecDiff::UpdateAt to the connected signals? Then we could just write:

my_mutable_vec.lock().update(1, |item| item.value = new_value);
Pauan commented

Vec and slice don't have an update method, because it's actually really tricky to implement in a safe way (if the closure panics).

I could implement get_mut with just a usize, but I'm not sure if that's future-compatible with SliceIndex.

And I think it's a bit of a footgun to implement get_mut, because it's not clear to the user that it's actually cloning the value repeatedly.


Note that if you want to update an inner part of the element (like the value field in your example), then your best option is to make it into a Mutable:

struct Foo {
    value: Mutable<u32>,
}

struct Bar {
    foos: MutableVec<Arc<Foo>>,
}

Now you can easily do this:

let lock = bar.foos.lock_ref();
lock[1].value.set(new_value);

This is very idiomatic, and will generally be quite fast (since it gives you fine-grained updates). You can also store multiple Mutables in the struct (one Mutable per field), which is also very idiomatic. MutableVec and Mutable are designed to complement each other very well.

The Arc is optional, but it means that the _cloned methods will be very fast.

Thanks for the insights @Pauan