rust/hg-core/src/dagops.rs
author Jun Wu <quark@fb.com>
Mon, 25 Nov 2019 11:53:50 -0800
changeset 43779 2e30d7df4809
parent 42841 ce6797ef6eab
child 44973 26114bd6ec60
permissions -rw-r--r--
revlog: fix revset in reachableroots docstring `reachableroots` will only return a subset of `roots` when `includepath` is False. For example, given the following linear DAG: 2 | 1 | 0 Using roots=0+2, heads=1, the definition in the docstring does not match what `reachableroots` actually does: ipdb> repo.changelog.reachableroots(0, roots=[0,2],heads=[1]) [0] ipdb> repo.revs('heads(::(0+2) & (0+2)::1)') <baseset+ [1]> The fix is to do `heads & ::roots` (or `heads & heads::roots`) first, then select their ancestors: ipdb> repo.revs('heads(::((0+2) & (0+2)::1))') <baseset+ [0]> The docstring was introduced by fd92bfbbe02d9 (2015-06-19 "revset: rename revsbetween to reachableroots and add an argument"), which introduced the `includepath=False` behavior for graphlog grandparents use-case. I believe the docstring instead of the code should be changed because changing the code to match the docstring can result in suboptimal graphlog like: o :\ : o : : :/ o As opposite to the current "linearized" graphlog: o | o : o Differential Revision: https://phab.mercurial-scm.org/D7518
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
41242
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
     1
// dagops.rs
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
     2
//
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
     3
// Copyright 2019 Georges Racinet <georges.racinet@octobus.net>
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
     4
//
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
     5
// This software may be used and distributed according to the terms of the
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
     6
// GNU General Public License version 2 or any later version.
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
     7
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
     8
//! Miscellaneous DAG operations
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
     9
//!
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    10
//! # Terminology
42841
ce6797ef6eab rust: apply more formatting fixes
Yuya Nishihara <yuya@tcha.org>
parents: 42177
diff changeset
    11
//! - By *relative heads* of a collection of revision numbers (`Revision`), we
ce6797ef6eab rust: apply more formatting fixes
Yuya Nishihara <yuya@tcha.org>
parents: 42177
diff changeset
    12
//!   mean those revisions that have no children among the collection.
ce6797ef6eab rust: apply more formatting fixes
Yuya Nishihara <yuya@tcha.org>
parents: 42177
diff changeset
    13
//! - Similarly *relative roots* of a collection of `Revision`, we mean those
ce6797ef6eab rust: apply more formatting fixes
Yuya Nishihara <yuya@tcha.org>
parents: 42177
diff changeset
    14
//!   whose parents, if any, don't belong to the collection.
41242
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    15
use super::{Graph, GraphError, Revision, NULL_REVISION};
42176
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
    16
use crate::ancestors::AncestorsIterator;
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
    17
