This is looking like a much better implementation of what has been hacked together so far. The only concern is storing timings output cleanly, but I think guppy's architecture will make it easier!
ZPFD3275NTWST7F5YCWYOOUS3QB5HE23LUOZXZIND4HBFSX62NCQC #[derive(Clone, Debug)]struct CrateMetadata<'metadata> {data: &'metadata cargo_metadata::Metadata,packages: &'metadata Vec<Node>,root: &'metadata PackageId,dependency_tree: Graph<&'metadata PackageId, usize>,}
impl<'metadata> CrateMetadata<'metadata> {fn new(metadata: &'metadata cargo_metadata::Metadata) -> Self {let resolve = metadata.resolve.as_ref().expect("Cargo did not resolve dependencies");let root = resolve.root.as_ref().expect("Must select a root crate");let edge_count = resolve.nodes.iter().map(|node| node.deps.len()).count();let mut dependency_tree = Graph::with_capacity(metadata.packages.len(), edge_count);let mut node_indexes = HashMap::new();
fn graph_data(graph: &PackageGraph) -> charming::series::GraphData {let categories = vec![charming::series::GraphCategory {name: String::from("default"),}];
for node in &metadata.packages {let node_index = dependency_tree.add_node(&node.id);node_indexes.insert(&node.id, node_index);}for resolved_dependency in &resolve.nodes {let parent_index = node_indexes.get(&resolved_dependency.id).unwrap();for child in &resolved_dependency.deps {let child_index = node_indexes.get(&child.pkg).unwrap();dependency_tree.add_edge(*parent_index, *child_index, 1);}}Self {data: metadata,packages: &resolve.nodes,root,dependency_tree,}}fn graph_data(&self) -> charming::series::GraphData {let categories = vec![charming::series::GraphCategory {name: String::from("default"),}];let nodes = self.dependency_tree.node_weights().enumerate().map(|(coords, id)| charming::series::GraphNode {id: id.to_string(),name: self.data[*id].name.clone(),x: coords as f64,y: coords as f64,value: 1_f64,category: 0,symbol_size: 1_f64,label: None,}).collect();
let nodes = graph.packages().enumerate().map(|(coords, package)| charming::series::GraphNode {id: package.id().repr().to_string(),name: package.name().to_string(),x: coords as f64,y: coords as f64,value: 1_f64,category: 0,symbol_size: 1_f64,label: None,}).collect();
let links = self.dependency_tree.edge_indices().map(|edge_idx| self.dependency_tree.edge_endpoints(edge_idx)).filter_map(|optional_endpoints| optional_endpoints).map(|(source_idx, target_idx)| {(&self.dependency_tree[source_idx],&self.dependency_tree[target_idx],)}).map(|(source, target)| charming::series::GraphLink {source: source.repr.clone(),target: target.repr.clone(),value: 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();
let cmd = cargo_metadata::MetadataCommand::new();let metadata = cmd.exec().expect("Cargo did not resolve metadata");let root_crate = CrateMetadata::new(&metadata);
let mut cmd = MetadataCommand::new();let package_graph = PackageGraph::from_command(&mut cmd).unwrap();
[[package]]name = "getrandom"version = "0.2.14"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"dependencies = ["cfg-if","libc","wasi",][[package]]name = "guppy"version = "0.17.5"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "34e99a7734579b834a076ef11789783c153c6eb5fb3520ed15bc41f483f0f317"dependencies = ["ahash","camino","cargo_metadata","cfg-if","debug-ignore","fixedbitset","guppy-workspace-hack","indexmap","itertools","nested","once_cell","pathdiff","petgraph","semver","serde","serde_json","smallvec","static_assertions","target-spec",][[package]]name = "guppy-workspace-hack"version = "0.1.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "92620684d99f750bae383ecb3be3748142d6095760afd5cbcf2261e9a279d780"
[[package]]name = "smallvec"version = "1.13.2"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"[[package]]name = "static_assertions"version = "1.1.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
name = "target-lexicon"version = "0.12.14"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f"[[package]]name = "target-spec"version = "3.1.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "36a8e795b1824524d13cdf04f73cf8b4f244ce86c96b4d2a83a6ca1a753d2752"dependencies = ["cfg-expr","guppy-workspace-hack","target-lexicon","unicode-ident",][[package]]
[[package]]name = "wasi"version = "0.11.0+wasi-snapshot-preview1"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"[[package]]name = "zerocopy"version = "0.7.32"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"dependencies = ["zerocopy-derive",][[package]]name = "zerocopy-derive"version = "0.7.32"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"dependencies = ["proc-macro2","quote","syn",]