diff --git a/lib/src/default_index/revset_engine.rs b/lib/src/default_index/revset_engine.rs index 452c1a4d10..ea26fedcb7 100644 --- a/lib/src/default_index/revset_engine.rs +++ b/lib/src/default_index/revset_engine.rs @@ -103,7 +103,7 @@ impl RevsetImpl { pub fn iter_graph_impl( &self, skip_transitive_edges: bool, - ) -> impl Iterator)> { + ) -> impl Iterator>)> { let index = self.index.clone(); let walk = self.inner.positions(); let mut graph_walk = RevsetGraphWalk::new(walk, skip_transitive_edges); @@ -147,7 +147,9 @@ impl Revset for RevsetImpl { })) } - fn iter_graph<'a>(&self) -> Box)> + 'a> + fn iter_graph<'a>( + &self, + ) -> Box>)> + 'a> where Self: 'a, { diff --git a/lib/src/default_index/revset_graph_iterator.rs b/lib/src/default_index/revset_graph_iterator.rs index e88bb62007..184f3883a7 100644 --- a/lib/src/default_index/revset_graph_iterator.rs +++ b/lib/src/default_index/revset_graph_iterator.rs @@ -49,7 +49,7 @@ impl IndexGraphEdge { IndexGraphEdge { target, edge_type } } - fn to_revset_edge(self, index: &CompositeIndex) -> RevsetGraphEdge { + fn to_revset_edge(self, index: &CompositeIndex) -> RevsetGraphEdge { RevsetGraphEdge { target: index.entry_by_pos(self.target).commit_id(), edge_type: self.edge_type, @@ -333,7 +333,7 @@ impl<'a> RevsetGraphWalk<'a> { } impl RevWalk for RevsetGraphWalk<'_> { - type Item = (CommitId, Vec); + type Item = (CommitId, Vec>); fn next(&mut self, index: &CompositeIndex) -> Option { let position = self.next_index_position(index)?; diff --git a/lib/src/revset.rs b/lib/src/revset.rs index 027e2014ac..ff88897b94 100644 --- a/lib/src/revset.rs +++ b/lib/src/revset.rs @@ -2567,7 +2567,9 @@ pub trait Revset: fmt::Debug { where Self: 'a; - fn iter_graph<'a>(&self) -> Box)> + 'a> + fn iter_graph<'a>( + &self, + ) -> Box>)> + 'a> where Self: 'a; diff --git a/lib/src/revset_graph.rs b/lib/src/revset_graph.rs index ff3c4b72ff..fd9539caff 100644 --- a/lib/src/revset_graph.rs +++ b/lib/src/revset_graph.rs @@ -15,31 +15,30 @@ #![allow(missing_docs)] use std::collections::{HashMap, HashSet, VecDeque}; - -use crate::backend::CommitId; +use std::hash::Hash; #[derive(Debug, PartialEq, Eq, Clone, Hash)] -pub struct RevsetGraphEdge { - pub target: CommitId, +pub struct RevsetGraphEdge { + pub target: N, pub edge_type: RevsetGraphEdgeType, } -impl RevsetGraphEdge { - pub fn missing(target: CommitId) -> Self { +impl RevsetGraphEdge { + pub fn missing(target: N) -> Self { Self { target, edge_type: RevsetGraphEdgeType::Missing, } } - pub fn direct(target: CommitId) -> Self { + pub fn direct(target: N) -> Self { Self { target, edge_type: RevsetGraphEdgeType::Direct, } } - pub fn indirect(target: CommitId) -> Self { + pub fn indirect(target: N) -> Self { Self { target, edge_type: RevsetGraphEdgeType::Indirect, @@ -54,45 +53,50 @@ pub enum RevsetGraphEdgeType { Indirect, } -fn reachable_targets(edges: &[RevsetGraphEdge]) -> impl DoubleEndedIterator { +fn reachable_targets( + edges: &[RevsetGraphEdge], +) -> impl DoubleEndedIterator { edges .iter() .filter(|edge| edge.edge_type != RevsetGraphEdgeType::Missing) .map(|edge| &edge.target) } -pub struct ReverseRevsetGraphIterator { - items: Vec<(CommitId, Vec)>, +pub struct ReverseRevsetGraphIterator { + items: Vec<(N, Vec>)>, } -impl ReverseRevsetGraphIterator { - pub fn new(input: impl IntoIterator)>) -> Self { +impl ReverseRevsetGraphIterator +where + N: Hash + Eq + PartialEq + Clone, +{ + pub fn new(input: impl IntoIterator>)>) -> Self { let mut entries = vec![]; - let mut reverse_edges: HashMap> = HashMap::new(); - for (commit_id, edges) in input { + let mut reverse_edges: HashMap>> = HashMap::new(); + for (node, edges) in input { for RevsetGraphEdge { target, edge_type } in edges { reverse_edges .entry(target) .or_default() .push(RevsetGraphEdge { - target: commit_id.clone(), + target: node.clone(), edge_type, }) } - entries.push(commit_id); + entries.push(node); } let mut items = vec![]; - for commit_id in entries.into_iter() { - let edges = reverse_edges.get(&commit_id).cloned().unwrap_or_default(); - items.push((commit_id, edges)); + for node in entries.into_iter() { + let edges = reverse_edges.get(&node).cloned().unwrap_or_default(); + items.push((node, edges)); } Self { items } } } -impl Iterator for ReverseRevsetGraphIterator { - type Item = (CommitId, Vec); +impl Iterator for ReverseRevsetGraphIterator { + type Item = (N, Vec>); fn next(&mut self) -> Option { self.items.pop() @@ -111,29 +115,39 @@ impl Iterator for ReverseRevsetGraphIterator { /// /// [Git]: https://github.blog/2022-08-30-gits-database-internals-ii-commit-history-queries/#topological-sorting #[derive(Clone, Debug)] -pub struct TopoGroupedRevsetGraphIterator { +pub struct TopoGroupedRevsetGraphIterator { input_iter: I, /// Graph nodes read from the input iterator but not yet emitted. - nodes: HashMap, + nodes: HashMap>, /// Stack of graph nodes to be emitted. - emittable_ids: Vec, + emittable_ids: Vec, /// List of new head nodes found while processing unpopulated nodes. - new_head_ids: VecDeque, + new_head_ids: VecDeque, /// Set of nodes which may be ancestors of `new_head_ids`. - blocked_ids: HashSet, + blocked_ids: HashSet, } -#[derive(Clone, Debug, Default)] -struct TopoGroupedGraphNode { +#[derive(Clone, Debug)] +struct TopoGroupedGraphNode { /// Graph nodes which must be emitted before. - child_ids: HashSet, + child_ids: HashSet, /// Graph edges to parent nodes. `None` until this node is populated. - edges: Option>, + edges: Option>>, } -impl TopoGroupedRevsetGraphIterator +impl Default for TopoGroupedGraphNode { + fn default() -> Self { + Self { + child_ids: Default::default(), + edges: None, + } + } +} + +impl TopoGroupedRevsetGraphIterator where - I: Iterator)>, + N: Clone + Hash + Eq + PartialEq, + I: Iterator>)>, { /// Wraps the given iterator to group topological branches. The input /// iterator must be topologically ordered. @@ -189,7 +203,7 @@ where } // Mark descendant nodes reachable from the blocking nodes - let mut to_visit: Vec<&CommitId> = self + let mut to_visit: Vec<&N> = self .blocked_ids .iter() .map(|id| { @@ -198,7 +212,7 @@ where id }) .collect(); - let mut visited: HashSet<&CommitId> = to_visit.iter().copied().collect(); + let mut visited: HashSet<&N> = to_visit.iter().copied().collect(); while let Some(id) = to_visit.pop() { let node = self.nodes.get(id).unwrap(); to_visit.extend(node.child_ids.iter().filter(|id| visited.insert(id))); @@ -229,7 +243,7 @@ where } #[must_use] - fn next_node(&mut self) -> Option<(CommitId, Vec)> { + fn next_node(&mut self) -> Option<(N, Vec>)> { // Based on Kahn's algorithm loop { if let Some(current_id) = self.emittable_ids.last() { @@ -274,11 +288,12 @@ where } } -impl Iterator for TopoGroupedRevsetGraphIterator +impl Iterator for TopoGroupedRevsetGraphIterator where - I: Iterator)>, + N: Clone + Hash + Eq + PartialEq, + I: Iterator>)>, { - type Item = (CommitId, Vec); + type Item = (N, Vec>); fn next(&mut self) -> Option { if let Some(node) = self.next_node() { @@ -296,27 +311,21 @@ mod tests { use renderdag::{Ancestor, GraphRowRenderer, Renderer as _}; use super::*; - use crate::object_id::ObjectId; - - fn id(c: char) -> CommitId { - let d = u8::try_from(c).unwrap(); - CommitId::new(vec![d]) - } - fn missing(c: char) -> RevsetGraphEdge { - RevsetGraphEdge::missing(id(c)) + fn missing(c: char) -> RevsetGraphEdge { + RevsetGraphEdge::missing(c) } - fn direct(c: char) -> RevsetGraphEdge { - RevsetGraphEdge::direct(id(c)) + fn direct(c: char) -> RevsetGraphEdge { + RevsetGraphEdge::direct(c) } - fn indirect(c: char) -> RevsetGraphEdge { - RevsetGraphEdge::indirect(id(c)) + fn indirect(c: char) -> RevsetGraphEdge { + RevsetGraphEdge::indirect(c) } - fn format_edge(edge: &RevsetGraphEdge) -> String { - let c = char::from(edge.target.as_bytes()[0]); + fn format_edge(edge: &RevsetGraphEdge) -> String { + let c = edge.target; match edge.edge_type { RevsetGraphEdgeType::Missing => format!("missing({c})"), RevsetGraphEdgeType::Direct => format!("direct({c})"), @@ -325,7 +334,7 @@ mod tests { } fn format_graph( - graph_iter: impl IntoIterator)>, + graph_iter: impl IntoIterator>)>, ) -> String { let mut renderer = GraphRowRenderer::new() .output() @@ -334,7 +343,7 @@ mod tests { graph_iter .into_iter() .map(|(id, edges)| { - let glyph = char::from(id.as_bytes()[0]).to_string(); + let glyph = id.to_string(); let message = edges.iter().map(format_edge).join(", "); let parents = edges .into_iter() @@ -352,10 +361,10 @@ mod tests { #[test] fn test_format_graph() { let graph = vec![ - (id('D'), vec![direct('C'), indirect('B')]), - (id('C'), vec![direct('A')]), - (id('B'), vec![missing('X')]), - (id('A'), vec![]), + ('D', vec![direct('C'), indirect('B')]), + ('C', vec![direct('A')]), + ('B', vec![missing('X')]), + ('A', vec![]), ]; insta::assert_snapshot!(format_graph(graph), @r###" D direct(C), indirect(B) @@ -371,9 +380,9 @@ mod tests { "###); } - fn topo_grouped(graph_iter: I) -> TopoGroupedRevsetGraphIterator + fn topo_grouped(graph_iter: I) -> TopoGroupedRevsetGraphIterator where - I: IntoIterator)>, + I: IntoIterator>)>, { TopoGroupedRevsetGraphIterator::new(graph_iter.into_iter()) } @@ -381,9 +390,9 @@ mod tests { #[test] fn test_topo_grouped_multiple_roots() { let graph = [ - (id('C'), vec![missing('Y')]), - (id('B'), vec![missing('X')]), - (id('A'), vec![]), + ('C', vec![missing('Y')]), + ('B', vec![missing('X')]), + ('A', vec![]), ]; insta::assert_snapshot!(format_graph(graph.iter().cloned()), @r###" C missing(Y) @@ -410,20 +419,20 @@ mod tests { // All nodes can be lazily emitted. let mut iter = topo_grouped(graph.iter().cloned().peekable()); - assert_eq!(iter.next().unwrap().0, id('C')); - assert_eq!(iter.input_iter.peek().unwrap().0, id('B')); - assert_eq!(iter.next().unwrap().0, id('B')); - assert_eq!(iter.input_iter.peek().unwrap().0, id('A')); + assert_eq!(iter.next().unwrap().0, 'C'); + assert_eq!(iter.input_iter.peek().unwrap().0, 'B'); + assert_eq!(iter.next().unwrap().0, 'B'); + assert_eq!(iter.input_iter.peek().unwrap().0, 'A'); } #[test] fn test_topo_grouped_trivial_fork() { let graph = vec![ - (id('E'), vec![direct('B')]), - (id('D'), vec![direct('A')]), - (id('C'), vec![direct('B')]), - (id('B'), vec![direct('A')]), - (id('A'), vec![]), + ('E', vec![direct('B')]), + ('D', vec![direct('A')]), + ('C', vec![direct('B')]), + ('B', vec![direct('A')]), + ('A', vec![]), ]; insta::assert_snapshot!(format_graph(graph.iter().cloned()), @r###" E direct(B) @@ -454,23 +463,23 @@ mod tests { // E can be lazy, then D and C will be queued. let mut iter = topo_grouped(graph.iter().cloned().peekable()); - assert_eq!(iter.next().unwrap().0, id('E')); - assert_eq!(iter.input_iter.peek().unwrap().0, id('D')); - assert_eq!(iter.next().unwrap().0, id('C')); - assert_eq!(iter.input_iter.peek().unwrap().0, id('B')); - assert_eq!(iter.next().unwrap().0, id('B')); - assert_eq!(iter.input_iter.peek().unwrap().0, id('A')); + assert_eq!(iter.next().unwrap().0, 'E'); + assert_eq!(iter.input_iter.peek().unwrap().0, 'D'); + assert_eq!(iter.next().unwrap().0, 'C'); + assert_eq!(iter.input_iter.peek().unwrap().0, 'B'); + assert_eq!(iter.next().unwrap().0, 'B'); + assert_eq!(iter.input_iter.peek().unwrap().0, 'A'); } #[test] fn test_topo_grouped_fork_interleaved() { let graph = vec![ - (id('F'), vec![direct('D')]), - (id('E'), vec![direct('C')]), - (id('D'), vec![direct('B')]), - (id('C'), vec![direct('B')]), - (id('B'), vec![direct('A')]), - (id('A'), vec![]), + ('F', vec![direct('D')]), + ('E', vec![direct('C')]), + ('D', vec![direct('B')]), + ('C', vec![direct('B')]), + ('B', vec![direct('A')]), + ('A', vec![]), ]; insta::assert_snapshot!(format_graph(graph.iter().cloned()), @r###" F direct(D) @@ -503,26 +512,26 @@ mod tests { // F can be lazy, then E will be queued, then C. let mut iter = topo_grouped(graph.iter().cloned().peekable()); - assert_eq!(iter.next().unwrap().0, id('F')); - assert_eq!(iter.input_iter.peek().unwrap().0, id('E')); - assert_eq!(iter.next().unwrap().0, id('D')); - assert_eq!(iter.input_iter.peek().unwrap().0, id('C')); - assert_eq!(iter.next().unwrap().0, id('E')); - assert_eq!(iter.input_iter.peek().unwrap().0, id('B')); + assert_eq!(iter.next().unwrap().0, 'F'); + assert_eq!(iter.input_iter.peek().unwrap().0, 'E'); + assert_eq!(iter.next().unwrap().0, 'D'); + assert_eq!(iter.input_iter.peek().unwrap().0, 'C'); + assert_eq!(iter.next().unwrap().0, 'E'); + assert_eq!(iter.input_iter.peek().unwrap().0, 'B'); } #[test] fn test_topo_grouped_fork_multiple_heads() { let graph = vec![ - (id('I'), vec![direct('E')]), - (id('H'), vec![direct('C')]), - (id('G'), vec![direct('A')]), - (id('F'), vec![direct('E')]), - (id('E'), vec![direct('C')]), - (id('D'), vec![direct('C')]), - (id('C'), vec![direct('A')]), - (id('B'), vec![direct('A')]), - (id('A'), vec![]), + ('I', vec![direct('E')]), + ('H', vec![direct('C')]), + ('G', vec![direct('A')]), + ('F', vec![direct('E')]), + ('E', vec![direct('C')]), + ('D', vec![direct('C')]), + ('C', vec![direct('A')]), + ('B', vec![direct('A')]), + ('A', vec![]), ]; insta::assert_snapshot!(format_graph(graph.iter().cloned()), @r###" I direct(E) @@ -567,28 +576,28 @@ mod tests { // I can be lazy, then H, G, and F will be queued. let mut iter = topo_grouped(graph.iter().cloned().peekable()); - assert_eq!(iter.next().unwrap().0, id('I')); - assert_eq!(iter.input_iter.peek().unwrap().0, id('H')); - assert_eq!(iter.next().unwrap().0, id('F')); - assert_eq!(iter.input_iter.peek().unwrap().0, id('E')); + assert_eq!(iter.next().unwrap().0, 'I'); + assert_eq!(iter.input_iter.peek().unwrap().0, 'H'); + assert_eq!(iter.next().unwrap().0, 'F'); + assert_eq!(iter.input_iter.peek().unwrap().0, 'E'); } #[test] fn test_topo_grouped_fork_parallel() { let graph = vec![ // Pull all sub graphs in reverse order: - (id('I'), vec![direct('A')]), - (id('H'), vec![direct('C')]), - (id('G'), vec![direct('E')]), + ('I', vec![direct('A')]), + ('H', vec![direct('C')]), + ('G', vec![direct('E')]), // Orphan sub graph G,F-E: - (id('F'), vec![direct('E')]), - (id('E'), vec![missing('Y')]), + ('F', vec![direct('E')]), + ('E', vec![missing('Y')]), // Orphan sub graph H,D-C: - (id('D'), vec![direct('C')]), - (id('C'), vec![missing('X')]), + ('D', vec![direct('C')]), + ('C', vec![missing('X')]), // Orphan sub graph I,B-A: - (id('B'), vec![direct('A')]), - (id('A'), vec![]), + ('B', vec![direct('A')]), + ('A', vec![]), ]; insta::assert_snapshot!(format_graph(graph.iter().cloned()), @r###" I direct(A) @@ -643,23 +652,23 @@ mod tests { fn test_topo_grouped_fork_nested() { fn sub_graph( chars: impl IntoIterator, - root_edges: Vec, - ) -> Vec<(CommitId, Vec)> { + root_edges: Vec>, + ) -> Vec<(char, Vec>)> { let [b, c, d, e, f]: [char; 5] = chars.into_iter().collect_vec().try_into().unwrap(); vec![ - (id(f), vec![direct(c)]), - (id(e), vec![direct(b)]), - (id(d), vec![direct(c)]), - (id(c), vec![direct(b)]), - (id(b), root_edges), + (f, vec![direct(c)]), + (e, vec![direct(b)]), + (d, vec![direct(c)]), + (c, vec![direct(b)]), + (b, root_edges), ] } // One nested fork sub graph from A let graph = itertools::chain!( - vec![(id('G'), vec![direct('A')])], + vec![('G', vec![direct('A')])], sub_graph('B'..='F', vec![direct('A')]), - vec![(id('A'), vec![])], + vec![('A', vec![])], ) .collect_vec(); insta::assert_snapshot!(format_graph(graph.iter().cloned()), @r###" @@ -698,10 +707,10 @@ mod tests { // Two nested fork sub graphs from A let graph = itertools::chain!( - vec![(id('L'), vec![direct('A')])], + vec![('L', vec![direct('A')])], sub_graph('G'..='K', vec![direct('A')]), sub_graph('B'..='F', vec![direct('A')]), - vec![(id('A'), vec![])], + vec![('A', vec![])], ) .collect_vec(); insta::assert_snapshot!(format_graph(graph.iter().cloned()), @r###" @@ -760,10 +769,10 @@ mod tests { // Two nested fork sub graphs from A, interleaved let graph = itertools::chain!( - vec![(id('L'), vec![direct('A')])], + vec![('L', vec![direct('A')])], sub_graph(['C', 'E', 'G', 'I', 'K'], vec![direct('A')]), sub_graph(['B', 'D', 'F', 'H', 'J'], vec![direct('A')]), - vec![(id('A'), vec![])], + vec![('A', vec![])], ) .sorted_by(|(id1, _), (id2, _)| id2.cmp(id1)) .collect_vec(); @@ -823,7 +832,7 @@ mod tests { // Merged fork sub graphs at K let graph = itertools::chain!( - vec![(id('K'), vec![direct('E'), direct('J')])], + vec![('K', vec![direct('E'), direct('J')])], sub_graph('F'..='J', vec![missing('Y')]), sub_graph('A'..='E', vec![missing('X')]), ) @@ -887,7 +896,7 @@ mod tests { // Merged fork sub graphs at K, interleaved let graph = itertools::chain!( - vec![(id('K'), vec![direct('I'), direct('J')])], + vec![('K', vec![direct('I'), direct('J')])], sub_graph(['B', 'D', 'F', 'H', 'J'], vec![missing('Y')]), sub_graph(['A', 'C', 'E', 'G', 'I'], vec![missing('X')]), ) @@ -954,12 +963,12 @@ mod tests { #[test] fn test_topo_grouped_merge_interleaved() { let graph = vec![ - (id('F'), vec![direct('E')]), - (id('E'), vec![direct('C'), direct('D')]), - (id('D'), vec![direct('B')]), - (id('C'), vec![direct('A')]), - (id('B'), vec![direct('A')]), - (id('A'), vec![]), + ('F', vec![direct('E')]), + ('E', vec![direct('C'), direct('D')]), + ('D', vec![direct('B')]), + ('C', vec![direct('A')]), + ('B', vec![direct('A')]), + ('A', vec![]), ]; insta::assert_snapshot!(format_graph(graph.iter().cloned()), @r###" F direct(E) @@ -992,24 +1001,24 @@ mod tests { // F, E, and D can be lazy, then C will be queued, then B. let mut iter = topo_grouped(graph.iter().cloned().peekable()); - assert_eq!(iter.next().unwrap().0, id('F')); - assert_eq!(iter.input_iter.peek().unwrap().0, id('E')); - assert_eq!(iter.next().unwrap().0, id('E')); - assert_eq!(iter.input_iter.peek().unwrap().0, id('D')); - assert_eq!(iter.next().unwrap().0, id('D')); - assert_eq!(iter.input_iter.peek().unwrap().0, id('C')); - assert_eq!(iter.next().unwrap().0, id('B')); - assert_eq!(iter.input_iter.peek().unwrap().0, id('A')); + assert_eq!(iter.next().unwrap().0, 'F'); + assert_eq!(iter.input_iter.peek().unwrap().0, 'E'); + assert_eq!(iter.next().unwrap().0, 'E'); + assert_eq!(iter.input_iter.peek().unwrap().0, 'D'); + assert_eq!(iter.next().unwrap().0, 'D'); + assert_eq!(iter.input_iter.peek().unwrap().0, 'C'); + assert_eq!(iter.next().unwrap().0, 'B'); + assert_eq!(iter.input_iter.peek().unwrap().0, 'A'); } #[test] fn test_topo_grouped_merge_but_missing() { let graph = vec![ - (id('E'), vec![direct('D')]), - (id('D'), vec![missing('Y'), direct('C')]), - (id('C'), vec![direct('B'), missing('X')]), - (id('B'), vec![direct('A')]), - (id('A'), vec![]), + ('E', vec![direct('D')]), + ('D', vec![missing('Y'), direct('C')]), + ('C', vec![direct('B'), missing('X')]), + ('B', vec![direct('A')]), + ('A', vec![]), ]; insta::assert_snapshot!(format_graph(graph.iter().cloned()), @r###" E direct(D) @@ -1050,26 +1059,26 @@ mod tests { // All nodes can be lazily emitted. let mut iter = topo_grouped(graph.iter().cloned().peekable()); - assert_eq!(iter.next().unwrap().0, id('E')); - assert_eq!(iter.input_iter.peek().unwrap().0, id('D')); - assert_eq!(iter.next().unwrap().0, id('D')); - assert_eq!(iter.input_iter.peek().unwrap().0, id('C')); - assert_eq!(iter.next().unwrap().0, id('C')); - assert_eq!(iter.input_iter.peek().unwrap().0, id('B')); - assert_eq!(iter.next().unwrap().0, id('B')); - assert_eq!(iter.input_iter.peek().unwrap().0, id('A')); + assert_eq!(iter.next().unwrap().0, 'E'); + assert_eq!(iter.input_iter.peek().unwrap().0, 'D'); + assert_eq!(iter.next().unwrap().0, 'D'); + assert_eq!(iter.input_iter.peek().unwrap().0, 'C'); + assert_eq!(iter.next().unwrap().0, 'C'); + assert_eq!(iter.input_iter.peek().unwrap().0, 'B'); + assert_eq!(iter.next().unwrap().0, 'B'); + assert_eq!(iter.input_iter.peek().unwrap().0, 'A'); } #[test] fn test_topo_grouped_merge_criss_cross() { let graph = vec![ - (id('G'), vec![direct('E')]), - (id('F'), vec![direct('D')]), - (id('E'), vec![direct('B'), direct('C')]), - (id('D'), vec![direct('B'), direct('C')]), - (id('C'), vec![direct('A')]), - (id('B'), vec![direct('A')]), - (id('A'), vec![]), + ('G', vec![direct('E')]), + ('F', vec![direct('D')]), + ('E', vec![direct('B'), direct('C')]), + ('D', vec![direct('B'), direct('C')]), + ('C', vec![direct('A')]), + ('B', vec![direct('A')]), + ('A', vec![]), ]; insta::assert_snapshot!(format_graph(graph.iter().cloned()), @r###" G direct(E) @@ -1108,14 +1117,14 @@ mod tests { #[test] fn test_topo_grouped_merge_descendants_interleaved() { let graph = vec![ - (id('H'), vec![direct('F')]), - (id('G'), vec![direct('E')]), - (id('F'), vec![direct('D')]), - (id('E'), vec![direct('C')]), - (id('D'), vec![direct('C'), direct('B')]), - (id('C'), vec![direct('A')]), - (id('B'), vec![direct('A')]), - (id('A'), vec![]), + ('H', vec![direct('F')]), + ('G', vec![direct('E')]), + ('F', vec![direct('D')]), + ('E', vec![direct('C')]), + ('D', vec![direct('C'), direct('B')]), + ('C', vec![direct('A')]), + ('B', vec![direct('A')]), + ('A', vec![]), ]; insta::assert_snapshot!(format_graph(graph.iter().cloned()), @r###" H direct(F) @@ -1158,10 +1167,10 @@ mod tests { #[test] fn test_topo_grouped_merge_multiple_roots() { let graph = [ - (id('D'), vec![direct('C')]), - (id('C'), vec![direct('B'), direct('A')]), - (id('B'), vec![missing('X')]), - (id('A'), vec![]), + ('D', vec![direct('C')]), + ('C', vec![direct('B'), direct('A')]), + ('B', vec![missing('X')]), + ('A', vec![]), ]; insta::assert_snapshot!(format_graph(graph.iter().cloned()), @r###" D direct(C) @@ -1193,18 +1202,18 @@ mod tests { fn test_topo_grouped_merge_stairs() { let graph = vec![ // Merge topic branches one by one: - (id('J'), vec![direct('I'), direct('G')]), - (id('I'), vec![direct('H'), direct('E')]), - (id('H'), vec![direct('D'), direct('F')]), + ('J', vec![direct('I'), direct('G')]), + ('I', vec![direct('H'), direct('E')]), + ('H', vec![direct('D'), direct('F')]), // Topic branches: - (id('G'), vec![direct('D')]), - (id('F'), vec![direct('C')]), - (id('E'), vec![direct('B')]), + ('G', vec![direct('D')]), + ('F', vec![direct('C')]), + ('E', vec![direct('B')]), // Base nodes: - (id('D'), vec![direct('C')]), - (id('C'), vec![direct('B')]), - (id('B'), vec![direct('A')]), - (id('A'), vec![]), + ('D', vec![direct('C')]), + ('C', vec![direct('B')]), + ('B', vec![direct('A')]), + ('A', vec![]), ]; insta::assert_snapshot!(format_graph(graph.iter().cloned()), @r###" J direct(I), direct(G) @@ -1256,16 +1265,16 @@ mod tests { #[test] fn test_topo_grouped_merge_and_fork() { let graph = vec![ - (id('J'), vec![direct('F')]), - (id('I'), vec![direct('E')]), - (id('H'), vec![direct('G')]), - (id('G'), vec![direct('D'), direct('E')]), - (id('F'), vec![direct('C')]), - (id('E'), vec![direct('B')]), - (id('D'), vec![direct('B')]), - (id('C'), vec![direct('A')]), - (id('B'), vec![direct('A')]), - (id('A'), vec![]), + ('J', vec![direct('F')]), + ('I', vec![direct('E')]), + ('H', vec![direct('G')]), + ('G', vec![direct('D'), direct('E')]), + ('F', vec![direct('C')]), + ('E', vec![direct('B')]), + ('D', vec![direct('B')]), + ('C', vec![direct('A')]), + ('B', vec![direct('A')]), + ('A', vec![]), ]; insta::assert_snapshot!(format_graph(graph.iter().cloned()), @r###" J direct(F) @@ -1316,16 +1325,16 @@ mod tests { #[test] fn test_topo_grouped_merge_and_fork_multiple_roots() { let graph = vec![ - (id('J'), vec![direct('F')]), - (id('I'), vec![direct('G')]), - (id('H'), vec![direct('E')]), - (id('G'), vec![direct('E'), direct('B')]), - (id('F'), vec![direct('D')]), - (id('E'), vec![direct('C')]), - (id('D'), vec![direct('A')]), - (id('C'), vec![direct('A')]), - (id('B'), vec![missing('X')]), - (id('A'), vec![]), + ('J', vec![direct('F')]), + ('I', vec![direct('G')]), + ('H', vec![direct('E')]), + ('G', vec![direct('E'), direct('B')]), + ('F', vec![direct('D')]), + ('E', vec![direct('C')]), + ('D', vec![direct('A')]), + ('C', vec![direct('A')]), + ('B', vec![missing('X')]), + ('A', vec![]), ]; insta::assert_snapshot!(format_graph(graph.iter().cloned()), @r###" J direct(F) @@ -1380,11 +1389,11 @@ mod tests { #[test] fn test_topo_grouped_parallel_interleaved() { let graph = vec![ - (id('E'), vec![direct('C')]), - (id('D'), vec![direct('B')]), - (id('C'), vec![direct('A')]), - (id('B'), vec![missing('X')]), - (id('A'), vec![]), + ('E', vec![direct('C')]), + ('D', vec![direct('B')]), + ('C', vec![direct('A')]), + ('B', vec![missing('X')]), + ('A', vec![]), ]; insta::assert_snapshot!(format_graph(graph.iter().cloned()), @r###" E direct(C) @@ -1418,15 +1427,15 @@ mod tests { #[test] fn test_topo_grouped_multiple_child_dependencies() { let graph = vec![ - (id('I'), vec![direct('H'), direct('G')]), - (id('H'), vec![direct('D')]), - (id('G'), vec![direct('B')]), - (id('F'), vec![direct('E'), direct('C')]), - (id('E'), vec![direct('D')]), - (id('D'), vec![direct('B')]), - (id('C'), vec![direct('B')]), - (id('B'), vec![direct('A')]), - (id('A'), vec![]), + ('I', vec![direct('H'), direct('G')]), + ('H', vec![direct('D')]), + ('G', vec![direct('B')]), + ('F', vec![direct('E'), direct('C')]), + ('E', vec![direct('D')]), + ('D', vec![direct('B')]), + ('C', vec![direct('B')]), + ('B', vec![direct('A')]), + ('A', vec![]), ]; insta::assert_snapshot!(format_graph(graph.iter().cloned()), @r###" I direct(H), direct(G) @@ -1475,9 +1484,9 @@ mod tests { #[test] fn test_topo_grouped_requeue_unpopulated() { let graph = [ - (id('C'), vec![direct('A'), direct('B')]), - (id('B'), vec![direct('A')]), - (id('A'), vec![]), + ('C', vec![direct('A'), direct('B')]), + ('B', vec![direct('A')]), + ('A', vec![]), ]; insta::assert_snapshot!(format_graph(graph.iter().cloned()), @r###" C direct(A), direct(B) @@ -1500,11 +1509,11 @@ mod tests { // B is the second parent, B-A is processed next and A is queued again. So // one of them in the queue has to be ignored. let mut iter = topo_grouped(graph.iter().cloned()); - assert_eq!(iter.next().unwrap().0, id('C')); - assert_eq!(iter.emittable_ids, vec![id('A'), id('B')]); - assert_eq!(iter.next().unwrap().0, id('B')); - assert_eq!(iter.emittable_ids, vec![id('A'), id('A')]); - assert_eq!(iter.next().unwrap().0, id('A')); + assert_eq!(iter.next().unwrap().0, 'C'); + assert_eq!(iter.emittable_ids, vec!['A', 'B']); + assert_eq!(iter.next().unwrap().0, 'B'); + assert_eq!(iter.emittable_ids, vec!['A', 'A']); + assert_eq!(iter.next().unwrap().0, 'A'); assert!(iter.next().is_none()); assert!(iter.emittable_ids.is_empty()); } @@ -1513,7 +1522,7 @@ mod tests { fn test_topo_grouped_duplicated_edges() { // The graph shouldn't have duplicated parent->child edges, but topo-grouped // iterator can handle it anyway. - let graph = [(id('B'), vec![direct('A'), direct('A')]), (id('A'), vec![])]; + let graph = [('B', vec![direct('A'), direct('A')]), ('A', vec![])]; insta::assert_snapshot!(format_graph(graph.iter().cloned()), @r###" B direct(A), direct(A) │ @@ -1528,9 +1537,9 @@ mod tests { "###); let mut iter = topo_grouped(graph.iter().cloned()); - assert_eq!(iter.next().unwrap().0, id('B')); - assert_eq!(iter.emittable_ids, vec![id('A'), id('A')]); - assert_eq!(iter.next().unwrap().0, id('A')); + assert_eq!(iter.next().unwrap().0, 'B'); + assert_eq!(iter.emittable_ids, vec!['A', 'A']); + assert_eq!(iter.next().unwrap().0, 'A'); assert!(iter.next().is_none()); assert!(iter.emittable_ids.is_empty()); } diff --git a/lib/tests/test_default_revset_graph_iterator.rs b/lib/tests/test_default_revset_graph_iterator.rs index 951c422caf..27ce0f1be6 100644 --- a/lib/tests/test_default_revset_graph_iterator.rs +++ b/lib/tests/test_default_revset_graph_iterator.rs @@ -13,6 +13,7 @@ // limitations under the License. use itertools::Itertools; +use jj_lib::backend::CommitId; use jj_lib::commit::Commit; use jj_lib::default_index::revset_engine::{evaluate, RevsetImpl}; use jj_lib::default_index::DefaultReadonlyIndex; @@ -36,15 +37,15 @@ fn revset_for_commits( evaluate(&expression, repo.store(), index.clone()).unwrap() } -fn direct(commit: &Commit) -> RevsetGraphEdge { +fn direct(commit: &Commit) -> RevsetGraphEdge { RevsetGraphEdge::direct(commit.id().clone()) } -fn indirect(commit: &Commit) -> RevsetGraphEdge { +fn indirect(commit: &Commit) -> RevsetGraphEdge { RevsetGraphEdge::indirect(commit.id().clone()) } -fn missing(commit: &Commit) -> RevsetGraphEdge { +fn missing(commit: &Commit) -> RevsetGraphEdge { RevsetGraphEdge::missing(commit.id().clone()) }