Skip to main content

code_split_core/
builder.rs

1use crate::graph::{Edge, EdgeKind, Graph, Node, NodeId, NodeKind};
2use std::collections::HashSet;
3
4#[derive(Debug, Default)]
5pub struct GraphBuilder {
6    graph: Graph,
7    seen_nodes: HashSet<NodeId>,
8}
9
10impl GraphBuilder {
11    pub fn new() -> Self {
12        Self::default()
13    }
14
15    pub fn add_node(&mut self, node: Node) -> bool {
16        if self.seen_nodes.insert(node.id.clone()) {
17            self.graph.nodes.push(node);
18            true
19        } else {
20            false
21        }
22    }
23
24    pub fn add_edge(&mut self, edge: Edge) {
25        self.graph.edges.push(edge);
26    }
27
28    pub fn node_count(&self) -> usize {
29        self.graph.nodes.len()
30    }
31
32    pub fn edge_count_of_kind(&self, kind: EdgeKind) -> usize {
33        self.graph.edges.iter().filter(|e| e.kind == kind).count()
34    }
35
36    pub fn nodes(&self) -> &Vec<Node> {
37        &self.graph.nodes
38    }
39
40    pub fn nodes_mut(&mut self) -> &mut Vec<Node> {
41        &mut self.graph.nodes
42    }
43
44    /// Look up an existing `File` node by `path` (canonicalized by the caller).
45    /// Returns the node ID if exactly one match is found, `None` otherwise.
46    pub fn find_file_node(&self, path: &str) -> Option<NodeId> {
47        let mut found = None;
48        for node in &self.graph.nodes {
49            if node.kind == NodeKind::File && node.path == path {
50                if found.is_some() {
51                    return None;
52                }
53                found = Some(node.id.clone());
54            }
55        }
56        found
57    }
58
59    pub fn build(self) -> Graph {
60        self.graph
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67    use crate::graph::NodeKind;
68
69    fn node(id: &str) -> Node {
70        Node {
71            id: id.into(),
72            kind: NodeKind::Crate,
73            name: id.into(),
74            path: String::new(),
75            parent: None,
76            external: None,
77            version: None,
78            visibility: None,
79            loc: None,
80            line: None,
81            item_count: None,
82            method_count: None,
83            complexity: None,
84            cycle_kind: None,
85        }
86    }
87
88    #[test]
89    fn add_node_deduplicates_by_id() {
90        let mut b = GraphBuilder::new();
91        assert!(b.add_node(node("x")));
92        assert!(!b.add_node(node("x")));
93        let g = b.build();
94        assert_eq!(g.nodes.len(), 1);
95    }
96}