Vector index vs reference

Hello there, I want to have a reference inside a vector, but the borrow checker for obvious reasons gives errors. Firstly I've solved it by using index instead of ref like in snippet below:

pub struct RenderSystem {
    current_pass_id: Option<usize>,
    passes: Vec<Pass>,
}

pub fn query(&mut self, command: RenderCommand) {
    assert!(self.current_pass_id.is_some(), "Can't query command without render pass");
    let id = self.current_pass_id.unwrap();
    self.passes[id].commands.push(command);
}

It works, but it looks not idiomatically for the rust. I could use lifetime for ref, but I don't want element to live while lives RenderSystem, every frame vector passes is being cleared, so lifetime is render function scope, but add this element to pass I can before enter to render function.

There is another solution I've come up with - use Rc and RefCell, but It looks pretty ugly and actually I think it's less idiomatic than the previous example:

pub struct RenderSystem {
    current_pass: Option<Rc<RefCell<Pass>>>,
    passes: Vec<Rc<RefCell<Pass>>>,
}

pub fn query(&mut self, command: RenderCommand) {
    assert!(
        self.current_pass.is_some(),
        "Can't query command without render pass"
    );
    let pass = self.current_pass.as_ref().unwrap();
    pass.borrow_mut().commands.push(command);
}

Actually, in my particular case I've solved this problem just by using the last element of the vector:

pub fn query(&mut self, command: RenderCommand) {
    assert!(
        !self.passes.is_empty(),
        "Can't query command without render pass"
    );
    let current_pass = self.passes.last_mut().unwrap();
    current_pass.commands.push(command);
}

So the problem has solved, but I still curious if there are any other solutions without RefCell and vector index. Or maybe it’s actually okay to have an index that refers to the desired item.

Storing an index into a Vec to emulate self-borrowing is fairly common, and probably the most idiomatic solution.

5 Likes

I would say the idiomatic solution is to use an index.

1 Like

I see, thanks!

Using indexes as pseudo-pointers is common. See, for example, Modeling graphs in Rust using vector indices · baby steps

petgraph is a good example using indexes.

… as is the ECS paradigm. (Google "Rust ECS" for a choice of relevant material.)

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.