Thank you all for the replies.
@kpreid
Can you tell us about what write operations you want to perform on this graph
Essentially: node addition / deletion, node state edition from outside the graph, node connection creation, and finally node running implying going through the graph depth-first along the dependency edges and accessing the node's state from its function every time.
Given the advice provided, I will be making significant structural changes to my code so I'll get back to you in this thread very soon whether I'm still encountering RefCell-related issues or not.
@giocri
depends on how you want to handle your graph, in my experience some of the easiest and most effective ways to do it are
struct GraphNodeTracksEdges{
HashSet<NodeId> nodes,
HashMap<NodeId,Vec<Nodeid>> edges,
}
struct GraphGlobalEdges{
HashSet<NodeId> nodes,
HashSet<(NodeId,NodeId)> edges,
}
Probably going to rewrite things to store edges like this; it's much more convenient and the benefits I thought I would get from having "intuitive" connections are actually more troublesome than anything, as nodes have no reason to know which other node they're connected to since in my case the depth-first traversal and their resulting function input are at the Graph level.
yuriy0 (new users can only mention 2 users in a post, dang)
If you need to modify more than one node at a time, you can move out of nodes (i.e. using mem::replace with a default "invalid" node state), then put the nodes back when you're done your modifications.
Instead of keeping an Rc to somehow reuse nodes, you can just use a free list. Keep a generation counter with each node.
I did not think of using mem::replace, but wouldn't the cost of initializing default nodes pile up? Could I perhaps just use an Option to wrap all nodes and take the value, leaving a None? I'm not entirely sure about the costs associated with moving values in/out of Options, which is why I thought of using a RefCell around every node to bypass the issues of single mutable access to the Vec without moving or copying any data.
Big fan of the generation counter idea though, I've even used it in prior projects but it slipped my mind.
Overall, it seems I'll be able to get rid of the RefCell around the NodeStorage, so most of my issues should vanish. The code seems like it's going to get much cleaner once some of the suggested changes are implemented.
It's not pretty nor clear and very far from efficient, but the current code is available here. I implore your mercy regarding the shortcuts taken and extremely WIP state, I mostly work on this on the tram to and from work and change core parts every other day so some things might have slipped through :')