kotoba_graph/graph/
graph.rs1use serde::{Deserialize, Serialize};
4use std::collections::{HashMap, HashSet};
5use parking_lot::RwLock;
6use kotoba_core::types::*;
7use kotoba_core::prelude::{Cid, GraphCore, GraphInstance, Node, Edge, GraphKind};
8use kotoba_cid::CidManager;
9use sha2::{Sha256, Digest};
10
11#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
13pub struct VertexData {
14 pub id: VertexId,
15 pub labels: Vec<Label>,
16 pub props: Properties,
17}
18
19impl VertexData {
20 pub fn to_node(&self) -> Node {
21 let mut hasher = Sha256::new();
22 hasher.update(self.id.to_string().as_bytes());
23 let hash: [u8; 32] = hasher.finalize().into();
24
25 Node {
26 cid: Cid(hash),
27 labels: self.labels.clone(),
28 r#type: "node".to_string(),
29 ports: Vec::new(),
30 attrs: Some(self.props.clone()),
31 component_ref: None,
32 }
33 }
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
38pub struct EdgeData {
39 pub id: EdgeId,
40 pub src: VertexId,
41 pub dst: VertexId,
42 pub label: Label,
43 pub props: Properties,
44}
45
46impl EdgeData {
47 pub fn to_edge(&self) -> Edge {
48 let mut hasher = Sha256::new();
49 hasher.update(self.id.to_string().as_bytes());
50 let hash: [u8; 32] = hasher.finalize().into();
51
52 Edge {
53 cid: Cid(hash),
54 label: Some(self.label.clone()),
55 src: self.src.to_string(),
56 tgt: self.dst.to_string(),
57 attrs: Some(self.props.clone()),
58 r#type: "edge".to_string(),
59 }
60 }
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
65pub struct Graph {
66 pub vertices: HashMap<VertexId, VertexData>,
68
69 pub edges: HashMap<EdgeId, EdgeData>,
71
72 pub adj_out: HashMap<VertexId, HashSet<VertexId>>,
74
75 pub adj_in: HashMap<VertexId, HashSet<VertexId>>,
77
78 pub vertex_labels: HashMap<Label, HashSet<VertexId>>,
80
81 pub edge_labels: HashMap<Label, HashSet<EdgeId>>,
83}
84
85impl Graph {
86 pub fn empty() -> Self {
88 Self {
89 vertices: HashMap::new(),
90 edges: HashMap::new(),
91 adj_out: HashMap::new(),
92 adj_in: HashMap::new(),
93 vertex_labels: HashMap::new(),
94 edge_labels: HashMap::new(),
95 }
96 }
97
98 pub fn add_vertex(&mut self, vertex: VertexData) -> VertexId {
100 let id = vertex.id;
101 for label in &vertex.labels {
102 self.vertex_labels.entry(label.clone()).or_default().insert(id);
103 }
104 self.vertices.insert(id, vertex);
105 id
106 }
107
108 pub fn add_edge(&mut self, edge: EdgeData) -> EdgeId {
110 let id = edge.id;
111 let src = edge.src;
112 let dst = edge.dst;
113
114 self.adj_out.entry(src).or_default().insert(dst);
116 self.adj_in.entry(dst).or_default().insert(src);
117
118 self.edge_labels.entry(edge.label.clone()).or_default().insert(id);
120
121 self.edges.insert(id, edge);
122 id
123 }
124
125 pub fn get_vertex(&self, id: &VertexId) -> Option<&VertexData> {
127 self.vertices.get(id)
128 }
129
130 pub fn get_edge(&self, id: &EdgeId) -> Option<&EdgeData> {
132 self.edges.get(id)
133 }
134
135 pub fn remove_vertex(&mut self, id: &VertexId) -> bool {
137 if let Some(vertex) = self.vertices.remove(id) {
138 for label in &vertex.labels {
140 if let Some(vertices) = self.vertex_labels.get_mut(label) {
141 vertices.remove(id);
142 if vertices.is_empty() {
143 self.vertex_labels.remove(label);
144 }
145 }
146 }
147
148 let mut edges_to_remove = Vec::new();
150 for (edge_id, edge) in &self.edges {
151 if edge.src == *id || edge.dst == *id {
152 edges_to_remove.push(*edge_id);
153 }
154 }
155 for edge_id in edges_to_remove {
156 self.remove_edge(&edge_id);
157 }
158
159 self.adj_out.remove(id);
161 self.adj_in.remove(id);
162
163 for adj in self.adj_out.values_mut() {
165 adj.remove(id);
166 }
167 for adj in self.adj_in.values_mut() {
168 adj.remove(id);
169 }
170
171 true
172 } else {
173 false
174 }
175 }
176
177 pub fn remove_edge(&mut self, id: &EdgeId) -> bool {
179 if let Some(edge) = self.edges.remove(id) {
180 if let Some(out) = self.adj_out.get_mut(&edge.src) {
182 out.remove(&edge.dst);
183 if out.is_empty() {
184 self.adj_out.remove(&edge.src);
185 }
186 }
187 if let Some(in_) = self.adj_in.get_mut(&edge.dst) {
188 in_.remove(&edge.src);
189 if in_.is_empty() {
190 self.adj_in.remove(&edge.dst);
191 }
192 }
193
194 if let Some(edges) = self.edge_labels.get_mut(&edge.label) {
196 edges.remove(id);
197 if edges.is_empty() {
198 self.edge_labels.remove(&edge.label);
199 }
200 }
201
202 true
203 } else {
204 false
205 }
206 }
207
208 pub fn vertices_by_label(&self, label: &Label) -> HashSet<VertexId> {
210 self.vertex_labels.get(label).cloned().unwrap_or_default()
211 }
212
213 pub fn edges_by_label(&self, label: &Label) -> HashSet<EdgeId> {
215 self.edge_labels.get(label).cloned().unwrap_or_default()
216 }
217
218 pub fn degree(&self, id: &VertexId) -> usize {
220 let out_degree = self.adj_out.get(id).map(|s| s.len()).unwrap_or(0);
221 let in_degree = self.adj_in.get(id).map(|s| s.len()).unwrap_or(0);
222 out_degree + in_degree
223 }
224
225 pub fn vertex_count(&self) -> usize {
227 self.vertices.len()
228 }
229
230 pub fn edge_count(&self) -> usize {
232 self.edges.len()
233 }
234
235 pub fn to_graph_core(&self) -> GraphCore {
236 GraphCore {
237 nodes: self.vertices.values().map(|v| v.to_node()).collect(),
238 edges: self.edges.values().map(|e| e.to_edge()).collect(),
239 boundary: None,
240 attrs: None,
241 }
242 }
243}
244
245#[derive(Debug, Clone)]
247pub struct GraphRef {
248 inner: std::sync::Arc<RwLock<Graph>>,
249}
250
251impl GraphRef {
252 pub fn new(graph: Graph) -> Self {
253 Self {
254 inner: std::sync::Arc::new(RwLock::new(graph)),
255 }
256 }
257
258 pub fn read(&self) -> parking_lot::RwLockReadGuard<'_, Graph> {
259 self.inner.read()
260 }
261
262 pub fn write(&self) -> parking_lot::RwLockWriteGuard<'_, Graph> {
263 self.inner.write()
264 }
265
266 pub fn to_graph_instance_with_cid(&self, cid_manager: &mut CidManager) -> Result<GraphInstance> {
267 let core_graph = self.read().to_graph_core();
268 let cid = cid_manager.compute_graph_cid(&core_graph)?;
269
270 Ok(GraphInstance {
271 cid,
272 kind: GraphKind::Graph,
273 core: core_graph,
274 typing: None, })
276 }
277}