Move graph functionality into `graph` module
Dependencies
- [2]
UQJO24KBUse `forceatlas2` to construct graph layout - [3]
B2L26LOAStore index of dependency nodes - [4]
LOR3KOXGParse JSON output from `cargo build --timings` - [5]
ZPFD3275Switch from `cargo_metadata`+`petgraph` to `guppy` - [6]
Q3Z6XMP5Migrate dependency tree to `petgraph::Graph` - [7]
7CVIL7UJCreate simple metadata parser - [8]
JVYWRCPTAdd basic chart visualisation - [9]
O7TNUABZMigrate `CrateMetadata::graph_data()` from `HashMap` to `petgraph` representation
Change contents
- edit in src/main.rs at line 1
use std::collections::HashMap; - replacement in src/main.rs at line 2[3.85]→[2.33:58](∅→∅),[2.58]→[3.0:13](∅→∅),[3.85]→[3.0:13](∅→∅),[3.13]→[2.59:119](∅→∅),[2.119]→[2.119:151](∅→∅),[3.82]→[3.123:126](∅→∅),[3.147]→[3.123:126](∅→∅),[2.151]→[3.123:126](∅→∅),[3.123]→[3.123:126](∅→∅)
use forceatlas2::Layout;use guppy::{graph::{DependencyDirection, PackageGraph, PackageSet},MetadataCommand, PackageId,};use guppy::{graph::PackageGraph, MetadataCommand}; - edit in src/main.rs at line 4
mod graph; - edit in src/main.rs at line 6[3.2725]→[2.152:484](∅→∅),[2.484]→[3.265:266](∅→∅),[3.2725]→[3.265:266](∅→∅),[3.265]→[3.265:266](∅→∅),[3.266]→[2.485:1077](∅→∅)
fn graph_layout<'graph>(package_set: &'graph PackageSet,) -> impl Iterator<Item = (&'graph PackageId, forceatlas2::Node<f64, 2>)> {let link_index: HashMap<&PackageId, usize> = package_set.package_ids(DependencyDirection::Forward).enumerate().map(|(index, id)| (id, index)).collect();let edges = package_set.links(DependencyDirection::Forward).map(|link| (link.from(), link.to())).map(|(from, to)| (link_index.get(from.id()), link_index.get(to.id()))).map(|(from, to)| (*from.unwrap(), *to.unwrap())).map(|edge| (edge, 1.0)).collect();let sizes = package_set.package_ids(DependencyDirection::Forward).map(|_id| 1.0);let mut layout =Layout::from_graph_with_degree_mass(edges, sizes, forceatlas2::Settings::default());for _step in 0..1_000 {layout.iteration();} - edit in src/main.rs at line 7[2.1078]→[2.1078:1414](∅→∅),[2.1414]→[3.83:259](∅→∅),[3.266]→[3.83:259](∅→∅),[3.259]→[2.1415:1503](∅→∅),[3.259]→[3.429:430](∅→∅),[2.1503]→[3.429:430](∅→∅),[3.429]→[3.429:430](∅→∅),[3.430]→[2.1504:1746](∅→∅),[2.1746]→[3.541:680](∅→∅),[3.541]→[3.541:680](∅→∅),[3.680]→[3.761:762](∅→∅),[3.761]→[3.761:762](∅→∅),[3.762]→[3.681:1089](∅→∅),[3.1089]→[3.1215:1216](∅→∅),[3.1215]→[3.1215:1216](∅→∅),[3.1216]→[3.1090:1174](∅→∅),[3.1174]→[3.697:706](∅→∅),[3.697]→[3.697:706](∅→∅)
// TODO: validate that PackageSet::package_ids() is stable; it is used twice (link_index, here)// so need to validate ordering is consistent (or, find a cleaner solution)layout.nodes.into_iter().zip(package_set.package_ids(DependencyDirection::Forward)).map(|(node, id)| (id, node))}fn graph_data(graph: &PackageGraph) -> charming::series::GraphData {let categories = vec![charming::series::GraphCategory {name: String::from("default"),}];let package_set = graph.resolve_all();let layout = graph_layout(&package_set);let nodes = layout.map(|(id, node)| charming::series::GraphNode {id: id.repr().to_string(),name: graph.metadata(id).unwrap().name().to_string(),x: node.pos.x(),y: node.pos.y(),value: 1_f64,category: 0,symbol_size: 1_f64,label: None,}).collect();let links = graph.query_forward(graph.package_ids()).unwrap().resolve().links(DependencyDirection::Forward).map(|link| link.endpoints()).map(|(source, target)| charming::series::GraphLink {source: source.id().repr().to_string(),target: target.id().repr().to_string(),value: None,}).collect();charming::series::GraphData {nodes,links,categories,}} - replacement in src/main.rs at line 18
.data(graph_data(&package_graph)),.data(graph::data(&package_graph)), - file addition: graph.rs[3.15]
use std::collections::HashMap;use forceatlas2::Layout;use guppy::{graph::{DependencyDirection, PackageGraph, PackageSet},PackageId,};fn layout<'graph>(package_set: &'graph PackageSet,) -> impl Iterator<Item = (&'graph PackageId, forceatlas2::Node<f64, 2>)> {let link_index: HashMap<&PackageId, usize> = package_set.package_ids(DependencyDirection::Forward).enumerate().map(|(index, id)| (id, index)).collect();let edges = package_set.links(DependencyDirection::Forward).map(|link| (link.from(), link.to())).map(|(from, to)| (link_index.get(from.id()), link_index.get(to.id()))).map(|(from, to)| (*from.unwrap(), *to.unwrap())).map(|edge| (edge, 1.0)).collect();let sizes = package_set.package_ids(DependencyDirection::Forward).map(|_id| 1.0);let mut layout =Layout::from_graph_with_degree_mass(edges, sizes, forceatlas2::Settings::default());for _step in 0..1_000 {layout.iteration();}// TODO: validate that PackageSet::package_ids() is stable; it is used twice (link_index, here)// so need to validate ordering is consistent (or, find a cleaner solution)layout.nodes.into_iter().zip(package_set.package_ids(DependencyDirection::Forward)).map(|(node, id)| (id, node))}pub fn data(graph: &PackageGraph) -> charming::series::GraphData {let categories = vec![charming::series::GraphCategory {name: String::from("default"),}];let package_set = graph.resolve_all();let layout = layout(&package_set);let nodes = layout.map(|(id, node)| charming::series::GraphNode {id: id.repr().to_string(),name: graph.metadata(id).unwrap().name().to_string(),x: node.pos.x(),y: node.pos.y(),value: 1_f64,category: 0,symbol_size: 1_f64,label: None,}).collect();let links = graph.query_forward(graph.package_ids()).unwrap().resolve().links(DependencyDirection::Forward).map(|link| link.endpoints()).map(|(source, target)| charming::series::GraphLink {source: source.id().repr().to_string(),target: target.id().repr().to_string(),value: None,}).collect();charming::series::GraphData {nodes,links,categories,}}