Skip to content

Commit 392d68b

Browse files
authored
refactor(tree): Abstract the concept of an edge (#15233)
### What does this PR try to resolve? I'm playing around with `--depth public` to help view and communicate public/private dependency test states and ended up doing these refactors along the way and felt they were generally useful independent of my `--depth public` work. ### How should we test and review this PR? ### Additional information
2 parents 2dcb9b0 + 05e5d6e commit 392d68b

File tree

2 files changed

+109
-77
lines changed

2 files changed

+109
-77
lines changed

src/cargo/ops/tree/graph.rs

Lines changed: 106 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,22 @@ pub enum Node {
2626
},
2727
}
2828

29+
#[derive(Debug, Copy, Hash, Eq, Clone, PartialEq)]
30+
pub struct Edge {
31+
kind: EdgeKind,
32+
node: usize,
33+
}
34+
35+
impl Edge {
36+
pub fn kind(&self) -> EdgeKind {
37+
self.kind
38+
}
39+
40+
pub fn node(&self) -> usize {
41+
self.node
42+
}
43+
}
44+
2945
/// The kind of edge, for separating dependencies into different sections.
3046
#[derive(Debug, Copy, Hash, Eq, Clone, PartialEq)]
3147
pub enum EdgeKind {
@@ -42,20 +58,32 @@ pub enum EdgeKind {
4258
/// The value is a `Vec` because each edge kind can have multiple outgoing
4359
/// edges. For example, package "foo" can have multiple normal dependencies.
4460
#[derive(Clone)]
45-
struct Edges(HashMap<EdgeKind, Vec<usize>>);
61+
struct Edges(HashMap<EdgeKind, Vec<Edge>>);
4662

4763
impl Edges {
4864
fn new() -> Edges {
4965
Edges(HashMap::new())
5066
}
5167

5268
/// Adds an edge pointing to the given node.
53-
fn add_edge(&mut self, kind: EdgeKind, index: usize) {
54-
let indexes = self.0.entry(kind).or_default();
55-
if !indexes.contains(&index) {
56-
indexes.push(index)
69+
fn add_edge(&mut self, edge: Edge) {
70+
let indexes = self.0.entry(edge.kind()).or_default();
71+
if !indexes.contains(&edge) {
72+
indexes.push(edge)
5773
}
5874
}
75+
76+
fn all(&self) -> impl Iterator<Item = &Edge> + '_ {
77+
self.0.values().flatten()
78+
}
79+
80+
fn of_kind(&self, kind: &EdgeKind) -> &[Edge] {
81+
self.0.get(kind).map(Vec::as_slice).unwrap_or_default()
82+
}
83+
84+
fn is_empty(&self) -> bool {
85+
self.0.is_empty()
86+
}
5987
}
6088

6189
/// A graph of dependencies.
@@ -104,21 +132,17 @@ impl<'a> Graph<'a> {
104132
}
105133

106134
/// Returns a list of nodes the given node index points to for the given kind.
107-
pub fn connected_nodes(&self, from: usize, kind: &EdgeKind) -> Vec<usize> {
108-
match self.edges[from].0.get(kind) {
109-
Some(indexes) => {
110-
// Created a sorted list for consistent output.
111-
let mut indexes = indexes.clone();
112-
indexes.sort_unstable_by(|a, b| self.nodes[*a].cmp(&self.nodes[*b]));
113-
indexes
114-
}
115-
None => Vec::new(),
116-
}
135+
pub fn edges(&self, from: usize, kind: &EdgeKind) -> Vec<Edge> {
136+
let edges = self.edges[from].of_kind(kind);
137+
// Created a sorted list for consistent output.
138+
let mut edges = edges.to_owned();
139+
edges.sort_unstable_by(|a, b| self.nodes[a.node()].cmp(&self.nodes[b.node()]));
140+
edges
117141
}
118142

119143
/// Returns `true` if the given node has any outgoing edges.
120144
pub fn has_outgoing_edges(&self, index: usize) -> bool {
121-
!self.edges[index].0.is_empty()
145+
!self.edges[index].is_empty()
122146
}
123147

124148
/// Gets a node by index.
@@ -184,11 +208,13 @@ impl<'a> Graph<'a> {
184208
let new_from = new_graph.add_node(node);
185209
remap[index] = Some(new_from);
186210
// Visit dependencies.
187-
for (edge_kind, edge_indexes) in &graph.edges[index].0 {
188-
for edge_index in edge_indexes {
189-
let new_to_index = visit(graph, new_graph, remap, *edge_index);
190-
new_graph.edges[new_from].add_edge(*edge_kind, new_to_index);
191-
}
211+
for edge in graph.edges[index].all() {
212+
let new_to_index = visit(graph, new_graph, remap, edge.node());
213+
let new_edge = Edge {
214+
kind: edge.kind(),
215+
node: new_to_index,
216+
};
217+
new_graph.edges[new_from].add_edge(new_edge);
192218
}
193219
new_from
194220
}
@@ -205,10 +231,12 @@ impl<'a> Graph<'a> {
205231
pub fn invert(&mut self) {
206232
let mut new_edges = vec![Edges::new(); self.edges.len()];
207233
for (from_idx, node_edges) in self.edges.iter().enumerate() {
208-
for (kind, edges) in &node_edges.0 {
209-
for edge_idx in edges {
210-
new_edges[*edge_idx].add_edge(*kind, from_idx);
211-
}
234+
for edge in node_edges.all() {
235+
let new_edge = Edge {
236+
kind: edge.kind(),
237+
node: from_idx,
238+
};
239+
new_edges[edge.node()].add_edge(new_edge);
212240
}
213241
}
214242
self.edges = new_edges;
@@ -280,7 +308,7 @@ pub fn build<'a>(
280308
) -> CargoResult<Graph<'a>> {
281309
let mut graph = Graph::new(package_map);
282310
let mut members_with_features = ws.members_with_features(specs, cli_features)?;
283-
members_with_features.sort_unstable_by_key(|e| e.0.package_id());
311+
members_with_features.sort_unstable_by_key(|(member, _)| member.package_id());
284312
for (member, cli_features) in members_with_features {
285313
let member_id = member.package_id();
286314
let features_for = FeaturesFor::from_for_host(member.proc_macro());
@@ -428,36 +456,28 @@ fn add_pkg(
428456
requested_kind,
429457
opts,
430458
);
459+
let new_edge = Edge {
460+
kind: EdgeKind::Dep(dep.kind()),
461+
node: dep_index,
462+
};
431463
if opts.graph_features {
432464
// Add the dependency node with feature nodes in-between.
433465
dep_name_map
434466
.entry(dep.name_in_toml())
435467
.or_default()
436468
.insert((dep_index, dep.is_optional()));
437469
if dep.uses_default_features() {
438-
add_feature(
439-
graph,
440-
INTERNED_DEFAULT,
441-
Some(from_index),
442-
dep_index,
443-
EdgeKind::Dep(dep.kind()),
444-
);
470+
add_feature(graph, INTERNED_DEFAULT, Some(from_index), new_edge);
445471
}
446472
for feature in dep.features().iter() {
447-
add_feature(
448-
graph,
449-
*feature,
450-
Some(from_index),
451-
dep_index,
452-
EdgeKind::Dep(dep.kind()),
453-
);
473+
add_feature(graph, *feature, Some(from_index), new_edge);
454474
}
455475
if !dep.uses_default_features() && dep.features().is_empty() {
456476
// No features, use a direct connection.
457-
graph.edges[from_index].add_edge(EdgeKind::Dep(dep.kind()), dep_index);
477+
graph.edges[from_index].add_edge(new_edge);
458478
}
459479
} else {
460-
graph.edges[from_index].add_edge(EdgeKind::Dep(dep.kind()), dep_index);
480+
graph.edges[from_index].add_edge(new_edge);
461481
}
462482
}
463483
}
@@ -486,23 +506,30 @@ fn add_feature(
486506
graph: &mut Graph<'_>,
487507
name: InternedString,
488508
from: Option<usize>,
489-
to: usize,
490-
kind: EdgeKind,
509+
to: Edge,
491510
) -> (bool, usize) {
492511
// `to` *must* point to a package node.
493-
assert!(matches! {graph.nodes[to], Node::Package{..}});
512+
assert!(matches! {graph.nodes[to.node()], Node::Package{..}});
494513
let node = Node::Feature {
495-
node_index: to,
514+
node_index: to.node(),
496515
name,
497516
};
498517
let (missing, node_index) = match graph.index.get(&node) {
499518
Some(idx) => (false, *idx),
500519
None => (true, graph.add_node(node)),
501520
};
502521
if let Some(from) = from {
503-
graph.edges[from].add_edge(kind, node_index);
522+
let from_edge = Edge {
523+
kind: to.kind(),
524+
node: node_index,
525+
};
526+
graph.edges[from].add_edge(from_edge);
504527
}
505-
graph.edges[node_index].add_edge(EdgeKind::Feature, to);
528+
let to_edge = Edge {
529+
kind: EdgeKind::Feature,
530+
node: to.node(),
531+
};
532+
graph.edges[node_index].add_edge(to_edge);
506533
(missing, node_index)
507534
}
508535

@@ -535,7 +562,11 @@ fn add_cli_features(
535562
for fv in to_add {
536563
match fv {
537564
FeatureValue::Feature(feature) => {
538-
let index = add_feature(graph, feature, None, package_index, EdgeKind::Feature).1;
565+
let feature_edge = Edge {
566+
kind: EdgeKind::Feature,
567+
node: package_index,
568+
};
569+
let index = add_feature(graph, feature, None, feature_edge).1;
539570
graph.cli_features.insert(index);
540571
}
541572
// This is enforced by CliFeatures.
@@ -565,12 +596,18 @@ fn add_cli_features(
565596
for (dep_index, is_optional) in dep_connections {
566597
if is_optional {
567598
// Activate the optional dep on self.
568-
let index =
569-
add_feature(graph, dep_name, None, package_index, EdgeKind::Feature).1;
599+
let feature_edge = Edge {
600+
kind: EdgeKind::Feature,
601+
node: package_index,
602+
};
603+
let index = add_feature(graph, dep_name, None, feature_edge).1;
570604
graph.cli_features.insert(index);
571605
}
572-
let index =
573-
add_feature(graph, dep_feature, None, dep_index, EdgeKind::Feature).1;
606+
let dep_edge = Edge {
607+
kind: EdgeKind::Feature,
608+
node: dep_index,
609+
};
610+
let index = add_feature(graph, dep_feature, None, dep_edge).1;
574611
graph.cli_features.insert(index);
575612
}
576613
}
@@ -626,13 +663,11 @@ fn add_feature_rec(
626663
for fv in fvs {
627664
match fv {
628665
FeatureValue::Feature(dep_name) => {
629-
let (missing, feat_index) = add_feature(
630-
graph,
631-
*dep_name,
632-
Some(from),
633-
package_index,
634-
EdgeKind::Feature,
635-
);
666+
let feature_edge = Edge {
667+
kind: EdgeKind::Feature,
668+
node: package_index,
669+
};
670+
let (missing, feat_index) = add_feature(graph, *dep_name, Some(from), feature_edge);
636671
// Don't recursive if the edge already exists to deal with cycles.
637672
if missing {
638673
add_feature_rec(
@@ -678,21 +713,18 @@ fn add_feature_rec(
678713
let dep_pkg_id = graph.package_id_for_index(dep_index);
679714
if is_optional && !weak {
680715
// Activate the optional dep on self.
681-
add_feature(
682-
graph,
683-
*dep_name,
684-
Some(from),
685-
package_index,
686-
EdgeKind::Feature,
687-
);
716+
let feature_edge = Edge {
717+
kind: EdgeKind::Feature,
718+
node: package_index,
719+
};
720+
add_feature(graph, *dep_name, Some(from), feature_edge);
688721
}
689-
let (missing, feat_index) = add_feature(
690-
graph,
691-
*dep_feature,
692-
Some(from),
693-
dep_index,
694-
EdgeKind::Feature,
695-
);
722+
let dep_edge = Edge {
723+
kind: EdgeKind::Feature,
724+
node: dep_index,
725+
};
726+
let (missing, feat_index) =
727+
add_feature(graph, *dep_feature, Some(from), dep_edge);
696728
if missing {
697729
add_feature_rec(
698730
graph,

src/cargo/ops/tree/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ fn print_dependencies<'a>(
383383
print_stack: &mut Vec<usize>,
384384
kind: &EdgeKind,
385385
) {
386-
let deps = graph.connected_nodes(node_index, kind);
386+
let deps = graph.edges(node_index, kind);
387387
if deps.is_empty() {
388388
return;
389389
}
@@ -420,7 +420,7 @@ fn print_dependencies<'a>(
420420
.iter()
421421
.filter(|dep| {
422422
// Filter out packages to prune.
423-
match graph.node(**dep) {
423+
match graph.node(dep.node()) {
424424
Node::Package { package_id, .. } => {
425425
if filter_non_workspace_member && !ws.is_member_id(*package_id) {
426426
return false;
@@ -437,7 +437,7 @@ fn print_dependencies<'a>(
437437
print_node(
438438
ws,
439439
graph,
440-
*dependency,
440+
dependency.node(),
441441
format,
442442
symbols,
443443
pkgs_to_prune,

0 commit comments

Comments
 (0)