Skip to main content

step_io/
refgraph.rs

1//! [`RefGraph`] — reverse-reference index over a [`StepModel`].
2//!
3//! The model stores references in the forward direction: an entity points to
4//! what it uses. Many read queries want the inverse ("what references this
5//! entity?") — the [`scene`](crate::scene) handles need it to walk an
6//! assembly or a shape upward. [`StepModel::ref_graph`] builds the index by
7//! inverting every entity's outgoing references; the enumeration underneath is
8//! generated, so no entity type is missed.
9
10use std::collections::HashMap;
11
12use crate::StepModel;
13use crate::generated::model::EntityKey;
14use crate::generated::walk::for_each_entity;
15use crate::generated::write::Writer;
16
17/// An inverse-reference index: for each entity, the entities that reference it.
18pub struct RefGraph {
19    referrers: HashMap<EntityKey, Vec<EntityKey>>,
20}
21
22impl StepModel {
23    /// Build the reverse-reference index for this model.
24    ///
25    /// O(total references); builds the whole index in one pass. Build once and
26    /// reuse for many reverse queries.
27    #[must_use]
28    pub fn ref_graph(&self) -> RefGraph {
29        let writer = Writer::new(self);
30        let mut referrers: HashMap<EntityKey, Vec<EntityKey>> = HashMap::new();
31        let mut deps = Vec::new();
32        for_each_entity(self, |referrer| {
33            deps.clear();
34            writer.deps_of(referrer, &mut deps);
35            for &target in &deps {
36                referrers.entry(target).or_default().push(referrer);
37            }
38        });
39        RefGraph { referrers }
40    }
41}
42
43impl RefGraph {
44    /// The entities that reference `target` (empty if none). Order is the model's
45    /// entity-walk order.
46    #[must_use]
47    pub fn referrers(&self, target: EntityKey) -> &[EntityKey] {
48        self.referrers.get(&target).map_or(&[], Vec::as_slice)
49    }
50}