Hello everybody,
this is not a real problem because I know how to write code that works but to do that I have to avoid certain abstraction that I'd like to keep, so I am looking for suggestion about how to do this "the Rust way".
Basically I have an object that encapsulates a cache and a dependency from a library that uses data from that cache. I'd like to keep some data private and expose the functionality via methods but I get into the cannot borrow as mutable more than once. Here is a simplification of the code (DataContext
is from the external library):
use std::collections::HashMap;
struct EditContext {
cache: HashMap<usize, Resource>,
context: DataContext,
}
struct DataContext {
data: usize,
}
struct Resource {
pub data: usize,
}
impl EditContext {
pub fn new() -> Self {
EditContext {
cache: HashMap::new(),
context: DataContext { data: 0 },
}
}
pub fn get_resource(&mut self, resource_id: usize) -> &Resource {
if !self.cache.contains_key(&resource_id) {
self.cache.insert(resource_id, Resource { data: 42 });
}
self.cache.get(&resource_id).unwrap()
}
pub fn do_edit(&mut self, resource: &Resource) {
self.context.do_something(resource);
}
}
impl DataContext {
pub fn do_something(&mut self, resource: &Resource) {
self.data = resource.data;
println!("data: {}", self.data);
}
}
fn main() {
let mut edit = EditContext::new();
let resource_id = 0;
let resource = edit.get_resource(0);
// The error happens on the next line.
edit.do_edit(resource);
}
Calling do_edit
is perfectly safe because the only way of invalidating the cache is by calling get
but the compiler does not know that. I can make the code working by making some members public and then replacing the code in main direct access:
if !edit.cache.contains_key(&resource_id) {
edit.cache.insert(resource_id, Resource { data: 42 });
}
let resource = edit.cache.get(&resource_id).unwrap();
edit.context.do_something(resource);
but it would be much better to be able to call a sequence of methods on edit
.
Suggestions? Thanks!