component/
deps.rs

1use petgraph::algo;
2use petgraph::graphmap::DiGraphMap;
3use crate::Component;
4
5// The verb to use when thinking about the relationships between the dependency
6// vertices is "depends upon." A component will declare the things it depends
7// upon, and the direction of the graph is from component -> dep 1,
8// component -> dep 2, etc.
9//
10// Great resources for reading up on petgraph:
11// * https://timothy.hobbs.cz/rust-play/petgraph_review.html
12// * https://timothy.hobbs.cz/rust-play/petgraph-internals.html
13// * https://depth-first.com/articles/2020/02/03/graphs-in-rust-an-introduction-to-petgraph/
14
15pub fn add_component(g: &mut DiGraphMap<&str, String>, c: &Component) {
16    let comp_vert = g.add_node(c.name);
17    for dep in c.dependencies.iter() {
18        let dep_vert = g.add_node(dep);
19        g.add_edge(comp_vert, dep_vert, format!("{} -> {}", c.name, dep));
20    }
21}
22
23pub fn add_components(g: &mut DiGraphMap<&str, String>, cs: Vec<Component>) {
24    for c in cs.iter() {
25        add_component(g, c);
26    }
27}
28
29pub fn sort<'a>(g: &DiGraphMap<&'a str, String>) -> Vec<&'a str> {
30    match algo::toposort(g, Option::None) {
31        Ok(sorted) => {
32            sorted
33                .iter()
34                .rev()
35                .map(| item: &&str | *item)
36                .collect()
37        },
38        Err(e) => panic!("Cyclic dependency detected for {}", e.node_id()),
39    }
40}
41
42//*************************************************************************//
43//*   Tests   *************************************************************//
44//*************************************************************************//
45
46#[cfg(test)]
47mod tests {
48    use petgraph::Directed;
49    use petgraph::graphmap::GraphMap;
50    use super::*;
51
52    #[test]
53    fn new_test() {
54        let mut g = GraphMap::<&str, String, Directed>::new();
55        let deps = vec![
56            Component{
57                name: "myapp::components::comp1",
58                dependencies: vec![
59                    "myapp::components::comp2",
60                    "myapp::components::comp3",
61                    "myapp::components::comp4",
62                ]
63            },
64            Component {
65                name: "myapp::components::comp4",
66                dependencies: vec!["myapp::components::comp5"],
67            },
68            Component {
69                name: "myapp::components::comp5",
70                dependencies: vec!["myapp::components::comp6"],
71            },
72            Component {
73                name: "myapp::components::comp6",
74                dependencies: vec!["myapp::components::comp7"],
75            },
76        ];
77        add_components(&mut g, deps);
78        println!("{:?}", g);
79        let sorted = sort(&g);
80        assert_eq!(*sorted.last().unwrap(), "myapp::components::comp1");
81    }
82}