use std::collections::{BTreeSet, HashSet};
41242
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    18
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    19
fn remove_parents(
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    20
    graph: &impl Graph,
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    21
    rev: Revision,
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    22
    set: &mut HashSet<Revision>,
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    23
) -> Result<(), GraphError> {
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    24
    for parent in graph.parents(rev)?.iter() {
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    25
        if *parent != NULL_REVISION {
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    26
            set.remove(parent);
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    27
        }
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    28
    }
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    29
    Ok(())
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    30
}
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    31
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    32
/// Relative heads out of some revisions, passed as an iterator.
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    33
///
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    34
/// These heads are defined as those revisions that have no children
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    35
/// among those emitted by the iterator.
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    36
///
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    37
/// # Performance notes
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    38
/// Internally, this clones the iterator, and builds a `HashSet` out of it.
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    39
///
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    40
/// This function takes an `Iterator` instead of `impl IntoIterator` to
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    41
/// guarantee that cloning the iterator doesn't result in cloning the full
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    42
/// construct it comes from.
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    43
pub fn heads<'a>(
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    44
    graph: &impl Graph,
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    45
    iter_revs: impl Clone + Iterator<Item = &'a Revision>,
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    46
) -> Result<HashSet<Revision>, GraphError> {
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    47
    let mut heads: HashSet<Revision> = iter_revs.clone().cloned().collect();
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    48
    heads.remove(&NULL_REVISION);
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    49
    for rev in iter_revs {
41717
9060af281be7 rust: itering less on MissingAncestors.bases for max()
Georges Racinet <georges.racinet@octobus.net>
parents: 41242
diff changeset
    50
        if *rev != NULL_REVISION {
9060af281be7 rust: itering less on MissingAncestors.bases for max()
Georges Racinet <georges.racinet@octobus.net>
parents: 41242
diff changeset
    51
            remove_parents(graph, *rev, &mut heads)?;
9060af281be7 rust: itering less on MissingAncestors.bases for max()
Georges Racinet <georges.racinet@octobus.net>
parents: 41242
diff changeset
    52
        }
41242
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    53
    }
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    54
    Ok(heads)
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    55
}
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    56
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    57
/// Retain in `revs` only its relative heads.
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    58
///
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    59
/// This is an in-place operation, so that control of the incoming
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    60
/// set is left to the caller.
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    61
/// - a direct Python binding would probably need to build its own `HashSet`
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    62
///   from an incoming iterable, even if its sole purpose is to extract the
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    63
///   heads.
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    64
/// - a Rust caller can decide whether cloning beforehand is appropriate
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    65
///
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    66
/// # Performance notes
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    67
/// Internally, this function will store a full copy of `revs` in a `Vec`.
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    68
pub fn retain_heads(
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    69
    graph: &impl Graph,
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    70
    revs: &mut HashSet<Revision>,
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    71
) -> Result<(), GraphError> {
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    72
    revs.remove(&NULL_REVISION);
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    73
    // we need to construct an iterable copy of revs to avoid itering while
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    74
    // mutating
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    75
    let as_vec: Vec<Revision> = revs.iter().cloned().collect();
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    76
    for rev in as_vec {
41717
9060af281be7 rust: itering less on MissingAncestors.bases for max()
Georges Racinet <georges.racinet@octobus.net>
parents: 41242
diff changeset
    77
        if rev != NULL_REVISION {
9060af281be7 rust: itering less on MissingAncestors.bases for max()
Georges Racinet <georges.racinet@octobus.net>
parents: 41242
diff changeset
    78
            remove_parents(graph, rev, revs)?;
9060af281be7 rust: itering less on MissingAncestors.bases for max()
Georges Racinet <georges.racinet@octobus.net>
parents: 41242
diff changeset
    79
        }
41242
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    80
    }
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    81
    Ok(())
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    82
}
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
    83
42177
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
    84
/// Roots of `revs`, passed as a `HashSet`
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
    85
///
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
    86
/// They are returned in arbitrary order
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
    87
