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