session_rust/
graph.rs

1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3use uuid::Uuid;
4
5/// A graph vertex with a unique identifier and attribute string.
6#[derive(Debug, Clone, Serialize, Deserialize)]
7#[serde(tag = "type", rename = "Vertex")]
8pub struct Vertex {
9    /// The unique identifier of the vertex.
10    pub guid: String,
11    /// The name of the vertex.
12    pub name: String,
13    /// Vertex attribute data as string.
14    pub attribute: String,
15    /// Integer index for the vertex. Set internally by Graph.
16    pub index: i32,
17}
18
19impl Default for Vertex {
20    fn default() -> Self {
21        Self {
22            name: "my_vertex".to_string(),
23            guid: Uuid::new_v4().to_string(),
24            attribute: String::new(),
25            index: -1,
26        }
27    }
28}
29
30impl Vertex {
31    /// Initialize a new Vertex.
32    pub fn new(name: Option<String>, attribute: Option<String>) -> Self {
33        Self {
34            name: name.unwrap_or_default(),
35            attribute: attribute.unwrap_or_default(),
36            ..Default::default()
37        }
38    }
39
40    ///////////////////////////////////////////////////////////////////////////////////////////
41    // JSON
42    ///////////////////////////////////////////////////////////////////////////////////////////
43
44    /// Convert the Vertex to a JSON-serializable string.
45    pub fn to_json_data(&self) -> Result<String, Box<dyn std::error::Error>> {
46        Ok(serde_json::to_string_pretty(self)?)
47    }
48
49    /// Create Vertex from JSON string data.
50    pub fn from_json_data(json_data: &str) -> Result<Self, Box<dyn std::error::Error>> {
51        Ok(serde_json::from_str(json_data)?)
52    }
53}
54
55/// A graph edge with a unique identifier and attribute string.
56#[derive(Debug, Clone, Serialize, Deserialize)]
57#[serde(tag = "type", rename = "Edge")]
58pub struct Edge {
59    /// The unique identifier of the edge.
60    pub guid: String,
61    /// The name of the edge.
62    pub name: String,
63    /// The first vertex of the edge.
64    pub v0: String,
65    /// The second vertex of the edge.
66    pub v1: String,
67    /// Edge attribute data as string.
68    pub attribute: String,
69    /// Integer index for the edge.
70    pub index: i32,
71}
72
73impl Default for Edge {
74    fn default() -> Self {
75        Self {
76            name: "my_edge".to_string(),
77            guid: Uuid::new_v4().to_string(),
78            v0: String::new(),
79            v1: String::new(),
80            attribute: String::new(),
81            index: -1,
82        }
83    }
84}
85
86impl Edge {
87    /// Initialize a new Edge.
88    pub fn new(
89        name: Option<String>,
90        v0: Option<String>,
91        v1: Option<String>,
92        attribute: Option<String>,
93    ) -> Self {
94        Self {
95            name: name.unwrap_or_default(),
96            v0: v0.unwrap_or_default(),
97            v1: v1.unwrap_or_default(),
98            attribute: attribute.unwrap_or_default(),
99            ..Default::default()
100        }
101    }
102
103    ///////////////////////////////////////////////////////////////////////////////////////////
104    // JSON
105    ///////////////////////////////////////////////////////////////////////////////////////////
106
107    /// Convert the Edge to a JSON-serializable string.
108    pub fn to_json_data(&self) -> Result<String, Box<dyn std::error::Error>> {
109        Ok(serde_json::to_string_pretty(self)?)
110    }
111
112    /// Create Edge from JSON string data.
113    pub fn from_json_data(json_data: &str) -> Result<Self, Box<dyn std::error::Error>> {
114        Ok(serde_json::from_str(json_data)?)
115    }
116
117    /// Get the edge vertices as a tuple.
118    pub fn vertices(&self) -> (String, String) {
119        (self.v0.clone(), self.v1.clone())
120    }
121
122    /// Check if this edge connects to a given vertex.
123    pub fn connects(&self, vertex_id: &str) -> bool {
124        self.v0 == vertex_id || self.v1 == vertex_id
125    }
126
127    /// Get the other vertex ID connected by this edge.
128    pub fn other_vertex(&self, vertex_id: &str) -> String {
129        if self.v0 == vertex_id {
130            self.v1.clone()
131        } else {
132            self.v0.clone()
133        }
134    }
135}
136
137#[derive(Debug, Clone, Serialize, Deserialize)]
138#[serde(tag = "type", rename = "Graph")]
139pub struct Graph {
140    // Public fields, similar to C++
141    pub guid: String,
142    pub name: String,
143    pub vertex_count: i32,
144    pub edge_count: i32,
145
146    // Private fields (by Rust's default visibility)
147    // std::map translates to HashMap in Rust.
148    vertices: HashMap<String, Vertex>,
149    edges: HashMap<String, HashMap<String, Edge>>,
150}
151
152impl Default for Graph {
153    fn default() -> Self {
154        Self {
155            guid: Uuid::new_v4().to_string(),
156            name: "my_graph".to_string(),
157            vertex_count: 0,
158            edge_count: 0,
159            vertices: HashMap::new(),
160            edges: HashMap::new(),
161        }
162    }
163}
164
165impl Graph {
166    /// Creates a new, empty `Graph` with a specific name.
167    pub fn new(name: &str) -> Self {
168        Self {
169            name: name.to_string(),
170            ..Default::default()
171        }
172    }
173
174    /// Checks if a node exists in the graph.
175    pub fn has_node(&self, key: &str) -> bool {
176        self.vertices.contains_key(key)
177    }
178
179    /// Adds a node to the graph.
180    pub fn add_node(&mut self, key: &str, attribute: &str) -> String {
181        if self.has_node(key) {
182            return self.vertices.get(key).unwrap().name.clone();
183        }
184
185        let mut vertex = Vertex::new(Some(key.to_string()), Some(attribute.to_string()));
186        vertex.index = self.vertices.len() as i32;
187        self.vertices.insert(key.to_string(), vertex.clone());
188        self.vertex_count = self.vertices.len() as i32;
189        vertex.name
190    }
191
192    /// Adds an edge between u and v.
193    pub fn add_edge(&mut self, u: &str, v: &str, attribute: &str) -> (String, String) {
194        // Add vertices if they don't exist
195        if !self.has_node(u) {
196            self.add_node(u, "");
197        }
198        if !self.has_node(v) {
199            self.add_node(v, "");
200        }
201
202        if self.has_edge((u, v)) {
203            return (u.to_string(), v.to_string());
204        }
205
206        let mut edge = Edge::new(
207            Some("my_edge".to_string()),
208            Some(u.to_string()),
209            Some(v.to_string()),
210            Some(attribute.to_string()),
211        );
212        edge.index = self.edge_count;
213
214        self.edges
215            .entry(u.to_string())
216            .or_default()
217            .insert(v.to_string(), edge.clone());
218        self.edges
219            .entry(v.to_string())
220            .or_default()
221            .insert(u.to_string(), edge);
222
223        self.edge_count += 1;
224
225        (u.to_string(), v.to_string())
226    }
227
228    /// Checks if an edge exists in the graph.
229    pub fn has_edge(&self, edge: (&str, &str)) -> bool {
230        let (u, v) = edge;
231        self.edges
232            .get(u)
233            .is_some_and(|neighbors| neighbors.contains_key(v))
234    }
235
236    /// Gets the number of vertices in the graph.
237    pub fn number_of_vertices(&self) -> usize {
238        self.vertices.len()
239    }
240
241    /// Gets the number of edges in the graph.
242    pub fn number_of_edges(&self) -> usize {
243        let mut count = 0;
244        let mut seen = std::collections::HashSet::new();
245        for (u, neighbors) in &self.edges {
246            for v in neighbors.keys() {
247                let edge = if u < v {
248                    (u.clone(), v.clone())
249                } else {
250                    (v.clone(), u.clone())
251                };
252                if seen.insert(edge) {
253                    count += 1;
254                }
255            }
256        }
257        count
258    }
259
260    /// Gets all vertices in the graph.
261    pub fn get_vertices(&self) -> Vec<Vertex> {
262        self.vertices.values().cloned().collect()
263    }
264
265    /// Gets all edges in the graph as tuples of vertex names.
266    pub fn get_edges(&self) -> Vec<(String, String)> {
267        let mut result = Vec::new();
268        let mut seen = std::collections::HashSet::new();
269        for (u, neighbors) in &self.edges {
270            for v in neighbors.keys() {
271                let edge = if u < v {
272                    (u.clone(), v.clone())
273                } else {
274                    (v.clone(), u.clone())
275                };
276                if seen.insert(edge.clone()) {
277                    result.push(edge);
278                }
279            }
280        }
281        result
282    }
283
284    /// Gets all neighbors of a node.
285    pub fn neighbors(&self, node: &str) -> Vec<String> {
286        self.edges
287            .get(node)
288            .map_or(Vec::new(), |neighbors| neighbors.keys().cloned().collect())
289    }
290
291    /// Removes a node and all its edges from the graph.
292    pub fn remove_node(&mut self, key: &str) {
293        if !self.has_node(key) {
294            return;
295        }
296
297        if let Some(neighbors) = self.edges.remove(key) {
298            for neighbor_key in neighbors.keys() {
299                if let Some(neighbor_edges) = self.edges.get_mut(neighbor_key) {
300                    neighbor_edges.remove(key);
301                }
302            }
303        }
304
305        self.vertices.remove(key);
306        self.vertex_count = self.vertices.len() as i32;
307        self.edge_count = self.number_of_edges() as i32;
308    }
309
310    /// Removes an edge from the graph.
311    pub fn remove_edge(&mut self, edge: (&str, &str)) {
312        let (u, v) = edge;
313        let mut edge_removed = false;
314
315        if let Some(neighbors) = self.edges.get_mut(u) {
316            if neighbors.remove(v).is_some() {
317                edge_removed = true;
318            }
319        }
320        if let Some(neighbors) = self.edges.get_mut(v) {
321            neighbors.remove(u);
322        }
323
324        if edge_removed {
325            self.edge_count = self.number_of_edges() as i32;
326        }
327    }
328
329    /// Removes all vertices and edges from the graph.
330    pub fn clear(&mut self) {
331        self.vertices.clear();
332        self.edges.clear();
333        self.vertex_count = 0;
334        self.edge_count = 0;
335    }
336
337    /// Get or set node attribute.
338    pub fn node_attribute(&mut self, node: &str, value: Option<&str>) -> Option<String> {
339        if !self.has_node(node) {
340            return None;
341        }
342        let vertex = self.vertices.get_mut(node).unwrap();
343        if let Some(val) = value {
344            vertex.attribute = val.to_string();
345            Some(vertex.attribute.clone())
346        } else {
347            Some(vertex.attribute.clone())
348        }
349    }
350
351    ///////////////////////////////////////////////////////////////////////////////////////////
352    // JSON
353    ///////////////////////////////////////////////////////////////////////////////////////////
354
355    /// Serializes the Graph to a JSON string.
356    pub fn to_json_data(&self) -> Result<String, serde_json::Error> {
357        // Convert vertices to array, sorted by index to ensure consistent order
358        let mut vertices: Vec<&Vertex> = self.vertices.values().collect();
359        vertices.sort_by_key(|v| v.index);
360
361        // Convert edges to array (store each edge only once), sorted by index
362        let mut edges = Vec::new();
363        let mut seen = std::collections::HashSet::new();
364        for (u, neighbors) in &self.edges {
365            for (v, edge) in neighbors {
366                let edge_tuple = if u < v { (u, v) } else { (v, u) };
367                if seen.insert(edge_tuple) {
368                    edges.push(edge);
369                }
370            }
371        }
372        edges.sort_by_key(|e| e.index);
373
374        let json_obj = serde_json::json!({
375            "type": "Graph",
376            "name": self.name,
377            "guid": self.guid,
378            "vertices": vertices,
379            "edges": edges,
380            "vertex_count": self.vertex_count,
381            "edge_count": self.edge_count
382        });
383
384        serde_json::to_string_pretty(&json_obj)
385    }
386
387    /// Deserializes a Graph from a JSON string.
388    pub fn from_json_data(json_data: &str) -> Result<Self, serde_json::Error> {
389        let json_obj: serde_json::Value = serde_json::from_str(json_data)?;
390
391        let mut graph = Graph::new(json_obj["name"].as_str().unwrap_or("my_graph"));
392        graph.guid = json_obj["guid"].as_str().unwrap_or("").to_string();
393        graph.vertex_count = json_obj["vertex_count"].as_i64().unwrap_or(0) as i32;
394        graph.edge_count = json_obj["edge_count"].as_i64().unwrap_or(0) as i32;
395
396        // Restore vertices
397        if let Some(vertices_array) = json_obj["vertices"].as_array() {
398            for vertex_data in vertices_array {
399                let vertex: Vertex = serde_json::from_value(vertex_data.clone())?;
400                graph.vertices.insert(vertex.name.clone(), vertex);
401            }
402        }
403
404        // Restore edges
405        if let Some(edges_array) = json_obj["edges"].as_array() {
406            for edge_data in edges_array {
407                let edge: Edge = serde_json::from_value(edge_data.clone())?;
408                let u = &edge.v0;
409                let v = &edge.v1;
410
411                graph
412                    .edges
413                    .entry(u.clone())
414                    .or_default()
415                    .insert(v.clone(), edge.clone());
416                graph
417                    .edges
418                    .entry(v.clone())
419                    .or_default()
420                    .insert(u.clone(), edge);
421            }
422        }
423
424        Ok(graph)
425    }
426
427    /// Serializes the Graph to a JSON file.
428    pub fn to_json(&self, filepath: &str) -> Result<(), Box<dyn std::error::Error>> {
429        let json_data = self.to_json_data()?;
430        std::fs::write(filepath, json_data)?;
431        Ok(())
432    }
433
434    /// Deserializes a Graph from a JSON file.
435    pub fn from_json(filepath: &str) -> Result<Self, Box<dyn std::error::Error>> {
436        let json_data = std::fs::read_to_string(filepath)?;
437        Self::from_json_data(&json_data).map_err(|e| e.into())
438    }
439
440    /// Get or set edge attribute.
441    pub fn edge_attribute(&mut self, u: &str, v: &str, value: Option<&str>) -> Option<String> {
442        if !self.has_edge((u, v)) {
443            return None;
444        }
445        if let Some(val) = value {
446            let new_attr = val.to_string();
447            if let Some(neighbors) = self.edges.get_mut(u) {
448                if let Some(edge) = neighbors.get_mut(v) {
449                    edge.attribute = new_attr.clone();
450                }
451            }
452            if let Some(neighbors) = self.edges.get_mut(v) {
453                if let Some(edge) = neighbors.get_mut(u) {
454                    edge.attribute = new_attr.clone();
455                }
456            }
457            Some(new_attr)
458        } else {
459            self.edges
460                .get(u)
461                .and_then(|neighbors| neighbors.get(v))
462                .map(|edge| edge.attribute.clone())
463        }
464    }
465}