Fighting the borrow checker (reborrow on None)


#1

If anyone can help me I’m tearing my hair out (and there isn’t much of it left!!)

I have a method (below) and the borrow checker complains that the borrow at self.sync_databases.iter() overlaps the one at self.sync_databases.push(..), but in my mind they don’t. Is what I’m trying to do safe? If it is, is there a way to appease the borrow checker (either with or without unsafe)?

    pub fn register_sync_database<'a>(
        &'a mut self,
        name: impl AsRef<str>,
    ) -> Result<Db<'a>, Error> {
        let name = name.as_ref();
        // If we've already registered the database, just return it
        if let Some(db) = self.sync_databases.iter().find(|&db| db.name() == name) {
            warn!(r#"database "{}" already registered"#, name);
            return Ok(Db::new(db, self));
        }
        let base = DbBase::new_sync(name, self, SignatureLevel::default())?;
        let db_idx = self.sync_databases.len();
        self.sync_databases.push(base);
        Ok(Db::new(&self.sync_databases[db_idx], self))
    }

EDIT worth mentioning that I’ve already tried extra braces around the if let.

EDIT2 it works with nll! Which suggests what I’m trying to do is safe if nll is working :slight_smile:


#2

Sounds like you’ve already answered this yourself :slight_smile:. But case #3 here talks about your problem - return'ing a borrow of self early in a method keeps it borrowed for the rest of the method too.


#3

Thanks for the link. I guess I’ll just use nightly for now.

EDIT I read about the entry api, and it made me think that maybe I’m using the wrong datastructure. As I’m always fetching a database by name I should be using a HashMap.


#4

You can also use position() (instead of find()) and match on its result if you don’t want to use HashMap.