session_rust/
graph.rs

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