Design patterns for dropping associated data?

In Rust, we sometimes use ID-keyed lookup structures to store data in a way that avoids the ownership problems with circular data structures. I was thinking of using this pattern to store some extra info about Things in another struct, I’ll call Root. This Root could have a map from ThingID to ExtraInfo.

But the issue is I have been storing my Things as Rc<Thing>. If I add this extra info, the simplicity of Rc is defeated. The drop when the Rc count goes to zero will not clean up the map in Root.

Right now I’m thinking about some kind of garbage collection for the associated data. The ExtraInfo in the Root could also have an rc::Weak<Thing>, and periodically the entries for dead Things could be cleared out.

Any articles on this, or other ideas that would help?

If Thing is your own struct, why not add an Option to it?

Alternative could be a ThingWrapper:

struct ThingWrapper {
    thing: Thing,
    data: Option<Data>, // or Cell, or RefCell,
}

impl ThingWrapper {
    pub fn data(this: &Self) -> Option<&Data> {
        this.data.as_ref()
    }
}

impl std::ops::Deref for ThingsWrapper {
    type Target = Thing;

    fn deref(&self) -> &Self::Target {
        &self.thing
    }
}

I had a couple ‘reasons’, but you may be right - KISS. I was thinking of a space issue, since 99% of the time this data will not be used, but I could get that to only 8 bytes by using Option<Box<ExtraData>>. The second reason is that the Things have pointers to other Things and form a tree, and this extra stuff could be circular. But given the complication of de-allocating the associated data, putting rc::Weak<Thing> in the extra data is probably the best.

1 Like