1use crate::graph::node::Node;
18
19use edge::Edge;
20use std::collections::{HashMap, HashSet};
21use std::fmt::Display;
22
23use dot::{Id, Nodes};
24use std::rc::Rc;
25
26use crate::extract::{Edges, ExtractData, Label, Query};
27
28use crate::graph::traversal::GraphTraversal;
29use crate::identify::{Identifiable, Identity};
30
31pub mod edge;
32pub mod node;
33
34pub mod traversal;
35
36pub type Graph<T> = ConcreteGraph<T>;
37
38pub trait GraphDefinition {
39 type Id: Identity;
40 type Label: Display + Clone;
41 type EdgeMeta;
42 type NodeData: 'static;
43
44 fn build_graph<V, Q>(source: &Q) -> ConcreteGraph<Self>
45 where
46 Q: Query<Self::Id, V>,
47 V: Identifiable<Self::Id>
48 + Edges<Self::Id, Self::EdgeMeta>
49 + ExtractData<Self::NodeData>
50 + Label<Label = Self::Label>,
51 Self: Sized,
52 {
53 let source = source.create_index();
54
55 let mut top_level_edges = source.all().into_iter().map(|value| value.get_id());
56
57 let mut output = HashMap::new();
58 let mut queue: Vec<Self::Id> = vec![];
59 let mut current: Option<Self::Id> = top_level_edges.next();
60 let mut seen_set = HashSet::new();
61 while let Some(current_identity) = current.take() {
62 if let Some(next) = queue.pop() {
64 current = Some(next);
65 } else if let Some(id) = top_level_edges.next() {
66 current = Some(id);
67 } else {
68 current = None;
69 }
70
71 if seen_set.contains(¤t_identity) {
72 continue;
73 } else {
74 seen_set.insert(current_identity.clone());
75 }
76
77 let value: &V = source
78 .query(¤t_identity)
79 .expect("Created a value that doesn't exist in the set");
80 let current_node = output
81 .entry(current_identity.clone() as Self::Id)
82 .or_insert_with(|| {
83 Node::new(
84 current_identity.clone(),
85 value.label(),
86 value.extract_data(),
87 )
88 })
89 .clone();
90
91 let edge_iterator = value.edges();
92
93 for edge in edge_iterator {
94 queue.push(edge.sink.clone());
96
97 let node = output
98 .entry(edge.sink.clone() as Self::Id)
99 .or_insert_with(|| {
100 let data = source.query(&edge.sink);
101
102 assert!(
103 data.is_some(),
104 "Created node that does not exist {}",
105 edge.sink.clone()
106 );
107 let data = data.unwrap();
108 Node::new(edge.sink, data.label(), data.extract_data())
109 })
110 .clone();
111
112 current_node.insert_edge(node.clone(), edge.meta);
113 }
114 }
115 output.into_values().collect()
116 }
117}
118
119pub struct SimpleGraphDefinition;
120impl GraphDefinition for SimpleGraphDefinition {
121 type Id = i32;
122 type Label = Self::Id;
123 type EdgeMeta = ();
124 type NodeData = ();
125}
126
127trait AbstractGraph {
128 type Definition: GraphDefinition;
129}
130
131pub struct ConcreteGraph<T>
132where
133 T: GraphDefinition,
134{
135 pub(crate) nodes: HashMap<T::Id, Node<T>>,
136}
137
138impl<T> ConcreteGraph<T>
139where
140 T: GraphDefinition,
141{
142 pub fn all_nodes(&self) -> impl Iterator<Item = Node<T>> + '_ {
143 self.nodes.values().cloned()
144 }
145
146 pub fn all_edges(&self) -> impl Iterator<Item = Edge<T>> + '_ {
148 self.nodes
149 .values()
150 .flat_map(|node| node.get_edges().into_iter())
151 }
152
153 pub fn order(&self) -> usize {
154 self.nodes.len()
155 }
156}
157
158impl<T: GraphDefinition> Default for ConcreteGraph<T> {
159 fn default() -> Self {
160 Self {
161 nodes: Default::default(),
162 }
163 }
164}
165
166impl<T> FromIterator<Node<T>> for ConcreteGraph<T>
167where
168 T: GraphDefinition,
169{
170 fn from_iter<I: IntoIterator<Item = Node<T>>>(iter: I) -> Self {
171 let mut map = HashMap::default();
172
173 for node in iter {
174 map.insert(node.get_id(), node);
175 }
176
177 Self { nodes: map }
178 }
179}
180
181impl<'a, T: GraphDefinition> IntoIterator for &'a ConcreteGraph<T> {
182 type Item = Node<T>;
183 type IntoIter = <Vec<Self::Item> as IntoIterator>::IntoIter;
184
185 fn into_iter(self) -> Self::IntoIter {
186 let nodes: Vec<_> = self.nodes.values().cloned().collect();
187 nodes.into_iter()
188 }
189}
190
191impl<T> Query<T::Id, Node<T>> for ConcreteGraph<T>
192where
193 T: GraphDefinition,
194{
195 fn query(&self, identifier: &T::Id) -> Option<&Node<T>> {
196 self.nodes.get(identifier)
197 }
198
199 fn all(&self) -> Vec<&Node<T>> {
200 self.nodes.values().collect()
201 }
202}
203
204impl<T> ConcreteGraph<T>
205where
206 T: GraphDefinition,
207{
208 pub fn invert(&self) -> Inverted<T> {
210 let edges = self.all_nodes(); let mut output_graph = Self::default();
213
214 for existing_node in edges {
215 let node = output_graph
216 .nodes
217 .entry(existing_node.get_id())
218 .or_insert_with(|| existing_node.new_derived())
219 .clone();
220
221 existing_node.with_edges_iter(|edge| {
222 for child in edge {
223 let child_node = output_graph
224 .nodes
225 .entry(child.target.get_id())
226 .or_insert_with(|| child.target.new_derived())
227 .clone();
228
229 child_node.derive_edge(node.clone(), &child);
230 }
231 });
232 }
233
234 Inverted {
235 graph: output_graph,
236 }
237 }
238}
239
240pub struct Inverted<T>
241where
242 T: GraphDefinition,
243{
244 graph: ConcreteGraph<T>,
245}
246
247impl<T> Inverted<T>
248where
249 T: GraphDefinition,
250{
251 pub fn inner(&self) -> &ConcreteGraph<T> {
252 &self.graph
253 }
254
255 pub fn map_project(mut self, traversal: GraphTraversal<T>) -> Self {
256 self.graph = traversal.project_into_graph(&self.graph);
257 self
258 }
259}
260
261impl Graph<SimpleGraphDefinition> {
262 pub fn insert_node(&mut self, node_id: <SimpleGraphDefinition as GraphDefinition>::Id) {
263 self.nodes
264 .entry(node_id.clone())
265 .or_insert_with(|| Node::<SimpleGraphDefinition>::new_bare(node_id));
266 }
267
268 pub fn insert_edge(
269 &mut self,
270 from: <SimpleGraphDefinition as GraphDefinition>::Id,
271 to: <SimpleGraphDefinition as GraphDefinition>::Id,
272 ) {
273 let node = self
274 .nodes
275 .entry(from.clone())
276 .or_insert_with(|| Node::<SimpleGraphDefinition>::new_bare(from))
277 .clone();
278 let target = self
279 .nodes
280 .entry(to.clone())
281 .or_insert_with(|| Node::<SimpleGraphDefinition>::new_bare(to))
282 .clone();
283 node.insert_edge(target, Rc::new(()));
284 }
285}
286
287#[cfg(test)]
288mod test {
289 type SimpleGraph = Graph<SimpleGraphDefinition>;
290
291 use crate::graph::node::Node;
292 use crate::graph::{Graph, GraphDefinition, SimpleGraphDefinition};
293 use std::collections::HashSet;
294
295 use crate::extract::{Edge, Edges, Label, Query};
296 use crate::identify::Identifiable;
297
298 type Id = i32;
299
300 struct Datastore {
301 store: Vec<Data>,
302 }
303
304 struct Data {
305 id: Id,
306 edges: Vec<Id>,
307 }
308
309 impl Label for Data {
310 type Label = Id;
311 fn label(&self) -> Self::Label {
312 self.id
313 }
314 }
315
316 impl Identifiable<Id> for Data {
317 fn get_id(&self) -> Id {
318 self.id.clone()
319 }
320 }
321
322 impl Query<Id, Data> for Datastore {
323 fn query(&self, identifier: &Id) -> Option<&Data> {
324 self.store.iter().find(|data| data.id == *identifier)
325 }
326
327 fn all(&self) -> Vec<&Data> {
328 self.store.iter().collect()
329 }
330 }
331
332 impl<'a> Edges<Id, ()> for Data {
333 fn next_edge(&self, previous_edge_index: Option<usize>) -> Option<Edge<Id, ()>> {
334 let next_idx = previous_edge_index.map(|e| e + 1).unwrap_or_default();
335 let edge = self.edges.get(next_idx)?;
336 Some(Edge::new(self.get_id(), edge.clone(), next_idx, ()))
337 }
338 }
339
340 type TestGraph = Graph<SimpleGraph>;
341 #[test]
342 fn graph_can_be_linked_together() {
343 let store = Datastore {
344 store: vec![
345 Data {
346 id: (1),
347 edges: vec![(2), (3)],
348 },
349 Data {
350 id: (2),
351 edges: vec![(4)],
352 },
353 Data {
354 id: (3),
355 edges: vec![(4)],
356 },
357 Data {
358 id: (4),
359 edges: vec![(1)],
360 },
361 ],
362 };
363
364 let graph = SimpleGraphDefinition::build_graph(&store);
365
366 let node_edge_compare = |node: &Node<SimpleGraphDefinition>| {
367 let mut coll = vec![];
368 node.with_edges_iter(|edges| {
369 coll.extend(edges.cloned().map(|edge| edge.target.get_id()))
370 });
371 coll
372 };
373
374 let one: Node<SimpleGraphDefinition> = graph
375 .into_iter()
376 .find(|node: &Node<SimpleGraphDefinition>| node.get_id() == (1))
377 .unwrap();
378
379 assert_eq!(node_edge_compare(&one), vec![(2), (3)]);
380 let three = one.get_edge_ref(1).unwrap().target;
381
382 assert_eq!(node_edge_compare(&three), vec![(4)]);
383 let two = one.get_edge_ref(0).unwrap().target;
384 assert_eq!(node_edge_compare(&two), vec![(4)]);
385 let four = two.get_edge_ref(0).unwrap().target;
386 let alt_four = three.get_edge_ref(0).unwrap().target;
387 assert_eq!(node_edge_compare(&alt_four), node_edge_compare(&four));
388
389 assert_eq!(node_edge_compare(&four), vec![(1)]);
390 assert_eq!(node_edge_compare(&alt_four), vec![(1)]);
391 }
392
393 #[test]
394 fn graph_can_be_inverted() {
395 let store = Datastore {
396 store: vec![
397 Data {
398 id: (1),
399 edges: vec![(2), (3)],
400 },
401 Data {
402 id: (2),
403 edges: vec![(4)],
404 },
405 Data {
406 id: (3),
407 edges: vec![(4)],
408 },
409 Data {
410 id: (4),
411 edges: vec![(1)],
412 },
413 ],
414 };
415
416 let graph = SimpleGraphDefinition::build_graph(&store);
417 let graph = graph.invert();
418
419 let one = graph
420 .graph
421 .into_iter()
422 .find(|node| node.get_id() == (1))
423 .unwrap();
424
425 let node_edge_compare = |node: &Node<SimpleGraphDefinition>| {
426 let mut coll = vec![];
427 node.with_edges_iter(|edges| {
428 coll.extend(edges.cloned().map(|edge| edge.target.get_id()))
429 });
430 coll
431 };
432
433 assert_eq!(node_edge_compare(&one), vec![(4)]);
434
435 let four = one.get_edge_ref(0).unwrap().target;
436 let three = four.get_edge_ref(1).unwrap().target;
437 let two = four.get_edge_ref(0).unwrap().target;
438
439 assert_eq!(node_edge_compare(&three), vec![(1)]);
440 assert_eq!(node_edge_compare(&two), vec![(1)]);
441
442 let alt_one = two.get_edge_ref(0).unwrap().target;
443 assert_eq!(node_edge_compare(&alt_one), node_edge_compare(&one));
444
445 assert_eq!(
446 HashSet::from_iter(node_edge_compare(&four).into_iter()),
447 HashSet::from([2, 3])
448 );
449 assert_eq!(node_edge_compare(&alt_one), vec![(4)]);
450 }
451}
452impl<'a, T: GraphDefinition> dot::GraphWalk<'a, Node<T>, Edge<T>> for ConcreteGraph<T> {
453 fn nodes(&'a self) -> Nodes<'a, Node<T>> {
454 let nodes = self.all_nodes();
455 Nodes::Owned(nodes.collect())
456 }
457
458 fn edges(&'a self) -> dot::Edges<'a, Edge<T>> {
459 dot::Edges::Owned(self.all_edges().collect())
460 }
461
462 fn source(&'a self, edge: &Edge<T>) -> Node<T> {
463 edge.origin.clone()
464 }
465
466 fn target(&'a self, edge: &Edge<T>) -> Node<T> {
467 edge.target.clone()
468 }
469}
470
471impl<'a, T: GraphDefinition> dot::Labeller<'a, Node<T>, Edge<T>> for ConcreteGraph<T> {
472 fn graph_id(&'a self) -> Id<'a> {
473 Id::new("webpack_stats").unwrap()
474 }
475
476 fn node_id(&'a self, n: &Node<T>) -> Id<'a> {
477 Id::new(n.get_id().escaped()).unwrap()
478 }
479}