Data behind Counted Immutable Refefence in Rust

88 Views Asked by At

I have a data structure in Rust that is created and then never changes (like the rule set of a game). Then I want to reference that data in other structs but I don't want these other structs to own it, just reference it 'immutably'. And it would be nice if the data is deleted when no more references are on it. So Rc comes in mind. However for the borrow checker it appears to be owning that data. Then there is RefCell, which kind of does the trick. But it also allows borrowing the inner data mutably, which I want to prevent and it allows mutability.

let these be my definitions:

struct RuleSet { rule1: Rule; ... }
struct GameState{ ruleSet: ??<RuleSet>; ... }
Impl for GameState {
  fn do_things(&mut self, rule: &rule){ ... }
}

and I want to do things like that:

let state: GameState = ...;
let def = state.ruleSet.rule1;
state.do_things(def); // <- here it complains: cannot mutably borrow 'state' whlie immutably borrow 'state' (def is part of it)

If I just let ruleSet be of type RuleSet, it complains that it cannot borrow state, because it is borrowed (from the line above) in def because rule1 is part of ruleSet which is part of it. When I use an Rc it says the same thing, so somehow it thinks that it has ownership over its content. I could clone the Rc before I take things out, but that is ugly. When I am using RefCell I can access it like this: state.ruleSet.borrow().rule1 That is very close to what I want to achieve, but RefCell supports borrow_mut(), that I don't want and I don't think it does reference counting.

So I mainly want to make it immutable or dis-attached, so that the borrow checker does not think I can not mess with the parent struct while having references on it.

1

There are 1 best solutions below

1
cafce25 On

You want exactly a Rc (or Arc in concurrent contexts) don't know why you think it's "ugly" to clone it but you have to increase the counter with some operation and a clone is doing exactly that. It's designed for exactly your use case, a thing that gets cleaned up when nothing uses it any more so each shared owner can hold on to something with a lifetime bound to nothing but 'static.

The only other option for a shared reference is to Box::leak it but that doesn't fulfil your requirement of freeing the data when it's no longer used.