Please consider the following program (it's a minimized example, so don't get hung up on the fact what I'm trying to do here could be better achieved with a HashMap<u32, Vec<MyVariant>>
):
#[derive(PartialEq)]
enum MyVariant {
None,
SomeValue,
SomeOtherValue,
Aggregate(Vec<MyVariant>)
}
impl MyVariant {
pub fn with(self, other: Self) -> Self {
if self == Self::None {
other
} else if other == Self::None {
self
} else {
Self::Aggregate(vec![self, other])
}
}
}
fn add_variant(vec: &mut Vec<(u32, MyVariant)>, id: u32, variant: MyVariant) {
if let Some(item) = vec.iter_mut().find(|item| item.0 == id) {
*item = (id, item.1.with(variant));
} else {
vec.push((id, variant));
}
}
fn main() {
let mut vec: Vec<(u32, MyVariant)> = Vec::new();
add_variant(&mut vec, 1, MyVariant::SomeValue);
add_variant(&mut vec, 2, MyVariant::None);
add_variant(&mut vec, 1, MyVariant::SomeOtherValue);
}
This will fail at *item = (id, item.1.with(variant))
, because item
is a shared mutable reference, so item.1
cannot be moved into the with()
method. I tried to get a reference using an index into the vector, but that doesn't solve the underlying problem.
Basically, what I want is a method that will temporarily move a value out of a mutable vector, and replaces it with a new, derived value. Maybe something like:
impl<T> Vec<T> {
/// Replaces the item at `index` with a new item produced by `replacer`.
/// `replacer` receives the old item as argument.
fn replace_with(&mut self, index: usize, replacer: Fn(T) -> T);
}
But I cannot find a method like the above, or any technique that does achieve the same intent.
I suspect I might be looking at it from the wrong angle, so any ideas? Thanks!