pugio_lib/lib.rs
1/*!
2`pugio-lib` is a library to generate, filter, and output dependency graphs of Rust projects,
3for dependency visualisation such as bloat or security auditing. It is used as the backend of
4the [`pugio`](https://crates.io/crates/pugio) CLI tool.
5
6It provides traits such as [`coloring::Gradient`], [`coloring::Values`], and
7[`template::Templating`] for full customisation of the generated graphs beyond only binary size
8analysis.
9
10# Example
11Here is a simple example of how to use `pugio-lib` to generate a dependency graph in DOT format,
12using custom defined templating, values and gradient implementations.
13
14```no_run
15use pugio_lib::graph::Graph;
16use pugio_lib::template::Templating;
17use pugio_lib::coloring::{Color, Gradient, Values};
18
19// Output of `cargo tree --edges=no-build,no-proc-macro,no-dev,features --prefix=depth --color=never ...`
20let cargo_tree_output = "...";
21// Output of `cargo bloat -n0 --message-format=json --crates ...`
22let cargo_bloat_output = "...";
23
24let mut graph = Graph::new(cargo_tree_output, cargo_bloat_output, false, None);
25
26// Remove dependencies more than 3 levels deep.
27graph.remove_deep_deps(3);
28
29// Remove all dependencies that are path or git specified.
30let iter = graph.node_indices().filter(|i| {
31 graph.node_weight(*i).extra().ends_with(")")
32}).collect::<Vec<_>>().into_iter();
33
34graph.remove_indices(iter);
35
36// Custom Gradient implementation.
37struct CustomGradient;
38
39impl Gradient for CustomGradient {
40 type Input = usize;
41
42 // Ignore `dark_mode` and `inverse` for simplicity.
43 fn color(&self, input: Self::Input, dark_mode: bool, inverse: bool) -> Color {
44 if input > 4096 {
45 Color {
46 r: 255,
47 g: 0,
48 b: 0,
49 }
50 } else {
51 Color {
52 r: 0,
53 g: 255,
54 b: 0,
55 }
56 }
57 }
58}
59
60// Custom Templating implementation.
61struct CustomTemplate;
62
63impl Templating for CustomTemplate {
64 type Context = bool;
65 type Value = &'static str;
66
67 fn node(
68 &self,
69 graph: &Graph,
70 index: usize,
71 value: Self::Value,
72 context: Self::Context,
73 ) -> (String, String) {
74 let tooltip = if context {
75 value.to_string()
76 } else {
77 "".to_string()
78 };
79 (graph.node_weight(index).short().to_string(), tooltip)
80 }
81
82 fn edge(
83 &self,
84 _graph: &Graph,
85 _source: usize,
86 _target: usize,
87 ) -> (String, String) {
88 ("".to_string(), "".to_string())
89 }
90}
91
92// Custom Values implementation.
93struct CustomValues(Vec<usize>);
94
95impl CustomValues {
96 fn new(graph: &Graph) -> Self {
97 let mut values = vec![0; graph.node_capacity()];
98 for index in graph.node_indices() {
99 let size = graph.size(index).unwrap_or_default();
100 values[index] = size;
101 }
102 Self(values)
103 }
104}
105
106impl Values for CustomValues {
107 type Context = bool;
108 type Value = &'static str;
109 type Output = usize;
110
111 fn context(&self) -> Self::Context {
112 true
113 }
114
115 fn value(&self, index: usize) -> Self::Value {
116 if self.0[index] > 4096 {
117 "large"
118 } else {
119 "small"
120 }
121 }
122
123 fn output(&self, index: usize) -> Self::Output {
124 self.0[index]
125 }
126}
127
128let custom_values = CustomValues::new(&graph);
129
130// Output the graph in DOT format.
131let dot_output = graph.output_dot(&Default::default(), &CustomTemplate, &custom_values, &CustomGradient);
132```
133*/
134
135mod cargo;
136pub mod coloring;
137pub mod error;
138pub mod graph;
139pub mod template;