I have some code where expensive computations need to be performed lazily. So I have a set of values which are either raw (RawValue
) or derived from raw (Value
), where derivation can be expensive, and I combine the values in an enum of RawValue
and Value
, and hold that enum (InternalValue
) in an Option<HashMap<String, InternalValue>>
. The idea is that when I want to process some value and find that it's raw, I want to use it to derive a value and store it back into the hashmap so it can be used without re-derivation next time. I can't seem to get the exact syntax for this right - the compiler tells me I can't borrow as mutable, but I can't see why not other than that I'm using some wrong approach to do it.
use std::collections::HashMap;
#[derive(Debug, Clone, PartialEq)]
pub enum RawValue {
TBD,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Value<'a> {
Integer(i64),
Sequence(&'a Vec<Value<'a>>),
}
#[derive(Debug, Clone, PartialEq)]
pub enum InternalValue<'a> {
Base(Value<'a>),
ToBeDerived(RawValue),
}
#[derive(Debug, Clone, PartialEq)]
pub struct Thing<'a> {
data: Option<HashMap<String, InternalValue<'a>>>,
}
fn expensive_derivation(_rv: &RawValue) -> InternalValue {
InternalValue::Base(Value::Integer(-1))
}
impl<'a> Thing<'a> {
fn process(&mut self, s: &str) {
assert!(self.data.is_some());
match self.data.as_ref().as_mut().unwrap().get(s) {
None => {},
Some(v) => {
match v {
InternalValue::ToBeDerived(rv) => {
// Do something to map rv to a Value (potentially expensive),
// then store it back into the hashmap to avoid rederivation
let iv = expensive_derivation(&rv);
self.data.as_ref().as_mut().unwrap().insert(s.to_string(), iv);
},
_ => {}
}
}
}
}
}
Errors:
Compiling playground v0.0.1 (/playground)
error[E0596]: cannot borrow data in a `&` reference as mutable
--> src/lib.rs:41:25
|
41 | self.data.as_ref().as_mut().unwrap().insert(s.to_string(), iv);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0596`.
error: could not compile `playground`.
To learn more, run the command again with --verbose.