Better Module rendering

<
>
December 22, 2021

Up until now Modules were rendered by simple rectangles with text on top of them to signal what they consume and produce.

I improved the rendering to also show all Structures within the Module.
There’s now also a slight overlay to indicate that this is a Module and not multiple Structures.
Production and consumption are now also shown at the respective Source or Sink, while these are rendered slightly differently to better indicate that they are the ‘edges’ of a Module and not freely placed Sources or Sinks.

Since the internals of Modules aren’t animated, the render Node of a Module will ‘never’ change (unless specific render settings are altered).
This makes it possible to cache their render Nodes.

For this I first wrapped the Node type:

pub enum RcNode {
    Node(Node),
    Rc(Rc<Node>),
}

An RcNode is either a simple Node (just as before), or an Rc<Node>. Rc is a reference counting pointer and in this use case allows for very cheap copies.
I then changed BranchNode to hold RcNodes as children:

pub struct BranchNode {
    ...
    pub children: Vec<RcNode>,
}

This way it’s now possible to create render trees with cheap-to-copy Nodes.
I also added:

pub struct ModuleNodeStore {
    cache: RefCell<BTreeMap<ModuleDefinitionID, Rc<Node>>>,
}

to take care of the caching of Module render Nodes.
It either returns an already generated Node, or generates one, then caches and returns it:

impl ModuleNodeStore {
    pub fn get(&self, module_store: &dyn ModuleStore, i: ModuleDefinitionID) -> Option<Rc<Node>> {
        if i.0 >= module_store.len() {
            return None;
        }

        if let Some(node) = self.cache.borrow().get(&i).cloned() {
            return Some(node);
        }

        let new_node = self.new_node(module_store, &*module_store.get(i).unwrap_condition());

        self.cache.borrow_mut().insert(i, new_node.clone());

        Some(new_node)
    }
    ...
}

By using ModuleNodeStore the render Node of every Module is only generated once.