flow_rs_core/graph/
mod.rs

1//! Graph data structures and operations
2
3use std::collections::HashMap;
4use std::marker::PhantomData;
5
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Serialize};
8
9use crate::error::{FlowError, Result};
10use crate::handle::Handle;
11use crate::types::{EdgeId, NodeId, Position, Rect};
12
13pub mod drag_operations;
14pub mod edge;
15pub mod node;
16pub mod traversal;
17pub mod validation;
18
19pub use edge::{Edge, EdgeBuilder};
20pub use node::{Node, NodeBuilder};
21
22/// Graph container for nodes and edges
23#[derive(Debug, Clone, PartialEq)]
24#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
25pub struct Graph<N = (), E = ()> {
26    pub(crate) nodes: HashMap<NodeId, Node<N>>,
27    pub(crate) edges: HashMap<EdgeId, Edge<E>>,
28
29    #[cfg_attr(feature = "serde", serde(skip))]
30    _phantom: PhantomData<(N, E)>,
31}
32
33impl<N, E> Graph<N, E> {
34    /// Create a new empty graph
35    pub fn new() -> Self {
36        Self {
37            nodes: HashMap::new(),
38            edges: HashMap::new(),
39            _phantom: PhantomData,
40        }
41    }
42
43    /// Add a node to the graph
44    pub fn add_node(&mut self, node: Node<N>) -> Result<()> {
45        if self.nodes.contains_key(&node.id) {
46            return Err(FlowError::duplicate_node_id(node.id.as_str()));
47        }
48
49        self.nodes.insert(node.id.clone(), node);
50        Ok(())
51    }
52
53    /// Remove a node and all connected edges
54    pub fn remove_node(&mut self, node_id: &NodeId) -> Result<Node<N>> {
55        let node = self
56            .nodes
57            .remove(node_id)
58            .ok_or_else(|| FlowError::node_not_found(node_id.as_str()))?;
59
60        // Remove all connected edges
61        self.edges.retain(|_, edge| !edge.is_connected_to(node_id));
62
63        Ok(node)
64    }
65
66    /// Get a reference to a node
67    pub fn get_node(&self, node_id: &NodeId) -> Option<&Node<N>> {
68        self.nodes.get(node_id)
69    }
70
71    /// Get a mutable reference to a node
72    pub fn get_node_mut(&mut self, node_id: &NodeId) -> Option<&mut Node<N>> {
73        self.nodes.get_mut(node_id)
74    }
75
76    /// Add an edge to the graph
77    pub fn add_edge(&mut self, edge: Edge<E>) -> Result<()> {
78        // Validate that source and target nodes exist
79        if !self.nodes.contains_key(&edge.source) {
80            return Err(FlowError::node_not_found(edge.source.as_str()));
81        }
82        if !self.nodes.contains_key(&edge.target) {
83            return Err(FlowError::node_not_found(edge.target.as_str()));
84        }
85
86        if self.edges.contains_key(&edge.id) {
87            return Err(FlowError::duplicate_edge_id(edge.id.as_str()));
88        }
89
90        self.edges.insert(edge.id.clone(), edge);
91        Ok(())
92    }
93
94    /// Remove an edge
95    pub fn remove_edge(&mut self, edge_id: &EdgeId) -> Result<Edge<E>> {
96        self.edges
97            .remove(edge_id)
98            .ok_or_else(|| FlowError::edge_not_found(edge_id.as_str()))
99    }
100
101    /// Get a reference to an edge
102    pub fn get_edge(&self, edge_id: &EdgeId) -> Option<&Edge<E>> {
103        self.edges.get(edge_id)
104    }
105
106    /// Get a mutable reference to an edge
107    pub fn get_edge_mut(&mut self, edge_id: &EdgeId) -> Option<&mut Edge<E>> {
108        self.edges.get_mut(edge_id)
109    }
110
111    /// Get all nodes
112    pub fn nodes(&self) -> impl Iterator<Item = &Node<N>> {
113        self.nodes.values()
114    }
115
116    /// Get all nodes mutably
117    pub fn nodes_mut(&mut self) -> impl Iterator<Item = &mut Node<N>> {
118        self.nodes.values_mut()
119    }
120
121    /// Get all edges
122    pub fn edges(&self) -> impl Iterator<Item = &Edge<E>> {
123        self.edges.values()
124    }
125
126    /// Get all edges mutably
127    pub fn edges_mut(&mut self) -> impl Iterator<Item = &mut Edge<E>> {
128        self.edges.values_mut()
129    }
130
131    /// Get node count
132    pub fn node_count(&self) -> usize {
133        self.nodes.len()
134    }
135
136    /// Get edge count
137    pub fn edge_count(&self) -> usize {
138        self.edges.len()
139    }
140
141    /// Check if graph is empty
142    pub fn is_empty(&self) -> bool {
143        self.nodes.is_empty()
144    }
145
146    /// Clear all nodes and edges
147    pub fn clear(&mut self) {
148        self.nodes.clear();
149        self.edges.clear();
150    }
151
152    /// Get edges connected to a node
153    pub fn get_connected_edges(&self, node_id: &NodeId) -> Vec<&Edge<E>> {
154        self.edges
155            .values()
156            .filter(|edge| edge.is_connected_to(node_id))
157            .collect()
158    }
159
160    /// Get incoming edges for a node
161    pub fn get_incoming_edges(&self, node_id: &NodeId) -> Vec<&Edge<E>> {
162        self.edges
163            .values()
164            .filter(|edge| &edge.target == node_id)
165            .collect()
166    }
167
168    /// Get outgoing edges for a node
169    pub fn get_outgoing_edges(&self, node_id: &NodeId) -> Vec<&Edge<E>> {
170        self.edges
171            .values()
172            .filter(|edge| &edge.source == node_id)
173            .collect()
174    }
175
176    /// Check if two nodes are connected
177    pub fn are_connected(&self, source: &NodeId, target: &NodeId) -> bool {
178        self.edges
179            .values()
180            .any(|edge| edge.connects(source, target))
181    }
182
183    /// Get all node IDs
184    pub fn node_ids(&self) -> impl Iterator<Item = &NodeId> {
185        self.nodes.keys()
186    }
187
188    /// Get all edge IDs
189    pub fn edge_ids(&self) -> impl Iterator<Item = &EdgeId> {
190        self.edges.keys()
191    }
192
193    /// Calculate bounding rectangle of all nodes
194    pub fn bounds(&self) -> Option<Rect>
195    where
196        N: Clone,
197    {
198        if self.nodes.is_empty() {
199            return None;
200        }
201
202        let mut min_x = f64::INFINITY;
203        let mut min_y = f64::INFINITY;
204        let mut max_x = f64::NEG_INFINITY;
205        let mut max_y = f64::NEG_INFINITY;
206
207        for node in self.nodes.values() {
208            let bounds = node.bounds();
209            min_x = min_x.min(bounds.x);
210            min_y = min_y.min(bounds.y);
211            max_x = max_x.max(bounds.x + bounds.width);
212            max_y = max_y.max(bounds.y + bounds.height);
213        }
214
215        Some(Rect::new(min_x, min_y, max_x - min_x, max_y - min_y))
216    }
217
218    /// Find handle at position in the graph
219    pub fn handle_at_position(
220        &self,
221        point: Position,
222        handle_size: f64,
223    ) -> Option<(&NodeId, &Handle)> {
224        for node in self.nodes.values() {
225            if let Some(handle) = node.handle_at_position(point, handle_size) {
226                return Some((&node.id, handle));
227            }
228        }
229        None
230    }
231
232    /// Get all handles of a specific type in the graph
233    pub fn get_handles_by_type(
234        &self,
235        handle_type: crate::handle::HandleType,
236    ) -> Vec<(&NodeId, &Handle)> {
237        let mut handles = Vec::new();
238        for node in self.nodes.values() {
239            for handle in node.handles() {
240                if handle.handle_type == handle_type {
241                    handles.push((&node.id, handle));
242                }
243            }
244        }
245        handles
246    }
247
248    /// Create a new edge creator for this graph
249    pub fn create_edge_creator(&self) -> crate::edge_creator::EdgeCreator {
250        crate::edge_creator::EdgeCreator::new()
251    }
252}
253
254impl<N, E> Default for Graph<N, E> {
255    fn default() -> Self {
256        Self::new()
257    }
258}
259
260// Include traversal algorithms
261
262#[cfg(test)]
263mod tests;