Deal with struct and borrowing

Hello,

I write Rust code since three years, but I have some issues with some code architecture. I'm writing a graphic user interface with egui crate.

There is some information about my context :

  • I have a JSON which represent expected interface to draw (like html)
  • egui input text take a mutable string as parameter (which is modified when input text modified)

So, I have a struct containing the expected interface representation and hashmap of string values to give to egui text inputs. Example:


struct Interface {
    values: HashMap<String, String>,
    inputs: Vec<String>,
}

impl Interface {
    fn new() -> Self {
        // These values are determines from the expected interface representation
        let mut values = HashMap::new();
        values.insert("foo".to_string(), "FOO".to_string());
        values.insert("bar".to_string(), "BAR".to_string());
        values.insert("baz".to_string(), "BAZ".to_string());
        let inputs = vec!["foo".to_string(), "bar".to_string(), "baz".to_string()];

        Self { values, inputs }
    }

    fn draw(&mut self, ui: &mut egui::Ui) {
        // To draw the text inpit, I have to iterate over them
        for input_name in self.inputs.iter() {
            // In my real code I have multiple type of thigs to draw (text input, label, image, buttons, checkbox, etc.)
            // So I use methods. BUT "cannot borrow `*self` as mutable because it is also borrowed as immutable"
            self.draw_input(ui, input_name)
        }
    }

    fn draw_input(&mut self, ui: &mut egui::Ui, name: &str) {
        let value = self.values.get_mut(name).unwrap();
        ui.add(egui::TextEdit::singleline(value));
    }
}
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
  --> src/main.rs:25:13
   |
24 |         for input_name in self.inputs.iter() {
   |                           ------------------
   |                           |
   |                           immutable borrow occurs here
   |                           immutable borrow later used here
25 |             self.draw_input(ui, input_name)
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here

Call to self.draw_input(ui, input_name) produce error because I already have self.inputs.iter().

I can replace my "sub method" by direct usage of struc attribute like this :

            // self.draw_input(ui, input_name)
            let value = self.values.get_mut(input_name).unwrap();
            ui.add(egui::TextEdit::singleline(value));

But in my real code, I have multiple cases and draw method will be huge.

How can I deal with that ?

Thanks !

The general problem can be called "interprocedural conflicts" and there is an article on it here. The approach you mentioned is one of the covered work-arounds, inlining. It covers a few more and I recommend reading it.

The other workarounds are possibilities, as is temporarily removing self.inputs from self (using std::mem::take) if it's unneeded in the other methods during the iteration (then putting it back afterwards). What is going to work best depends on what exactly the methods you're calling in the loop do (what parts of Self they need access to, et cetra).

1 Like
fn draw(&mut self, ui: &mut egui::Ui) {
    for id in 0..self.inputs.len() {
        self.draw_input(ui, id)
    }
}

fn draw_input(&mut self, ui: &mut egui::Ui, id: usize) {
    let value = self.values.get_mut(&self.inputs[id]).unwrap();
    ui.add(egui::TextEdit::singleline(value));
}

Thanks ! I will study all of that

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.