How to resolve "error[E0499]: cannot borrow ... as mutable more than once at a time" in this case

Hi, folks!

I'm trying do this:

    fn main() {
        let mut indexer_customer = IndexerCustomer::new();

        let customer = Customer::new(1, "Martin".to_string(), "New York".to_string());
        indexer_customer.insert(customer);

        let customer = Customer::new(2, "Johnny".to_string(), "Austin".to_string());
        indexer_customer.insert(customer);
    }

But I'm getting the error:

error[E0499]: cannot borrow `indexer_customer` as mutable more than once at a time
  --> src/main.rs:52:5
   |
49 |     indexer_customer.insert(customer);
   |     ---------------- first mutable borrow occurs here
...
52 |     indexer_customer.insert(customer);
   |     ^^^^^^^^^^^^^^^^
   |     |
   |     second mutable borrow occurs here
   |     first borrow later used here

error: aborting due to previous error

I can't understand where the borrow is occurring. I'm not using "&" explicitly.

The method insert is:

pub fn insert(&'a mut self, customer: Customer) {
        let customer_opt = match self.index_code.entry(customer.code) {
            Entry::Occupied(_) => None,
            Entry::Vacant(e) => Some(&*e.insert(customer)),
        };
        match customer_opt {
            Some(customer) => {
                self.index_name.insert(&customer.name, &customer);
                self.index_city.insert(&customer.city, &customer);
            }
            None => {}
        }
    }

The playground is here: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=391247b164b5c14c13222aa38a5e9d71

How I can resolve this error in this code?

I appreciate any help! Thank you.

This is due to the 'a in &'a mut self. You never want that because the 'a lifetime is guaranteed to contain the entire lifetime of the struct, which means borrowing self for the 'a lifetime borrows it at least until the end of the struct's lifetime. Remove it.

1 Like

After looking at your code closer, I see why the compiler led you astray: you are trying to create a self-referential struct.

When you have a lifetime <'a> on a struct, that lifetime denotes references to values stored outside of the struct. If you try to store a reference that points inside the struct rather than outside, you will run into a compiler error when the compiler notices you lied to it.

Use the key instead of a reference:

pub struct IndexerCustomer {
    index_code: BTreeMap<u32, Customer>,
    index_name: BTreeMap<String, u32>,
    index_city: BTreeMap<String, u32>,
}

impl IndexerCustomer {
    pub fn insert(&mut self, customer: Customer) {
        let customer_opt = match self.index_code.entry(customer.code) {
            Entry::Occupied(_) => None,
            Entry::Vacant(e) => Some(&*e.insert(customer)),
        };
        match customer_opt {
            Some(customer) => {
                self.index_name.insert(customer.name.clone(), customer.code);
                self.index_city.insert(customer.city.clone(), customer.code);
            }
            None => {}
        }
    }
}

playground

3 Likes

This also avoids any problems with "pointer invalidation" when the BTreeMap decides to move its internals around or reallocate.

This reference couldn't live past the next modification to the tree in C++ either.

First, thank you very much! I learned a lot with your explanation!

Well, Rust doesn’t allow self ref is very sad. My project is memory-critical over performance, then I need to avoid cloning always when possible. Your response inspired me to push the red button (aka Rc<>). And appears that work very fine too me… that’s the result:

What do you think?

pub struct IndexerCustomer {
    index_code: BTreeMap<u32, Rc<Customer>>,
    index_name: BTreeMap<Rc<String>, Rc<Customer>>,
    index_city: BTreeMap<Rc<String>, Rc<Customer>>,
}

impl IndexerCustomer {
    pub fn new() -> IndexerCustomer {
        IndexerCustomer {
            index_code: BTreeMap::new(),
            index_name: BTreeMap::new(),
            index_city: BTreeMap::new(),
        }
    }

    pub fn insert(&mut self, customer: Customer) {
        let customer_opt = match self.index_code.entry(customer.code) {
            Entry::Occupied(_) => None,
            Entry::Vacant(e) => Some(&*e.insert(Rc::new(customer))),
        };
        match customer_opt {
            Some(customer) => {
                self.index_name.insert(Rc::clone(&customer.name), Rc::clone(&customer));
                self.index_city.insert(Rc::clone(&customer.city), Rc::clone(&customer));
            }
            None => {}
        }
    }

The full playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=9cd371b7726dd85357c9534fe4da8406

I'm way out of my depth here, but I think Pin is supposed to enable self-referential structs?

The Pin type is a tool for helping you write correct unsafe code when writing self-referential structs. It doesn't allow you to do it safely.

1 Like

I would go as far as saying that Pin doesn't do anything. It's a type-system way of saying "Don't touch this! Unsafe stuff may be inside it!". It helps isolate data that is unsafe to access, but it won't automatically make it safe for you.