Skip to main content

god_graph/graph/
builders.rs

1//! 图构建器模块
2//!
3//! 提供流式 API 用于构建图
4
5use crate::errors::{GraphError, GraphResult};
6use crate::graph::traits::GraphOps;
7use crate::graph::Graph;
8
9/// 图构建器
10///
11/// 提供流式 API 用于方便地构建图
12pub struct GraphBuilder<T, E> {
13    graph: Graph<T, E>,
14    nodes: Vec<T>,
15    edges: Vec<(usize, usize, E)>,
16}
17
18impl<T, E> GraphBuilder<T, E>
19where
20    T: Clone,
21    E: Clone,
22{
23    /// 创建新的有向图构建器
24    pub fn directed() -> Self {
25        Self {
26            graph: Graph::directed(),
27            nodes: Vec::new(),
28            edges: Vec::new(),
29        }
30    }
31
32    /// 创建新的无向图构建器
33    pub fn undirected() -> Self {
34        Self {
35            graph: Graph::undirected(),
36            nodes: Vec::new(),
37            edges: Vec::new(),
38        }
39    }
40
41    /// 添加节点数据
42    pub fn with_node(mut self, data: T) -> Self {
43        self.nodes.push(data);
44        self
45    }
46
47    /// 批量添加节点
48    pub fn with_nodes<I>(mut self, iter: I) -> Self
49    where
50        I: IntoIterator<Item = T>,
51    {
52        self.nodes.extend(iter);
53        self
54    }
55
56    /// 添加边
57    pub fn with_edge(mut self, from: usize, to: usize, data: E) -> Self {
58        self.edges.push((from, to, data));
59        self
60    }
61
62    /// 批量添加边
63    pub fn with_edges<I>(mut self, iter: I) -> Self
64    where
65        I: IntoIterator<Item = (usize, usize, E)>,
66    {
67        self.edges.extend(iter);
68        self
69    }
70
71    /// 构建图
72    pub fn build(mut self) -> GraphResult<Graph<T, E>> {
73        // 先添加所有节点
74        let mut node_indices = Vec::with_capacity(self.nodes.len());
75        for data in self.nodes {
76            let idx = self.graph.add_node(data)?;
77            node_indices.push(idx);
78        }
79
80        // 再添加所有边
81        for (from, to, data) in self.edges {
82            if from >= node_indices.len() || to >= node_indices.len() {
83                return Err(GraphError::IndexOutOfBounds {
84                    index: from.max(to),
85                    bound: node_indices.len(),
86                });
87            }
88            self.graph
89                .add_edge(node_indices[from], node_indices[to], data)?;
90        }
91
92        Ok(self.graph)
93    }
94}
95
96impl<T, E> Default for GraphBuilder<T, E>
97where
98    T: Clone,
99    E: Clone,
100{
101    fn default() -> Self {
102        Self::directed()
103    }
104}
105
106#[cfg(test)]
107mod tests {
108    use super::*;
109    use crate::graph::traits::GraphBase;
110
111    #[test]
112    fn test_builder_basic() {
113        let graph = GraphBuilder::directed()
114            .with_node("A")
115            .with_node("B")
116            .with_node("C")
117            .with_edge(0, 1, 1.0)
118            .with_edge(1, 2, 2.0)
119            .build()
120            .unwrap();
121
122        assert_eq!(graph.node_count(), 3);
123        assert_eq!(graph.edge_count(), 2);
124    }
125
126    #[test]
127    fn test_builder_with_nodes() {
128        let graph: Graph<i32, f64> = GraphBuilder::directed()
129            .with_nodes(vec![1, 2, 3, 4])
130            .build()
131            .unwrap();
132
133        assert_eq!(graph.node_count(), 4);
134    }
135
136    #[test]
137    fn test_builder_with_edges() {
138        use crate::graph::traits::GraphBase;
139
140        let graph = GraphBuilder::directed()
141            .with_nodes(vec!["A", "B", "C"])
142            .with_edges(vec![(0, 1, 1.0), (1, 2, 2.0), (0, 2, 3.0)])
143            .build()
144            .unwrap();
145
146        assert_eq!(graph.node_count(), 3);
147        assert_eq!(graph.edge_count(), 3);
148    }
149}