pub fn roots<G: Graph>(
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
    88
    graph: &G,
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
    89
    revs: &HashSet<Revision>,
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
    90
) -> Result<Vec<Revision>, GraphError> {
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
    91
    let mut roots: Vec<Revision> = Vec::new();
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
    92
    for rev in revs {
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
    93
        if graph
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
    94
            .parents(*rev)?
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
    95
            .iter()
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
    96
            .filter(|p| **p != NULL_REVISION)
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
    97
            .all(|p| !revs.contains(p))
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
    98
        {
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
    99
            roots.push(*rev);
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   100
        }
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   101
    }
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   102
    Ok(roots)
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   103
}
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   104
42176
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   105
/// Compute the topological range between two collections of revisions
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   106
///
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   107
/// This is equivalent to the revset `<roots>::<heads>`.
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   108
///
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   109
/// Currently, the given `Graph` has to implement `Clone`, which means
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   110
/// actually cloning just a reference-counted Python pointer if
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   111
/// it's passed over through `rust-cpython`. This is due to the internal
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   112
/// use of `AncestorsIterator`
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   113
///
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   114
/// # Algorithmic details
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   115
///
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   116
/// This is a two-pass swipe inspired from what `reachableroots2` from
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   117
/// `mercurial.cext.parsers` does to obtain the same results.
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   118
///
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   119
/// - first, we climb up the DAG from `heads` in topological order, keeping
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   120
///   them in the vector `heads_ancestors` vector, and adding any element of
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   121
///   `roots` we find among them to the resulting range.
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   122
/// - Then, we iterate on that recorded vector so that a revision is always
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   123
///   emitted after its parents and add all revisions whose parents are already
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   124
///   in the range to the results.
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   125
///
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   126
/// # Performance notes
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   127
///
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   128
/// The main difference with the C implementation is that
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   129
/// the latter uses a flat array with bit flags, instead of complex structures
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   130
/// like `HashSet`, making it faster in most scenarios. In theory, it's
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   131
/// possible that the present implementation could be more memory efficient
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   132
/// for very large repositories with many branches.
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   133
pub fn range(
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   134
    graph: &(impl Graph + Clone),
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   135
    roots: impl IntoIterator<Item = Revision>,
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   136
    heads: impl IntoIterator<Item = Revision>,
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   137
) -> Result<BTreeSet<Revision>, GraphError> {
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   138
    let mut range = BTreeSet::new();
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   139
    let roots: HashSet<Revision> = roots.into_iter().collect();
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   140
    let min_root: Revision = match roots.iter().cloned().min() {
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   141
        None => {
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   142
            return Ok(range);
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   143
        }
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   144
        Some(r) => r,
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   145
    };
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   146
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   147
    // Internally, AncestorsIterator currently maintains a `HashSet`
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   148
    // of all seen revision, which is also what we record, albeit in an ordered
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   149
    // way. There's room for improvement on this duplication.
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   150
    let ait = AncestorsIterator::new(graph.clone(), heads, min_root, true)?;
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   151
    let mut heads_ancestors: Vec<Revision> = Vec::new();
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   152
    for revres in ait {
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   153
        let rev = revres?;
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   154
        if roots.contains(&rev) {
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   155
            range.insert(rev);
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   156
        }
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   157
        heads_ancestors.push(rev);
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   158
    }
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   159
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   160
    for rev in heads_ancestors.into_iter().rev() {
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   161
        for parent in graph.parents(rev)?.iter() {
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   162
            if *parent != NULL_REVISION && range.contains(parent) {
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   163
                range.insert(rev);
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   164
            }
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   165
        }
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   166
    }
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   167
    Ok(range)
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   168
}
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   169
41242
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   170
#[cfg(test)]
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   171
mod tests {
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   172
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   173
    use super::*;
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   174
    use crate::testing::SampleGraph;
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   175
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   176
    /// Apply `retain_heads()` to the given slice and return as a sorted `Vec`
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   177
    fn retain_heads_sorted(
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   178
        graph: &impl Graph,
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   179
        revs: &[Revision],
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   180
    ) -> Result<Vec<Revision>, GraphError> {
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   181
        let mut revs: HashSet<Revision> = revs.iter().cloned().collect();
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   182
        retain_heads(graph, &mut revs)?;
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   183
        let mut as_vec: Vec<Revision> = revs.iter().cloned().collect();
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   184
        as_vec.sort();
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   185
        Ok(as_vec)
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   186
    }
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   187
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   188
    #[test]
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   189
    fn test_retain_heads() -> Result<(), GraphError> {
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   190
        assert_eq!(retain_heads_sorted(&SampleGraph, &[4, 5, 6])?, vec![5, 6]);
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   191
        assert_eq!(
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   192
            retain_heads_sorted(&SampleGraph, &[4, 1, 6, 12, 0])?,
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   193
            vec![1, 6, 12]
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   194
        );
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   195
        assert_eq!(
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   196
            retain_heads_sorted(&SampleGraph, &[1, 2, 3, 4, 5, 6, 7, 8, 9])?,
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   197
            vec![3, 5, 8, 9]
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   198
        );
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   199
        Ok(())
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   200
    }
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   201
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   202
    /// Apply `heads()` to the given slice and return as a sorted `Vec`
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   203
    fn heads_sorted(
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   204
        graph: &impl Graph,
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   205
        revs: &[Revision],
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   206
    ) -> Result<Vec<Revision>, GraphError> {
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   207
        let heads = heads(graph, revs.iter())?;
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   208
        let mut as_vec: Vec<Revision> = heads.iter().cloned().collect();
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   209
        as_vec.sort();
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   210
        Ok(as_vec)
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   211
    }
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   212
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   213
    #[test]
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   214
    fn test_heads() -> Result<(), GraphError> {
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   215
        assert_eq!(heads_sorted(&SampleGraph, &[4, 5, 6])?, vec![5, 6]);
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   216
        assert_eq!(
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   217
            heads_sorted(&SampleGraph, &[4, 1, 6, 12, 0])?,
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   218
            vec![1, 6, 12]
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   219
        );
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   220
        assert_eq!(
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   221
            heads_sorted(&SampleGraph, &[1, 2, 3, 4, 5, 6, 7, 8, 9])?,
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   222
            vec![3, 5, 8, 9]
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   223
        );
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   224
        Ok(())
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   225
    }
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   226
42177
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   227
    /// Apply `roots()` and sort the result for easier comparison
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   228
    fn roots_sorted(
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   229
        graph: &impl Graph,
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   230
        revs: &[Revision],
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   231
    ) -> Result<Vec<Revision>, GraphError> {
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   232
        let mut as_vec = roots(graph, &revs.iter().cloned().collect())?;
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   233
        as_vec.sort();
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   234
        Ok(as_vec)
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   235
    }
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   236
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   237
    #[test]
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   238
    fn test_roots() -> Result<(), GraphError> {
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   239
        assert_eq!(roots_sorted(&SampleGraph, &[4, 5, 6])?, vec![4]);
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   240
        assert_eq!(
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   241
            roots_sorted(&SampleGraph, &[4, 1, 6, 12, 0])?,
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   242
            vec![0, 4, 12]
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   243
        );
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   244
        assert_eq!(
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   245
            roots_sorted(&SampleGraph, &[1, 2, 3, 4, 5, 6, 7, 8, 9])?,
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   246
            vec![1, 8]
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   247
        );
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   248
        Ok(())
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   249
    }
be0733552984 rust-dagops: roots
Georges Racinet <georges.racinet@octobus.net>
parents: 42176
diff changeset
   250
42176
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   251
    /// Apply `range()` and convert the result into a Vec for easier comparison
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   252
    fn range_vec(
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   253
        graph: impl Graph + Clone,
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   254
        roots: &[Revision],
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   255
        heads: &[Revision],
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   256
    ) -> Result<Vec<Revision>, GraphError> {
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   257
        range(&graph, roots.iter().cloned(), heads.iter().cloned())
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   258
            .map(|bs| bs.into_iter().collect())
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   259
    }
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   260
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   261
    #[test]
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   262
    fn test_range() -> Result<(), GraphError> {
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   263
        assert_eq!(range_vec(SampleGraph, &[0], &[4])?, vec![0, 1, 2, 4]);
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   264
        assert_eq!(range_vec(SampleGraph, &[0], &[8])?, vec![]);
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   265
        assert_eq!(
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   266
            range_vec(SampleGraph, &[5, 6], &[10, 11, 13])?,
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   267
            vec![5, 10]
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   268
        );
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   269
        assert_eq!(
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   270
            range_vec(SampleGraph, &[5, 6], &[10, 12])?,
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   271
            vec![5, 6, 9, 10, 12]
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   272
        );
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   273
        Ok(())
3bdb21bbf791 rust-dagops: range of revisions
Georges Racinet <georges.racinet@octobus.net>
parents: 41717
diff changeset
   274
    }
41242
47881d2a9d99 rust: dagop.headrevs() Rust counterparts
Georges Racinet on ishtar.racinet.fr <georges@racinet.fr>
parents:
diff changeset
   275
}