I tried to write an application where the user can create objects from templates.
In my dreams the code looks like this:
struct DataTemplate {
tmp: u32,
}
struct Data<'a> {
name: &'a str,
tmp: u32,
}
struct Consumer<'a> {
items: Vec<Data<'a>>,
}
struct Library {
items: Vec<DataTemplate>,
}
struct Application<'a> {
library: Library,
consumer: Consumer<'a>,
}
impl DataTemplate {
fn new(data: u32) -> Self {
DataTemplate { tmp: data }
}
}
impl<'a> Data<'a> {
fn new(name: &'a str, tmp: u32) -> Self {
Data { name, tmp }
}
fn from_template(template: &DataTemplate, name: &'a str) -> Self {
Data::new(name, template.tmp)
}
}
impl<'a> Consumer<'a> {
fn new() -> Self {
Consumer { items: vec![] }
}
fn consume(&mut self, data: Data<'a>) {
self.items.push(data);
}
}
impl Library {
fn new() -> Self {
Library { items: vec![] }
}
fn add(&mut self, d: DataTemplate) {
self.items.push(d);
}
fn get(&self, index: usize) -> &DataTemplate {
&self.items[index]
}
}
impl<'a> Application<'a> {
fn new() -> Self {
Application {
library: Library::new(),
consumer: Consumer::new(),
}
}
fn get_library(&self) -> &Library {
&self.library
}
fn get_library_mut(&mut self) -> &mut Library {
&mut self.library
}
fn get_consumer_mut(&mut self) -> &mut Consumer<'a> {
&mut self.consumer
}
}
fn main() {
let mut app = Application::new();
use_it(&mut app);
}
fn use_it(app: &mut Application) {
app.get_library_mut().add(DataTemplate::new(1));
app.get_library_mut().add(DataTemplate::new(2));
app.get_library_mut().add(DataTemplate::new(3));
let item = app.get_library().get(1);
app.get_consumer_mut()
.consume(Data::from_template(item, "hi"));
}
The problem is in the use_it
function:
error[E0502]: cannot borrow `*app` as mutable because it is also borrowed as immutable
--> src/main.rs:89:5
|
88 | let item = app.get_library().get(1);
| --- immutable borrow occurs here
89 | app.get_consumer_mut()
| ^^^ mutable borrow occurs here
90 | .consume(Data::from_template(item, "hi"));
91 | }
| - immutable borrow ends here
I need to get an immutable reference to the app (let item = app.get_library()
) to get the template, and then after creating the data item from the template, I have to add it to the consumer in the application, now mutable of course (app.get_consumer_mut()
).
Is there any common solution for a problem like this, or is this entire idea just not the Rust way?
You will need to make sure that you drop the reference to the library before you try to access the consumer. For example:
let data = Data::from_template(app.get_library().get(1), "hi");
app.get_consumer_mut().consume(data);