##// END OF EJS Templates
rust: translated random test of missingancestors...
Georges Racinet -
r41841:ee7b7bd4 default
parent child Browse files
Show More
@@ -0,0 +1,340 b''
1 extern crate hg;
2 extern crate rand;
3 extern crate rand_pcg;
4
5 use hg::testing::VecGraph;
6 use hg::Revision;
7 use hg::*;
8 use rand::distributions::{Distribution, LogNormal, Uniform};
9 use rand::{thread_rng, Rng, RngCore, SeedableRng};
10 use std::cmp::min;
11 use std::collections::HashSet;
12 use std::env;
13 use std::fmt::Debug;
14
15 fn build_random_graph(
16 nodes_opt: Option<usize>,
17 rootprob_opt: Option<f64>,
18 mergeprob_opt: Option<f64>,
19 prevprob_opt: Option<f64>,
20 ) -> VecGraph {
21 let nodes = nodes_opt.unwrap_or(100);
22 let rootprob = rootprob_opt.unwrap_or(0.05);
23 let mergeprob = mergeprob_opt.unwrap_or(0.2);
24 let prevprob = prevprob_opt.unwrap_or(0.7);
25
26 let mut rng = thread_rng();
27 let mut vg: VecGraph = Vec::with_capacity(nodes);
28 for i in 0..nodes {
29 if i == 0 || rng.gen_bool(rootprob) {
30 vg.push([NULL_REVISION, NULL_REVISION])
31 } else if i == 1 {
32 vg.push([0, NULL_REVISION])
33 } else if rng.gen_bool(mergeprob) {
34 let p1 = {
35 if i == 2 || rng.gen_bool(prevprob) {
36 (i - 1) as Revision
37 } else {
38 rng.gen_range(0, i - 1) as Revision
39 }
40 };
41 // p2 is a random revision lower than i and different from p1
42 let mut p2 = rng.gen_range(0, i - 1) as Revision;
43 if p2 >= p1 {
44 p2 = p2 + 1;
45 }
46 vg.push([p1, p2]);
47 } else if rng.gen_bool(prevprob) {
48 vg.push([(i - 1) as Revision, NULL_REVISION])
49 } else {
50 vg.push([rng.gen_range(0, i - 1) as Revision, NULL_REVISION])
51 }
52 }
53 vg
54 }
55
56 /// Compute the ancestors set of all revisions of a VecGraph
57 fn ancestors_sets(vg: &VecGraph) -> Vec<HashSet<Revision>> {
58 let mut ancs: Vec<HashSet<Revision>> = Vec::new();
59 for i in 0..vg.len() {
60 let mut ancs_i = HashSet::new();
61 ancs_i.insert(i as Revision);
62 for p in vg[i].iter().cloned() {
63 if p != NULL_REVISION {
64 ancs_i.extend(&ancs[p as usize]);
65 }
66 }
67 ancs.push(ancs_i);
68 }
69 ancs
70 }
71
72 #[derive(Clone, Debug)]
73 enum MissingAncestorsAction {
74 InitialBases(HashSet<Revision>),
75 AddBases(HashSet<Revision>),
76 RemoveAncestorsFrom(HashSet<Revision>),
77 MissingAncestors(HashSet<Revision>),
78 }
79
80 /// An instrumented naive yet obviously correct implementation
81 ///
82 /// It also records all its actions for easy reproduction for replay
83 /// of problematic cases
84 struct NaiveMissingAncestors<'a> {
85 ancestors_sets: &'a Vec<HashSet<Revision>>,
86 graph: &'a VecGraph, // used for error reporting only
87 bases: HashSet<Revision>,
88 history: Vec<MissingAncestorsAction>,
89 // for error reporting, assuming we are in a random test
90 random_seed: String,
91 }
92
93 impl<'a> NaiveMissingAncestors<'a> {
94 fn new(
95 graph: &'a VecGraph,
96 ancestors_sets: &'a Vec<HashSet<Revision>>,
97 bases: &HashSet<Revision>,
98 random_seed: &str,
99 ) -> Self {
100 Self {
101 ancestors_sets: ancestors_sets,
102 bases: bases.clone(),
103 graph: graph,
104 history: vec![MissingAncestorsAction::InitialBases(bases.clone())],
105 random_seed: random_seed.into(),
106 }
107 }
108
109 fn add_bases(&mut self, new_bases: HashSet<Revision>) {
110 self.bases.extend(&new_bases);
111 self.history
112 .push(MissingAncestorsAction::AddBases(new_bases))
113 }
114
115 fn remove_ancestors_from(&mut self, revs: &mut HashSet<Revision>) {
116 revs.remove(&NULL_REVISION);
117 self.history
118 .push(MissingAncestorsAction::RemoveAncestorsFrom(revs.clone()));
119 for base in self.bases.iter().cloned() {
120 if base != NULL_REVISION {
121 for rev in &self.ancestors_sets[base as usize] {
122 revs.remove(&rev);
123 }
124 }
125 }
126 }
127
128 fn missing_ancestors(
129 &mut self,
130 revs: impl IntoIterator<Item = Revision>,
131 ) -> Vec<Revision> {
132 let revs_as_set: HashSet<Revision> = revs.into_iter().collect();
133
134 let mut missing: HashSet<Revision> = HashSet::new();
135 for rev in revs_as_set.iter().cloned() {
136 if rev != NULL_REVISION {
137 missing.extend(&self.ancestors_sets[rev as usize])
138 }
139 }
140 self.history
141 .push(MissingAncestorsAction::MissingAncestors(revs_as_set));
142
143 for base in self.bases.iter().cloned() {
144 if base != NULL_REVISION {
145 for rev in &self.ancestors_sets[base as usize] {
146 missing.remove(&rev);
147 }
148 }
149 }
150 let mut res: Vec<Revision> = missing.iter().cloned().collect();
151 res.sort();
152 res
153 }
154
155 fn assert_eq<T>(&self, left: T, right: T)
156 where
157 T: PartialEq + Debug,
158 {
159 if left == right {
160 return;
161 }
162 panic!(format!(
163 "Equality assertion failed (left != right)
164 left={:?}
165 right={:?}
166 graph={:?}
167 current bases={:?}
168 history={:?}
169 random seed={}
170 ",
171 left,
172 right,
173 self.graph,
174 self.bases,
175 self.history,
176 self.random_seed,
177 ));
178 }
179 }
180
181 /// Choose a set of random revisions
182 ///
183 /// The size of the set is taken from a LogNormal distribution
184 /// with default mu=1.1 and default sigma=0.8. Quoting the Python
185 /// test this is taken from:
186 /// the default mu and sigma give us a nice distribution of mostly
187 /// single-digit counts (including 0) with some higher ones
188 /// The sample may include NULL_REVISION
189 fn sample_revs<R: RngCore>(
190 rng: &mut R,
191 maxrev: Revision,
192 mu_opt: Option<f64>,
193 sigma_opt: Option<f64>,
194 ) -> HashSet<Revision> {
195 let mu = mu_opt.unwrap_or(1.1);
196 let sigma = sigma_opt.unwrap_or(0.8);
197
198 let log_normal = LogNormal::new(mu, sigma);
199 let nb = min(maxrev as usize, log_normal.sample(rng).floor() as usize);
200
201 let dist = Uniform::from(NULL_REVISION..maxrev);
202 return rng.sample_iter(&dist).take(nb).collect();
203 }
204
205 /// Produces the hexadecimal representation of a slice of bytes
206 fn hex_bytes(bytes: &[u8]) -> String {
207 let mut s = String::with_capacity(bytes.len() * 2);
208 for b in bytes {
209 s.push_str(&format!("{:x}", b));
210 }
211 s
212 }
213
214 /// Fill a random seed from its hexadecimal representation.
215 ///
216 /// This signature is meant to be consistent with `RngCore::fill_bytes`
217 fn seed_parse_in(hex: &str, seed: &mut [u8]) {
218 if hex.len() != 32 {
219 panic!("Seed {} is too short for 128 bits hex", hex);
220 }
221 for i in 0..8 {
222 seed[i] = u8::from_str_radix(&hex[2 * i..2 * (i + 1)], 16)
223 .unwrap_or_else(|_e| panic!("Seed {} is not 128 bits hex", hex));
224 }
225 }
226
227 /// Parse the parameters for `test_missing_ancestors()`
228 ///
229 /// Returns (graphs, instances, calls per instance)
230 fn parse_test_missing_ancestors_params(var: &str) -> (usize, usize, usize) {
231 let err_msg = "TEST_MISSING_ANCESTORS format: GRAPHS,INSTANCES,CALLS";
232 let params: Vec<usize> = var
233 .split(',')
234 .map(|n| n.trim().parse().expect(err_msg))
235 .collect();
236 if params.len() != 3 {
237 panic!(err_msg);
238 }
239 (params[0], params[1], params[2])
240 }
241
242 #[test]
243 /// This test creates lots of random VecGraphs,
244 /// and compare a bunch of MissingAncestors for them with
245 /// NaiveMissingAncestors that rely on precomputed transitive closures of
246 /// these VecGraphs (ancestors_sets).
247 ///
248 /// For each generater graph, several instances of `MissingAncestors` are
249 /// created, whose methods are called and checked a given number of times.
250 ///
251 /// This test can be parametrized by two environment variables:
252 ///
253 /// - TEST_RANDOM_SEED: must be 128 bits in hexadecimal
254 /// - TEST_MISSING_ANCESTORS: "GRAPHS,INSTANCES,CALLS". The default is
255 /// "100,10,10"
256 ///
257 /// This is slow: it runs on my workstation in about 5 seconds with the
258 /// default parameters with a plain `cargo --test`.
259 ///
260 /// If you want to run it faster, especially if you're changing the
261 /// parameters, use `cargo test --release`.
262 /// For me, that gets it down to 0.15 seconds with the default parameters
263 fn test_missing_ancestors_compare_naive() {
264 let (graphcount, testcount, inccount) =
265 match env::var("TEST_MISSING_ANCESTORS") {
266 Err(env::VarError::NotPresent) => (100, 10, 10),
267 Ok(val) => parse_test_missing_ancestors_params(&val),
268 Err(env::VarError::NotUnicode(_)) => {
269 panic!("TEST_MISSING_ANCESTORS is invalid");
270 }
271 };
272 let mut seed: [u8; 16] = [0; 16];
273 match env::var("TEST_RANDOM_SEED") {
274 Ok(val) => {
275 seed_parse_in(&val, &mut seed);
276 }
277 Err(env::VarError::NotPresent) => {
278 thread_rng().fill_bytes(&mut seed);
279 }
280 Err(env::VarError::NotUnicode(_)) => {
281 panic!("TEST_RANDOM_SEED must be 128 bits in hex");
282 }
283 }
284 let hex_seed = hex_bytes(&seed);
285 eprintln!("Random seed: {}", hex_seed);
286
287 let mut rng = rand_pcg::Pcg32::from_seed(seed);
288
289 eprint!("Checking MissingAncestors against brute force implementation ");
290 eprint!("for {} random graphs, ", graphcount);
291 eprintln!(
292 "with {} instances for each and {} calls per instance",
293 testcount, inccount,
294 );
295 for g in 0..graphcount {
296 if g != 0 && g % 100 == 0 {
297 eprintln!("Tested with {} graphs", g);
298 }
299 let graph = build_random_graph(None, None, None, None);
300 let graph_len = graph.len() as Revision;
301 let ancestors_sets = ancestors_sets(&graph);
302 for _testno in 0..testcount {
303 let bases: HashSet<Revision> =
304 sample_revs(&mut rng, graph_len, None, None);
305 let mut inc = MissingAncestors::<VecGraph>::new(
306 graph.clone(),
307 bases.clone(),
308 );
309 let mut naive = NaiveMissingAncestors::new(
310 &graph,
311 &ancestors_sets,
312 &bases,
313 &hex_seed,
314 );
315 for _m in 0..inccount {
316 if rng.gen_bool(0.2) {
317 let new_bases =
318 sample_revs(&mut rng, graph_len, None, None);
319 inc.add_bases(new_bases.iter().cloned());
320 naive.add_bases(new_bases);
321 }
322 if rng.gen_bool(0.4) {
323 // larger set so that there are more revs to remove from
324 let mut hrevs =
325 sample_revs(&mut rng, graph_len, Some(1.5), None);
326 let mut rrevs = hrevs.clone();
327 inc.remove_ancestors_from(&mut hrevs).unwrap();
328 naive.remove_ancestors_from(&mut rrevs);
329 naive.assert_eq(hrevs, rrevs);
330 } else {
331 let revs = sample_revs(&mut rng, graph_len, None, None);
332 let hm =
333 inc.missing_ancestors(revs.iter().cloned()).unwrap();
334 let rm = naive.missing_ancestors(revs.iter().cloned());
335 naive.assert_eq(hm, rm);
336 }
337 }
338 }
339 }
340 }
@@ -7,11 +7,29 b' dependencies = ['
7 ]
7 ]
8
8
9 [[package]]
9 [[package]]
10 name = "autocfg"
11 version = "0.1.2"
12 source = "registry+https://github.com/rust-lang/crates.io-index"
13
14 [[package]]
15 name = "bitflags"
16 version = "1.0.4"
17 source = "registry+https://github.com/rust-lang/crates.io-index"
18
19 [[package]]
10 name = "cfg-if"
20 name = "cfg-if"
11 version = "0.1.6"
21 version = "0.1.6"
12 source = "registry+https://github.com/rust-lang/crates.io-index"
22 source = "registry+https://github.com/rust-lang/crates.io-index"
13
23
14 [[package]]
24 [[package]]
25 name = "cloudabi"
26 version = "0.0.3"
27 source = "registry+https://github.com/rust-lang/crates.io-index"
28 dependencies = [
29 "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
30 ]
31
32 [[package]]
15 name = "cpython"
33 name = "cpython"
16 version = "0.2.1"
34 version = "0.2.1"
17 source = "registry+https://github.com/rust-lang/crates.io-index"
35 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -23,8 +41,17 b' dependencies = ['
23 ]
41 ]
24
42
25 [[package]]
43 [[package]]
44 name = "fuchsia-cprng"
45 version = "0.1.0"
46 source = "registry+https://github.com/rust-lang/crates.io-index"
47
48 [[package]]
26 name = "hg-core"
49 name = "hg-core"
27 version = "0.1.0"
50 version = "0.1.0"
51 dependencies = [
52 "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
53 "rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
54 ]
28
55
29 [[package]]
56 [[package]]
30 name = "hg-cpython"
57 name = "hg-cpython"
@@ -89,6 +116,110 b' dependencies = ['
89 ]
116 ]
90
117
91 [[package]]
118 [[package]]
119 name = "rand"
120 version = "0.6.5"
121 source = "registry+https://github.com/rust-lang/crates.io-index"
122 dependencies = [
123 "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
124 "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
125 "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
126 "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
127 "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
128 "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
129 "rand_jitter 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
130 "rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
131 "rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
132 "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
133 "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
134 ]
135
136 [[package]]
137 name = "rand_chacha"
138 version = "0.1.1"
139 source = "registry+https://github.com/rust-lang/crates.io-index"
140 dependencies = [
141 "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
142 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
143 ]
144
145 [[package]]
146 name = "rand_core"
147 version = "0.3.1"
148 source = "registry+https://github.com/rust-lang/crates.io-index"
149 dependencies = [
150 "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
151 ]
152
153 [[package]]
154 name = "rand_core"
155 version = "0.4.0"
156 source = "registry+https://github.com/rust-lang/crates.io-index"
157
158 [[package]]
159 name = "rand_hc"
160 version = "0.1.0"
161 source = "registry+https://github.com/rust-lang/crates.io-index"
162 dependencies = [
163 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
164 ]
165
166 [[package]]
167 name = "rand_isaac"
168 version = "0.1.1"
169 source = "registry+https://github.com/rust-lang/crates.io-index"
170 dependencies = [
171 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
172 ]
173
174 [[package]]
175 name = "rand_jitter"
176 version = "0.1.2"
177 source = "registry+https://github.com/rust-lang/crates.io-index"
178 dependencies = [
179 "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
180 "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
181 "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
182 ]
183
184 [[package]]
185 name = "rand_os"
186 version = "0.1.2"
187 source = "registry+https://github.com/rust-lang/crates.io-index"
188 dependencies = [
189 "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
190 "fuchsia-cprng 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
191 "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
192 "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
193 "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
194 "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
195 ]
196
197 [[package]]
198 name = "rand_pcg"
199 version = "0.1.1"
200 source = "registry+https://github.com/rust-lang/crates.io-index"
201 dependencies = [
202 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
203 "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
204 ]
205
206 [[package]]
207 name = "rand_xorshift"
208 version = "0.1.1"
209 source = "registry+https://github.com/rust-lang/crates.io-index"
210 dependencies = [
211 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
212 ]
213
214 [[package]]
215 name = "rdrand"
216 version = "0.4.0"
217 source = "registry+https://github.com/rust-lang/crates.io-index"
218 dependencies = [
219 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
220 ]
221
222 [[package]]
92 name = "regex"
223 name = "regex"
93 version = "1.1.0"
224 version = "1.1.0"
94 source = "registry+https://github.com/rust-lang/crates.io-index"
225 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -109,6 +240,27 b' dependencies = ['
109 ]
240 ]
110
241
111 [[package]]
242 [[package]]
243 name = "rustc_version"
244 version = "0.2.3"
245 source = "registry+https://github.com/rust-lang/crates.io-index"
246 dependencies = [
247 "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
248 ]
249
250 [[package]]
251 name = "semver"
252 version = "0.9.0"
253 source = "registry+https://github.com/rust-lang/crates.io-index"
254 dependencies = [
255 "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
256 ]
257
258 [[package]]
259 name = "semver-parser"
260 version = "0.7.0"
261 source = "registry+https://github.com/rust-lang/crates.io-index"
262
263 [[package]]
112 name = "thread_local"
264 name = "thread_local"
113 version = "0.3.6"
265 version = "0.3.6"
114 source = "registry+https://github.com/rust-lang/crates.io-index"
266 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -131,19 +283,59 b' name = "version_check"'
131 version = "0.1.5"
283 version = "0.1.5"
132 source = "registry+https://github.com/rust-lang/crates.io-index"
284 source = "registry+https://github.com/rust-lang/crates.io-index"
133
285
286 [[package]]
287 name = "winapi"
288 version = "0.3.6"
289 source = "registry+https://github.com/rust-lang/crates.io-index"
290 dependencies = [
291 "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
292 "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
293 ]
294
295 [[package]]
296 name = "winapi-i686-pc-windows-gnu"
297 version = "0.4.0"
298 source = "registry+https://github.com/rust-lang/crates.io-index"
299
300 [[package]]
301 name = "winapi-x86_64-pc-windows-gnu"
302 version = "0.4.0"
303 source = "registry+https://github.com/rust-lang/crates.io-index"
304
134 [metadata]
305 [metadata]
135 "checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e"
306 "checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e"
307 "checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"
308 "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
136 "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
309 "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
310 "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
137 "checksum cpython 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b489034e723e7f5109fecd19b719e664f89ef925be785885252469e9822fa940"
311 "checksum cpython 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b489034e723e7f5109fecd19b719e664f89ef925be785885252469e9822fa940"
312 "checksum fuchsia-cprng 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81f7f8eb465745ea9b02e2704612a9946a59fa40572086c6fd49d6ddcf30bf31"
138 "checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
313 "checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
139 "checksum libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2857ec59fadc0773853c664d2d18e7198e83883e7060b63c924cb077bd5c74"
314 "checksum libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2857ec59fadc0773853c664d2d18e7198e83883e7060b63c924cb077bd5c74"
140 "checksum memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "db4c41318937f6e76648f42826b1d9ade5c09cafb5aef7e351240a70f39206e9"
315 "checksum memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "db4c41318937f6e76648f42826b1d9ade5c09cafb5aef7e351240a70f39206e9"
141 "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
316 "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
142 "checksum python27-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "56114c37d4dca82526d74009df7782a28c871ac9d36b19d4cb9e67672258527e"
317 "checksum python27-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "56114c37d4dca82526d74009df7782a28c871ac9d36b19d4cb9e67672258527e"
143 "checksum python3-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "61e4aac43f833fd637e429506cb2ac9d7df672c4b68f2eaaa163649b7fdc0444"
318 "checksum python3-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "61e4aac43f833fd637e429506cb2ac9d7df672c4b68f2eaaa163649b7fdc0444"
319 "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
320 "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
321 "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
322 "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
323 "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
324 "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
325 "checksum rand_jitter 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "080723c6145e37503a2224f801f252e14ac5531cb450f4502698542d188cb3c0"
326 "checksum rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b7c690732391ae0abafced5015ffb53656abfaec61b342290e5eb56b286a679d"
327 "checksum rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05"
328 "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
329 "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
144 "checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f"
330 "checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f"
145 "checksum regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4e47a2ed29da7a9e1960e1639e7a982e6edc6d49be308a3b02daf511504a16d1"
331 "checksum regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4e47a2ed29da7a9e1960e1639e7a982e6edc6d49be308a3b02daf511504a16d1"
332 "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
333 "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
334 "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
146 "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
335 "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
147 "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
336 "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
148 "checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
337 "checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
149 "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
338 "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
339 "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
340 "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
341 "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
@@ -6,3 +6,7 b' description = "Mercurial pure Rust core '
6
6
7 [lib]
7 [lib]
8 name = "hg"
8 name = "hg"
9
10 [dev-dependencies]
11 rand = "*"
12 rand_pcg = "*"
@@ -5,8 +5,7 b''
5 mod ancestors;
5 mod ancestors;
6 pub mod dagops;
6 pub mod dagops;
7 pub use ancestors::{AncestorsIterator, LazyAncestors, MissingAncestors};
7 pub use ancestors::{AncestorsIterator, LazyAncestors, MissingAncestors};
8 #[cfg(test)]
8 pub mod testing; // unconditionally built, for use from integration tests
9 pub mod testing;
10
9
11 /// Mercurial revision numbers
10 /// Mercurial revision numbers
12 ///
11 ///
General Comments 0
You need to be logged in to leave comments. Login now