##// END OF EJS Templates
hg-core: check data integrity in `Revlog`...
Antoine Cezar -
r46102:b0d6309f default
parent child Browse files
Show More
@@ -1,816 +1,895 b''
1 # This file is automatically @generated by Cargo.
1 # This file is automatically @generated by Cargo.
2 # It is not intended for manual editing.
2 # It is not intended for manual editing.
3 [[package]]
3 [[package]]
4 name = "adler"
4 name = "adler"
5 version = "0.2.3"
5 version = "0.2.3"
6 source = "registry+https://github.com/rust-lang/crates.io-index"
6 source = "registry+https://github.com/rust-lang/crates.io-index"
7
7
8 [[package]]
8 [[package]]
9 name = "aho-corasick"
9 name = "aho-corasick"
10 version = "0.7.13"
10 version = "0.7.13"
11 source = "registry+https://github.com/rust-lang/crates.io-index"
11 source = "registry+https://github.com/rust-lang/crates.io-index"
12 dependencies = [
12 dependencies = [
13 "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
13 "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
14 ]
14 ]
15
15
16 [[package]]
16 [[package]]
17 name = "ansi_term"
17 name = "ansi_term"
18 version = "0.11.0"
18 version = "0.11.0"
19 source = "registry+https://github.com/rust-lang/crates.io-index"
19 source = "registry+https://github.com/rust-lang/crates.io-index"
20 dependencies = [
20 dependencies = [
21 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
21 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
22 ]
22 ]
23
23
24 [[package]]
24 [[package]]
25 name = "atty"
25 name = "atty"
26 version = "0.2.14"
26 version = "0.2.14"
27 source = "registry+https://github.com/rust-lang/crates.io-index"
27 source = "registry+https://github.com/rust-lang/crates.io-index"
28 dependencies = [
28 dependencies = [
29 "hermit-abi 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
29 "hermit-abi 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
30 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
30 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
31 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
31 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
32 ]
32 ]
33
33
34 [[package]]
34 [[package]]
35 name = "autocfg"
35 name = "autocfg"
36 version = "1.0.1"
36 version = "1.0.1"
37 source = "registry+https://github.com/rust-lang/crates.io-index"
37 source = "registry+https://github.com/rust-lang/crates.io-index"
38
38
39 [[package]]
39 [[package]]
40 name = "bitflags"
40 name = "bitflags"
41 version = "1.2.1"
41 version = "1.2.1"
42 source = "registry+https://github.com/rust-lang/crates.io-index"
42 source = "registry+https://github.com/rust-lang/crates.io-index"
43
43
44 [[package]]
44 [[package]]
45 name = "byteorder"
45 name = "byteorder"
46 version = "1.3.4"
46 version = "1.3.4"
47 source = "registry+https://github.com/rust-lang/crates.io-index"
47 source = "registry+https://github.com/rust-lang/crates.io-index"
48
48
49 [[package]]
49 [[package]]
50 name = "cc"
50 name = "cc"
51 version = "1.0.60"
51 version = "1.0.60"
52 source = "registry+https://github.com/rust-lang/crates.io-index"
52 source = "registry+https://github.com/rust-lang/crates.io-index"
53 dependencies = [
53 dependencies = [
54 "jobserver 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
54 "jobserver 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
55 ]
55 ]
56
56
57 [[package]]
57 [[package]]
58 name = "cfg-if"
58 name = "cfg-if"
59 version = "0.1.10"
59 version = "0.1.10"
60 source = "registry+https://github.com/rust-lang/crates.io-index"
60 source = "registry+https://github.com/rust-lang/crates.io-index"
61
61
62 [[package]]
62 [[package]]
63 name = "clap"
63 name = "clap"
64 version = "2.33.3"
64 version = "2.33.3"
65 source = "registry+https://github.com/rust-lang/crates.io-index"
65 source = "registry+https://github.com/rust-lang/crates.io-index"
66 dependencies = [
66 dependencies = [
67 "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
67 "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
68 "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
68 "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
69 "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
69 "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
70 "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
70 "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
71 "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
71 "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
72 "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
72 "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
73 "vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
73 "vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
74 ]
74 ]
75
75
76 [[package]]
76 [[package]]
77 name = "cpython"
77 name = "cpython"
78 version = "0.4.1"
78 version = "0.4.1"
79 source = "registry+https://github.com/rust-lang/crates.io-index"
79 source = "registry+https://github.com/rust-lang/crates.io-index"
80 dependencies = [
80 dependencies = [
81 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
81 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
82 "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
82 "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
83 "python27-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
83 "python27-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
84 "python3-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
84 "python3-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
85 ]
85 ]
86
86
87 [[package]]
87 [[package]]
88 name = "crc32fast"
88 name = "crc32fast"
89 version = "1.2.0"
89 version = "1.2.0"
90 source = "registry+https://github.com/rust-lang/crates.io-index"
90 source = "registry+https://github.com/rust-lang/crates.io-index"
91 dependencies = [
91 dependencies = [
92 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
92 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
93 ]
93 ]
94
94
95 [[package]]
95 [[package]]
96 name = "crossbeam"
96 name = "crossbeam"
97 version = "0.7.3"
97 version = "0.7.3"
98 source = "registry+https://github.com/rust-lang/crates.io-index"
98 source = "registry+https://github.com/rust-lang/crates.io-index"
99 dependencies = [
99 dependencies = [
100 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
100 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
101 "crossbeam-channel 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
101 "crossbeam-channel 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
102 "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
102 "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
103 "crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
103 "crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
104 "crossbeam-queue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
104 "crossbeam-queue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
105 "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
105 "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
106 ]
106 ]
107
107
108 [[package]]
108 [[package]]
109 name = "crossbeam-channel"
109 name = "crossbeam-channel"
110 version = "0.4.4"
110 version = "0.4.4"
111 source = "registry+https://github.com/rust-lang/crates.io-index"
111 source = "registry+https://github.com/rust-lang/crates.io-index"
112 dependencies = [
112 dependencies = [
113 "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
113 "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
114 "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
114 "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
115 ]
115 ]
116
116
117 [[package]]
117 [[package]]
118 name = "crossbeam-deque"
118 name = "crossbeam-deque"
119 version = "0.7.3"
119 version = "0.7.3"
120 source = "registry+https://github.com/rust-lang/crates.io-index"
120 source = "registry+https://github.com/rust-lang/crates.io-index"
121 dependencies = [
121 dependencies = [
122 "crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
122 "crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
123 "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
123 "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
124 "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
124 "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
125 ]
125 ]
126
126
127 [[package]]
127 [[package]]
128 name = "crossbeam-epoch"
128 name = "crossbeam-epoch"
129 version = "0.8.2"
129 version = "0.8.2"
130 source = "registry+https://github.com/rust-lang/crates.io-index"
130 source = "registry+https://github.com/rust-lang/crates.io-index"
131 dependencies = [
131 dependencies = [
132 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
132 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
133 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
133 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
134 "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
134 "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
135 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
135 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
136 "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
136 "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
137 "memoffset 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
137 "memoffset 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
138 "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
138 "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
139 ]
139 ]
140
140
141 [[package]]
141 [[package]]
142 name = "crossbeam-queue"
142 name = "crossbeam-queue"
143 version = "0.2.3"
143 version = "0.2.3"
144 source = "registry+https://github.com/rust-lang/crates.io-index"
144 source = "registry+https://github.com/rust-lang/crates.io-index"
145 dependencies = [
145 dependencies = [
146 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
146 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
147 "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
147 "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
148 "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
148 "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
149 ]
149 ]
150
150
151 [[package]]
151 [[package]]
152 name = "crossbeam-utils"
152 name = "crossbeam-utils"
153 version = "0.7.2"
153 version = "0.7.2"
154 source = "registry+https://github.com/rust-lang/crates.io-index"
154 source = "registry+https://github.com/rust-lang/crates.io-index"
155 dependencies = [
155 dependencies = [
156 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
156 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
157 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
157 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
158 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
158 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
159 ]
159 ]
160
160
161 [[package]]
161 [[package]]
162 name = "ctor"
162 name = "ctor"
163 version = "0.1.16"
163 version = "0.1.16"
164 source = "registry+https://github.com/rust-lang/crates.io-index"
164 source = "registry+https://github.com/rust-lang/crates.io-index"
165 dependencies = [
165 dependencies = [
166 "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
166 "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
167 "syn 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
167 "syn 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
168 ]
168 ]
169
169
170 [[package]]
170 [[package]]
171 name = "difference"
171 name = "difference"
172 version = "2.0.0"
172 version = "2.0.0"
173 source = "registry+https://github.com/rust-lang/crates.io-index"
173 source = "registry+https://github.com/rust-lang/crates.io-index"
174
174
175 [[package]]
175 [[package]]
176 name = "either"
176 name = "either"
177 version = "1.6.1"
177 version = "1.6.1"
178 source = "registry+https://github.com/rust-lang/crates.io-index"
178 source = "registry+https://github.com/rust-lang/crates.io-index"
179
179
180 [[package]]
180 [[package]]
181 name = "env_logger"
181 name = "env_logger"
182 version = "0.7.1"
182 version = "0.7.1"
183 source = "registry+https://github.com/rust-lang/crates.io-index"
183 source = "registry+https://github.com/rust-lang/crates.io-index"
184 dependencies = [
184 dependencies = [
185 "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
185 "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
186 "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
186 "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
187 "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
187 "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
188 "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
188 "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
189 "termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
189 "termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
190 ]
190 ]
191
191
192 [[package]]
192 [[package]]
193 name = "flate2"
193 name = "flate2"
194 version = "1.0.17"
194 version = "1.0.17"
195 source = "registry+https://github.com/rust-lang/crates.io-index"
195 source = "registry+https://github.com/rust-lang/crates.io-index"
196 dependencies = [
196 dependencies = [
197 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
197 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
198 "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
198 "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
199 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
199 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
200 "libz-sys 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
200 "libz-sys 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
201 "miniz_oxide 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
201 "miniz_oxide 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
202 ]
202 ]
203
203
204 [[package]]
204 [[package]]
205 name = "fuchsia-cprng"
206 version = "0.1.1"
207 source = "registry+https://github.com/rust-lang/crates.io-index"
208
209 [[package]]
210 name = "gcc"
211 version = "0.3.55"
212 source = "registry+https://github.com/rust-lang/crates.io-index"
213
214 [[package]]
205 name = "getrandom"
215 name = "getrandom"
206 version = "0.1.15"
216 version = "0.1.15"
207 source = "registry+https://github.com/rust-lang/crates.io-index"
217 source = "registry+https://github.com/rust-lang/crates.io-index"
208 dependencies = [
218 dependencies = [
209 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
219 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
210 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
220 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
211 "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
221 "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
212 ]
222 ]
213
223
214 [[package]]
224 [[package]]
215 name = "glob"
225 name = "glob"
216 version = "0.3.0"
226 version = "0.3.0"
217 source = "registry+https://github.com/rust-lang/crates.io-index"
227 source = "registry+https://github.com/rust-lang/crates.io-index"
218
228
219 [[package]]
229 [[package]]
220 name = "hermit-abi"
230 name = "hermit-abi"
221 version = "0.1.16"
231 version = "0.1.16"
222 source = "registry+https://github.com/rust-lang/crates.io-index"
232 source = "registry+https://github.com/rust-lang/crates.io-index"
223 dependencies = [
233 dependencies = [
224 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
234 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
225 ]
235 ]
226
236
227 [[package]]
237 [[package]]
228 name = "hex"
238 name = "hex"
229 version = "0.4.2"
239 version = "0.4.2"
230 source = "registry+https://github.com/rust-lang/crates.io-index"
240 source = "registry+https://github.com/rust-lang/crates.io-index"
231
241
232 [[package]]
242 [[package]]
233 name = "hg-core"
243 name = "hg-core"
234 version = "0.1.0"
244 version = "0.1.0"
235 dependencies = [
245 dependencies = [
236 "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
246 "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
237 "clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)",
247 "clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)",
238 "crossbeam 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
248 "crossbeam 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
239 "flate2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
249 "flate2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
240 "hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
250 "hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
241 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
251 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
242 "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
252 "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
243 "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
253 "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
244 "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
254 "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
245 "micro-timer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
255 "micro-timer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
246 "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
256 "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
247 "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
257 "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
248 "rand_distr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
258 "rand_distr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
249 "rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
259 "rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
250 "rayon 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
260 "rayon 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
251 "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
261 "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
262 "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
252 "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
263 "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
253 "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
264 "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
254 "twox-hash 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
265 "twox-hash 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
255 "zstd 0.5.3+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
266 "zstd 0.5.3+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
256 ]
267 ]
257
268
258 [[package]]
269 [[package]]
259 name = "hg-cpython"
270 name = "hg-cpython"
260 version = "0.1.0"
271 version = "0.1.0"
261 dependencies = [
272 dependencies = [
262 "cpython 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
273 "cpython 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
263 "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
274 "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
264 "hg-core 0.1.0",
275 "hg-core 0.1.0",
265 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
276 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
266 "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
277 "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
267 ]
278 ]
268
279
269 [[package]]
280 [[package]]
270 name = "humantime"
281 name = "humantime"
271 version = "1.3.0"
282 version = "1.3.0"
272 source = "registry+https://github.com/rust-lang/crates.io-index"
283 source = "registry+https://github.com/rust-lang/crates.io-index"
273 dependencies = [
284 dependencies = [
274 "quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
285 "quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
275 ]
286 ]
276
287
277 [[package]]
288 [[package]]
278 name = "itertools"
289 name = "itertools"
279 version = "0.9.0"
290 version = "0.9.0"
280 source = "registry+https://github.com/rust-lang/crates.io-index"
291 source = "registry+https://github.com/rust-lang/crates.io-index"
281 dependencies = [
292 dependencies = [
282 "either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
293 "either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
283 ]
294 ]
284
295
285 [[package]]
296 [[package]]
286 name = "jobserver"
297 name = "jobserver"
287 version = "0.1.21"
298 version = "0.1.21"
288 source = "registry+https://github.com/rust-lang/crates.io-index"
299 source = "registry+https://github.com/rust-lang/crates.io-index"
289 dependencies = [
300 dependencies = [
290 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
301 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
291 ]
302 ]
292
303
293 [[package]]
304 [[package]]
294 name = "lazy_static"
305 name = "lazy_static"
295 version = "1.4.0"
306 version = "1.4.0"
296 source = "registry+https://github.com/rust-lang/crates.io-index"
307 source = "registry+https://github.com/rust-lang/crates.io-index"
297
308
298 [[package]]
309 [[package]]
299 name = "libc"
310 name = "libc"
300 version = "0.2.77"
311 version = "0.2.77"
301 source = "registry+https://github.com/rust-lang/crates.io-index"
312 source = "registry+https://github.com/rust-lang/crates.io-index"
302
313
303 [[package]]
314 [[package]]
304 name = "libz-sys"
315 name = "libz-sys"
305 version = "1.1.2"
316 version = "1.1.2"
306 source = "registry+https://github.com/rust-lang/crates.io-index"
317 source = "registry+https://github.com/rust-lang/crates.io-index"
307 dependencies = [
318 dependencies = [
308 "cc 1.0.60 (registry+https://github.com/rust-lang/crates.io-index)",
319 "cc 1.0.60 (registry+https://github.com/rust-lang/crates.io-index)",
309 "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
320 "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
310 "vcpkg 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
321 "vcpkg 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
311 ]
322 ]
312
323
313 [[package]]
324 [[package]]
314 name = "log"
325 name = "log"
315 version = "0.4.11"
326 version = "0.4.11"
316 source = "registry+https://github.com/rust-lang/crates.io-index"
327 source = "registry+https://github.com/rust-lang/crates.io-index"
317 dependencies = [
328 dependencies = [
318 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
329 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
319 ]
330 ]
320
331
321 [[package]]
332 [[package]]
322 name = "maybe-uninit"
333 name = "maybe-uninit"
323 version = "2.0.0"
334 version = "2.0.0"
324 source = "registry+https://github.com/rust-lang/crates.io-index"
335 source = "registry+https://github.com/rust-lang/crates.io-index"
325
336
326 [[package]]
337 [[package]]
327 name = "memchr"
338 name = "memchr"
328 version = "2.3.3"
339 version = "2.3.3"
329 source = "registry+https://github.com/rust-lang/crates.io-index"
340 source = "registry+https://github.com/rust-lang/crates.io-index"
330
341
331 [[package]]
342 [[package]]
332 name = "memmap"
343 name = "memmap"
333 version = "0.7.0"
344 version = "0.7.0"
334 source = "registry+https://github.com/rust-lang/crates.io-index"
345 source = "registry+https://github.com/rust-lang/crates.io-index"
335 dependencies = [
346 dependencies = [
336 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
347 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
337 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
348 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
338 ]
349 ]
339
350
340 [[package]]
351 [[package]]
341 name = "memoffset"
352 name = "memoffset"
342 version = "0.5.6"
353 version = "0.5.6"
343 source = "registry+https://github.com/rust-lang/crates.io-index"
354 source = "registry+https://github.com/rust-lang/crates.io-index"
344 dependencies = [
355 dependencies = [
345 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
356 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
346 ]
357 ]
347
358
348 [[package]]
359 [[package]]
349 name = "micro-timer"
360 name = "micro-timer"
350 version = "0.3.1"
361 version = "0.3.1"
351 source = "registry+https://github.com/rust-lang/crates.io-index"
362 source = "registry+https://github.com/rust-lang/crates.io-index"
352 dependencies = [
363 dependencies = [
353 "micro-timer-macros 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
364 "micro-timer-macros 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
354 "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
365 "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
355 ]
366 ]
356
367
357 [[package]]
368 [[package]]
358 name = "micro-timer-macros"
369 name = "micro-timer-macros"
359 version = "0.3.1"
370 version = "0.3.1"
360 source = "registry+https://github.com/rust-lang/crates.io-index"
371 source = "registry+https://github.com/rust-lang/crates.io-index"
361 dependencies = [
372 dependencies = [
362 "proc-macro2 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)",
373 "proc-macro2 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)",
363 "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
374 "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
364 "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
375 "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
365 "syn 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
376 "syn 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
366 ]
377 ]
367
378
368 [[package]]
379 [[package]]
369 name = "miniz_oxide"
380 name = "miniz_oxide"
370 version = "0.4.2"
381 version = "0.4.2"
371 source = "registry+https://github.com/rust-lang/crates.io-index"
382 source = "registry+https://github.com/rust-lang/crates.io-index"
372 dependencies = [
383 dependencies = [
373 "adler 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
384 "adler 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
374 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
385 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
375 ]
386 ]
376
387
377 [[package]]
388 [[package]]
378 name = "num-traits"
389 name = "num-traits"
379 version = "0.2.12"
390 version = "0.2.12"
380 source = "registry+https://github.com/rust-lang/crates.io-index"
391 source = "registry+https://github.com/rust-lang/crates.io-index"
381 dependencies = [
392 dependencies = [
382 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
393 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
383 ]
394 ]
384
395
385 [[package]]
396 [[package]]
386 name = "num_cpus"
397 name = "num_cpus"
387 version = "1.13.0"
398 version = "1.13.0"
388 source = "registry+https://github.com/rust-lang/crates.io-index"
399 source = "registry+https://github.com/rust-lang/crates.io-index"
389 dependencies = [
400 dependencies = [
390 "hermit-abi 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
401 "hermit-abi 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
391 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
402 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
392 ]
403 ]
393
404
394 [[package]]
405 [[package]]
395 name = "output_vt100"
406 name = "output_vt100"
396 version = "0.1.2"
407 version = "0.1.2"
397 source = "registry+https://github.com/rust-lang/crates.io-index"
408 source = "registry+https://github.com/rust-lang/crates.io-index"
398 dependencies = [
409 dependencies = [
399 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
410 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
400 ]
411 ]
401
412
402 [[package]]
413 [[package]]
403 name = "pkg-config"
414 name = "pkg-config"
404 version = "0.3.18"
415 version = "0.3.18"
405 source = "registry+https://github.com/rust-lang/crates.io-index"
416 source = "registry+https://github.com/rust-lang/crates.io-index"
406
417
407 [[package]]
418 [[package]]
408 name = "ppv-lite86"
419 name = "ppv-lite86"
409 version = "0.2.9"
420 version = "0.2.9"
410 source = "registry+https://github.com/rust-lang/crates.io-index"
421 source = "registry+https://github.com/rust-lang/crates.io-index"
411
422
412 [[package]]
423 [[package]]
413 name = "pretty_assertions"
424 name = "pretty_assertions"
414 version = "0.6.1"
425 version = "0.6.1"
415 source = "registry+https://github.com/rust-lang/crates.io-index"
426 source = "registry+https://github.com/rust-lang/crates.io-index"
416 dependencies = [
427 dependencies = [
417 "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
428 "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
418 "ctor 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
429 "ctor 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
419 "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
430 "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
420 "output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
431 "output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
421 ]
432 ]
422
433
423 [[package]]
434 [[package]]
424 name = "proc-macro2"
435 name = "proc-macro2"
425 version = "1.0.21"
436 version = "1.0.21"
426 source = "registry+https://github.com/rust-lang/crates.io-index"
437 source = "registry+https://github.com/rust-lang/crates.io-index"
427 dependencies = [
438 dependencies = [
428 "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
439 "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
429 ]
440 ]
430
441
431 [[package]]
442 [[package]]
432 name = "python27-sys"
443 name = "python27-sys"
433 version = "0.4.1"
444 version = "0.4.1"
434 source = "registry+https://github.com/rust-lang/crates.io-index"
445 source = "registry+https://github.com/rust-lang/crates.io-index"
435 dependencies = [
446 dependencies = [
436 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
447 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
437 "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
448 "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
438 ]
449 ]
439
450
440 [[package]]
451 [[package]]
441 name = "python3-sys"
452 name = "python3-sys"
442 version = "0.4.1"
453 version = "0.4.1"
443 source = "registry+https://github.com/rust-lang/crates.io-index"
454 source = "registry+https://github.com/rust-lang/crates.io-index"
444 dependencies = [
455 dependencies = [
445 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
456 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
446 "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
457 "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
447 ]
458 ]
448
459
449 [[package]]
460 [[package]]
450 name = "quick-error"
461 name = "quick-error"
451 version = "1.2.3"
462 version = "1.2.3"
452 source = "registry+https://github.com/rust-lang/crates.io-index"
463 source = "registry+https://github.com/rust-lang/crates.io-index"
453
464
454 [[package]]
465 [[package]]
455 name = "quote"
466 name = "quote"
456 version = "1.0.7"
467 version = "1.0.7"
457 source = "registry+https://github.com/rust-lang/crates.io-index"
468 source = "registry+https://github.com/rust-lang/crates.io-index"
458 dependencies = [
469 dependencies = [
459 "proc-macro2 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)",
470 "proc-macro2 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)",
460 ]
471 ]
461
472
462 [[package]]
473 [[package]]
463 name = "rand"
474 name = "rand"
475 version = "0.3.23"
476 source = "registry+https://github.com/rust-lang/crates.io-index"
477 dependencies = [
478 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
479 "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
480 ]
481
482 [[package]]
483 name = "rand"
484 version = "0.4.6"
485 source = "registry+https://github.com/rust-lang/crates.io-index"
486 dependencies = [
487 "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
488 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
489 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
490 "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
491 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
492 ]
493
494 [[package]]
495 name = "rand"
464 version = "0.7.3"
496 version = "0.7.3"
465 source = "registry+https://github.com/rust-lang/crates.io-index"
497 source = "registry+https://github.com/rust-lang/crates.io-index"
466 dependencies = [
498 dependencies = [
467 "getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
499 "getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
468 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
500 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
469 "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
501 "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
470 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
502 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
471 "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
503 "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
472 ]
504 ]
473
505
474 [[package]]
506 [[package]]
475 name = "rand_chacha"
507 name = "rand_chacha"
476 version = "0.2.2"
508 version = "0.2.2"
477 source = "registry+https://github.com/rust-lang/crates.io-index"
509 source = "registry+https://github.com/rust-lang/crates.io-index"
478 dependencies = [
510 dependencies = [
479 "ppv-lite86 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
511 "ppv-lite86 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
480 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
512 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
481 ]
513 ]
482
514
483 [[package]]
515 [[package]]
484 name = "rand_core"
516 name = "rand_core"
517 version = "0.3.1"
518 source = "registry+https://github.com/rust-lang/crates.io-index"
519 dependencies = [
520 "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
521 ]
522
523 [[package]]
524 name = "rand_core"
525 version = "0.4.2"
526 source = "registry+https://github.com/rust-lang/crates.io-index"
527
528 [[package]]
529 name = "rand_core"
485 version = "0.5.1"
530 version = "0.5.1"
486 source = "registry+https://github.com/rust-lang/crates.io-index"
531 source = "registry+https://github.com/rust-lang/crates.io-index"
487 dependencies = [
532 dependencies = [
488 "getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
533 "getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
489 ]
534 ]
490
535
491 [[package]]
536 [[package]]
492 name = "rand_distr"
537 name = "rand_distr"
493 version = "0.2.2"
538 version = "0.2.2"
494 source = "registry+https://github.com/rust-lang/crates.io-index"
539 source = "registry+https://github.com/rust-lang/crates.io-index"
495 dependencies = [
540 dependencies = [
496 "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
541 "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
497 ]
542 ]
498
543
499 [[package]]
544 [[package]]
500 name = "rand_hc"
545 name = "rand_hc"
501 version = "0.2.0"
546 version = "0.2.0"
502 source = "registry+https://github.com/rust-lang/crates.io-index"
547 source = "registry+https://github.com/rust-lang/crates.io-index"
503 dependencies = [
548 dependencies = [
504 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
549 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
505 ]
550 ]
506
551
507 [[package]]
552 [[package]]
508 name = "rand_pcg"
553 name = "rand_pcg"
509 version = "0.2.1"
554 version = "0.2.1"
510 source = "registry+https://github.com/rust-lang/crates.io-index"
555 source = "registry+https://github.com/rust-lang/crates.io-index"
511 dependencies = [
556 dependencies = [
512 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
557 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
513 ]
558 ]
514
559
515 [[package]]
560 [[package]]
516 name = "rayon"
561 name = "rayon"
517 version = "1.4.0"
562 version = "1.4.0"
518 source = "registry+https://github.com/rust-lang/crates.io-index"
563 source = "registry+https://github.com/rust-lang/crates.io-index"
519 dependencies = [
564 dependencies = [
520 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
565 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
521 "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
566 "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
522 "either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
567 "either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
523 "rayon-core 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
568 "rayon-core 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
524 ]
569 ]
525
570
526 [[package]]
571 [[package]]
527 name = "rayon-core"
572 name = "rayon-core"
528 version = "1.8.1"
573 version = "1.8.1"
529 source = "registry+https://github.com/rust-lang/crates.io-index"
574 source = "registry+https://github.com/rust-lang/crates.io-index"
530 dependencies = [
575 dependencies = [
531 "crossbeam-channel 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
576 "crossbeam-channel 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
532 "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
577 "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
533 "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
578 "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
534 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
579 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
535 "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
580 "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
536 ]
581 ]
537
582
538 [[package]]
583 [[package]]
584 name = "rdrand"
585 version = "0.4.0"
586 source = "registry+https://github.com/rust-lang/crates.io-index"
587 dependencies = [
588 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
589 ]
590
591 [[package]]
539 name = "redox_syscall"
592 name = "redox_syscall"
540 version = "0.1.57"
593 version = "0.1.57"
541 source = "registry+https://github.com/rust-lang/crates.io-index"
594 source = "registry+https://github.com/rust-lang/crates.io-index"
542
595
543 [[package]]
596 [[package]]
544 name = "regex"
597 name = "regex"
545 version = "1.3.9"
598 version = "1.3.9"
546 source = "registry+https://github.com/rust-lang/crates.io-index"
599 source = "registry+https://github.com/rust-lang/crates.io-index"
547 dependencies = [
600 dependencies = [
548 "aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)",
601 "aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)",
549 "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
602 "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
550 "regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)",
603 "regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)",
551 "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
604 "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
552 ]
605 ]
553
606
554 [[package]]
607 [[package]]
555 name = "regex-syntax"
608 name = "regex-syntax"
556 version = "0.6.18"
609 version = "0.6.18"
557 source = "registry+https://github.com/rust-lang/crates.io-index"
610 source = "registry+https://github.com/rust-lang/crates.io-index"
558
611
559 [[package]]
612 [[package]]
560 name = "remove_dir_all"
613 name = "remove_dir_all"
561 version = "0.5.3"
614 version = "0.5.3"
562 source = "registry+https://github.com/rust-lang/crates.io-index"
615 source = "registry+https://github.com/rust-lang/crates.io-index"
563 dependencies = [
616 dependencies = [
564 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
617 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
565 ]
618 ]
566
619
567 [[package]]
620 [[package]]
568 name = "rhg"
621 name = "rhg"
569 version = "0.1.0"
622 version = "0.1.0"
570 dependencies = [
623 dependencies = [
571 "clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)",
624 "clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)",
572 "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
625 "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
573 "hg-core 0.1.0",
626 "hg-core 0.1.0",
574 "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
627 "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
575 "micro-timer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
628 "micro-timer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
576 ]
629 ]
577
630
578 [[package]]
631 [[package]]
632 name = "rust-crypto"
633 version = "0.2.36"
634 source = "registry+https://github.com/rust-lang/crates.io-index"
635 dependencies = [
636 "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)",
637 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
638 "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)",
639 "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
640 "time 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)",
641 ]
642
643 [[package]]
644 name = "rustc-serialize"
645 version = "0.3.24"
646 source = "registry+https://github.com/rust-lang/crates.io-index"
647
648 [[package]]
579 name = "same-file"
649 name = "same-file"
580 version = "1.0.6"
650 version = "1.0.6"
581 source = "registry+https://github.com/rust-lang/crates.io-index"
651 source = "registry+https://github.com/rust-lang/crates.io-index"
582 dependencies = [
652 dependencies = [
583 "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
653 "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
584 ]
654 ]
585
655
586 [[package]]
656 [[package]]
587 name = "scopeguard"
657 name = "scopeguard"
588 version = "1.1.0"
658 version = "1.1.0"
589 source = "registry+https://github.com/rust-lang/crates.io-index"
659 source = "registry+https://github.com/rust-lang/crates.io-index"
590
660
591 [[package]]
661 [[package]]
592 name = "strsim"
662 name = "strsim"
593 version = "0.8.0"
663 version = "0.8.0"
594 source = "registry+https://github.com/rust-lang/crates.io-index"
664 source = "registry+https://github.com/rust-lang/crates.io-index"
595
665
596 [[package]]
666 [[package]]
597 name = "syn"
667 name = "syn"
598 version = "1.0.41"
668 version = "1.0.41"
599 source = "registry+https://github.com/rust-lang/crates.io-index"
669 source = "registry+https://github.com/rust-lang/crates.io-index"
600 dependencies = [
670 dependencies = [
601 "proc-macro2 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)",
671 "proc-macro2 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)",
602 "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
672 "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
603 "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
673 "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
604 ]
674 ]
605
675
606 [[package]]
676 [[package]]
607 name = "tempfile"
677 name = "tempfile"
608 version = "3.1.0"
678 version = "3.1.0"
609 source = "registry+https://github.com/rust-lang/crates.io-index"
679 source = "registry+https://github.com/rust-lang/crates.io-index"
610 dependencies = [
680 dependencies = [
611 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
681 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
612 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
682 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
613 "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
683 "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
614 "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)",
684 "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)",
615 "remove_dir_all 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
685 "remove_dir_all 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
616 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
686 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
617 ]
687 ]
618
688
619 [[package]]
689 [[package]]
620 name = "termcolor"
690 name = "termcolor"
621 version = "1.1.0"
691 version = "1.1.0"
622 source = "registry+https://github.com/rust-lang/crates.io-index"
692 source = "registry+https://github.com/rust-lang/crates.io-index"
623 dependencies = [
693 dependencies = [
624 "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
694 "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
625 ]
695 ]
626
696
627 [[package]]
697 [[package]]
628 name = "textwrap"
698 name = "textwrap"
629 version = "0.11.0"
699 version = "0.11.0"
630 source = "registry+https://github.com/rust-lang/crates.io-index"
700 source = "registry+https://github.com/rust-lang/crates.io-index"
631 dependencies = [
701 dependencies = [
632 "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
702 "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
633 ]
703 ]
634
704
635 [[package]]
705 [[package]]
636 name = "thread_local"
706 name = "thread_local"
637 version = "1.0.1"
707 version = "1.0.1"
638 source = "registry+https://github.com/rust-lang/crates.io-index"
708 source = "registry+https://github.com/rust-lang/crates.io-index"
639 dependencies = [
709 dependencies = [
640 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
710 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
641 ]
711 ]
642
712
643 [[package]]
713 [[package]]
644 name = "twox-hash"
714 name = "twox-hash"
645 version = "1.5.0"
715 version = "1.5.0"
646 source = "registry+https://github.com/rust-lang/crates.io-index"
716 source = "registry+https://github.com/rust-lang/crates.io-index"
647 dependencies = [
717 dependencies = [
648 "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
718 "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
649 ]
719 ]
650
720
651 [[package]]
721 [[package]]
652 name = "unicode-width"
722 name = "unicode-width"
653 version = "0.1.8"
723 version = "0.1.8"
654 source = "registry+https://github.com/rust-lang/crates.io-index"
724 source = "registry+https://github.com/rust-lang/crates.io-index"
655
725
656 [[package]]
726 [[package]]
657 name = "unicode-xid"
727 name = "unicode-xid"
658 version = "0.2.1"
728 version = "0.2.1"
659 source = "registry+https://github.com/rust-lang/crates.io-index"
729 source = "registry+https://github.com/rust-lang/crates.io-index"
660
730
661 [[package]]
731 [[package]]
662 name = "vcpkg"
732 name = "vcpkg"
663 version = "0.2.10"
733 version = "0.2.10"
664 source = "registry+https://github.com/rust-lang/crates.io-index"
734 source = "registry+https://github.com/rust-lang/crates.io-index"
665
735
666 [[package]]
736 [[package]]
667 name = "vec_map"
737 name = "vec_map"
668 version = "0.8.2"
738 version = "0.8.2"
669 source = "registry+https://github.com/rust-lang/crates.io-index"
739 source = "registry+https://github.com/rust-lang/crates.io-index"
670
740
671 [[package]]
741 [[package]]
672 name = "wasi"
742 name = "wasi"
673 version = "0.9.0+wasi-snapshot-preview1"
743 version = "0.9.0+wasi-snapshot-preview1"
674 source = "registry+https://github.com/rust-lang/crates.io-index"
744 source = "registry+https://github.com/rust-lang/crates.io-index"
675
745
676 [[package]]
746 [[package]]
677 name = "winapi"
747 name = "winapi"
678 version = "0.3.9"
748 version = "0.3.9"
679 source = "registry+https://github.com/rust-lang/crates.io-index"
749 source = "registry+https://github.com/rust-lang/crates.io-index"
680 dependencies = [
750 dependencies = [
681 "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
751 "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
682 "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
752 "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
683 ]
753 ]
684
754
685 [[package]]
755 [[package]]
686 name = "winapi-i686-pc-windows-gnu"
756 name = "winapi-i686-pc-windows-gnu"
687 version = "0.4.0"
757 version = "0.4.0"
688 source = "registry+https://github.com/rust-lang/crates.io-index"
758 source = "registry+https://github.com/rust-lang/crates.io-index"
689
759
690 [[package]]
760 [[package]]
691 name = "winapi-util"
761 name = "winapi-util"
692 version = "0.1.5"
762 version = "0.1.5"
693 source = "registry+https://github.com/rust-lang/crates.io-index"
763 source = "registry+https://github.com/rust-lang/crates.io-index"
694 dependencies = [
764 dependencies = [
695 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
765 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
696 ]
766 ]
697
767
698 [[package]]
768 [[package]]
699 name = "winapi-x86_64-pc-windows-gnu"
769 name = "winapi-x86_64-pc-windows-gnu"
700 version = "0.4.0"
770 version = "0.4.0"
701 source = "registry+https://github.com/rust-lang/crates.io-index"
771 source = "registry+https://github.com/rust-lang/crates.io-index"
702
772
703 [[package]]
773 [[package]]
704 name = "zstd"
774 name = "zstd"
705 version = "0.5.3+zstd.1.4.5"
775 version = "0.5.3+zstd.1.4.5"
706 source = "registry+https://github.com/rust-lang/crates.io-index"
776 source = "registry+https://github.com/rust-lang/crates.io-index"
707 dependencies = [
777 dependencies = [
708 "zstd-safe 2.0.5+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
778 "zstd-safe 2.0.5+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
709 ]
779 ]
710
780
711 [[package]]
781 [[package]]
712 name = "zstd-safe"
782 name = "zstd-safe"
713 version = "2.0.5+zstd.1.4.5"
783 version = "2.0.5+zstd.1.4.5"
714 source = "registry+https://github.com/rust-lang/crates.io-index"
784 source = "registry+https://github.com/rust-lang/crates.io-index"
715 dependencies = [
785 dependencies = [
716 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
786 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
717 "zstd-sys 1.4.17+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
787 "zstd-sys 1.4.17+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
718 ]
788 ]
719
789
720 [[package]]
790 [[package]]
721 name = "zstd-sys"
791 name = "zstd-sys"
722 version = "1.4.17+zstd.1.4.5"
792 version = "1.4.17+zstd.1.4.5"
723 source = "registry+https://github.com/rust-lang/crates.io-index"
793 source = "registry+https://github.com/rust-lang/crates.io-index"
724 dependencies = [
794 dependencies = [
725 "cc 1.0.60 (registry+https://github.com/rust-lang/crates.io-index)",
795 "cc 1.0.60 (registry+https://github.com/rust-lang/crates.io-index)",
726 "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
796 "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
727 "itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
797 "itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
728 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
798 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
729 ]
799 ]
730
800
731 [metadata]
801 [metadata]
732 "checksum adler 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
802 "checksum adler 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
733 "checksum aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)" = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86"
803 "checksum aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)" = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86"
734 "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
804 "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
735 "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
805 "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
736 "checksum autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
806 "checksum autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
737 "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
807 "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
738 "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
808 "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
739 "checksum cc 1.0.60 (registry+https://github.com/rust-lang/crates.io-index)" = "ef611cc68ff783f18535d77ddd080185275713d852c4f5cbb6122c462a7a825c"
809 "checksum cc 1.0.60 (registry+https://github.com/rust-lang/crates.io-index)" = "ef611cc68ff783f18535d77ddd080185275713d852c4f5cbb6122c462a7a825c"
740 "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
810 "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
741 "checksum clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)" = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
811 "checksum clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)" = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
742 "checksum cpython 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bfaf3847ab963e40c4f6dd8d6be279bdf74007ae2413786a0dcbb28c52139a95"
812 "checksum cpython 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bfaf3847ab963e40c4f6dd8d6be279bdf74007ae2413786a0dcbb28c52139a95"
743 "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
813 "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
744 "checksum crossbeam 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e"
814 "checksum crossbeam 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e"
745 "checksum crossbeam-channel 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87"
815 "checksum crossbeam-channel 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87"
746 "checksum crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285"
816 "checksum crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285"
747 "checksum crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
817 "checksum crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
748 "checksum crossbeam-queue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570"
818 "checksum crossbeam-queue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570"
749 "checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
819 "checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
750 "checksum ctor 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "7fbaabec2c953050352311293be5c6aba8e141ba19d6811862b232d6fd020484"
820 "checksum ctor 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "7fbaabec2c953050352311293be5c6aba8e141ba19d6811862b232d6fd020484"
751 "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
821 "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
752 "checksum either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
822 "checksum either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
753 "checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
823 "checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
754 "checksum flate2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "766d0e77a2c1502169d4a93ff3b8c15a71fd946cd0126309752104e5f3c46d94"
824 "checksum flate2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "766d0e77a2c1502169d4a93ff3b8c15a71fd946cd0126309752104e5f3c46d94"
825 "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
826 "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
755 "checksum getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
827 "checksum getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
756 "checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
828 "checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
757 "checksum hermit-abi 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c30f6d0bc6b00693347368a67d41b58f2fb851215ff1da49e90fe2c5c667151"
829 "checksum hermit-abi 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c30f6d0bc6b00693347368a67d41b58f2fb851215ff1da49e90fe2c5c667151"
758 "checksum hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
830 "checksum hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
759 "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
831 "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
760 "checksum itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
832 "checksum itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
761 "checksum jobserver 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2"
833 "checksum jobserver 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2"
762 "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
834 "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
763 "checksum libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235"
835 "checksum libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235"
764 "checksum libz-sys 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "602113192b08db8f38796c4e85c39e960c145965140e918018bcde1952429655"
836 "checksum libz-sys 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "602113192b08db8f38796c4e85c39e960c145965140e918018bcde1952429655"
765 "checksum log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
837 "checksum log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
766 "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
838 "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
767 "checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
839 "checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
768 "checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
840 "checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
769 "checksum memoffset 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa"
841 "checksum memoffset 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa"
770 "checksum micro-timer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2620153e1d903d26b72b89f0e9c48d8c4756cba941c185461dddc234980c298c"
842 "checksum micro-timer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2620153e1d903d26b72b89f0e9c48d8c4756cba941c185461dddc234980c298c"
771 "checksum micro-timer-macros 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e28a3473e6abd6e9aab36aaeef32ad22ae0bd34e79f376643594c2b152ec1c5d"
843 "checksum micro-timer-macros 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e28a3473e6abd6e9aab36aaeef32ad22ae0bd34e79f376643594c2b152ec1c5d"
772 "checksum miniz_oxide 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c60c0dfe32c10b43a144bad8fc83538c52f58302c92300ea7ec7bf7b38d5a7b9"
844 "checksum miniz_oxide 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c60c0dfe32c10b43a144bad8fc83538c52f58302c92300ea7ec7bf7b38d5a7b9"
773 "checksum num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
845 "checksum num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
774 "checksum num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
846 "checksum num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
775 "checksum output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
847 "checksum output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
776 "checksum pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33"
848 "checksum pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33"
777 "checksum ppv-lite86 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20"
849 "checksum ppv-lite86 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20"
778 "checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427"
850 "checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427"
779 "checksum proc-macro2 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c"
851 "checksum proc-macro2 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c"
780 "checksum python27-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "67cb041de8615111bf224dd75667af5f25c6e032118251426fed7f1b70ce4c8c"
852 "checksum python27-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "67cb041de8615111bf224dd75667af5f25c6e032118251426fed7f1b70ce4c8c"
781 "checksum python3-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90af11779515a1e530af60782d273b59ac79d33b0e253c071a728563957c76d4"
853 "checksum python3-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90af11779515a1e530af60782d273b59ac79d33b0e253c071a728563957c76d4"
782 "checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
854 "checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
783 "checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
855 "checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
856 "checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c"
857 "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
784 "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
858 "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
785 "checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
859 "checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
860 "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
861 "checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
786 "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
862 "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
787 "checksum rand_distr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96977acbdd3a6576fb1d27391900035bf3863d4a16422973a409b488cf29ffb2"
863 "checksum rand_distr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96977acbdd3a6576fb1d27391900035bf3863d4a16422973a409b488cf29ffb2"
788 "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
864 "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
789 "checksum rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
865 "checksum rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
790 "checksum rayon 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cfd016f0c045ad38b5251be2c9c0ab806917f82da4d36b2a327e5166adad9270"
866 "checksum rayon 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cfd016f0c045ad38b5251be2c9c0ab806917f82da4d36b2a327e5166adad9270"
791 "checksum rayon-core 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e8c4fec834fb6e6d2dd5eece3c7b432a52f0ba887cf40e595190c4107edc08bf"
867 "checksum rayon-core 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e8c4fec834fb6e6d2dd5eece3c7b432a52f0ba887cf40e595190c4107edc08bf"
868 "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
792 "checksum redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)" = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
869 "checksum redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)" = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
793 "checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6"
870 "checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6"
794 "checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
871 "checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
795 "checksum remove_dir_all 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
872 "checksum remove_dir_all 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
873 "checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a"
874 "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
796 "checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
875 "checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
797 "checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
876 "checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
798 "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
877 "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
799 "checksum syn 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b"
878 "checksum syn 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b"
800 "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
879 "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
801 "checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
880 "checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
802 "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
881 "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
803 "checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
882 "checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
804 "checksum twox-hash 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bfd5b7557925ce778ff9b9ef90e3ade34c524b5ff10e239c69a42d546d2af56"
883 "checksum twox-hash 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bfd5b7557925ce778ff9b9ef90e3ade34c524b5ff10e239c69a42d546d2af56"
805 "checksum unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
884 "checksum unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
806 "checksum unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
885 "checksum unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
807 "checksum vcpkg 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c"
886 "checksum vcpkg 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c"
808 "checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
887 "checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
809 "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
888 "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
810 "checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
889 "checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
811 "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
890 "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
812 "checksum winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
891 "checksum winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
813 "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
892 "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
814 "checksum zstd 0.5.3+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "01b32eaf771efa709e8308605bbf9319bf485dc1503179ec0469b611937c0cd8"
893 "checksum zstd 0.5.3+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "01b32eaf771efa709e8308605bbf9319bf485dc1503179ec0469b611937c0cd8"
815 "checksum zstd-safe 2.0.5+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1cfb642e0d27f64729a639c52db457e0ae906e7bc6f5fe8f5c453230400f1055"
894 "checksum zstd-safe 2.0.5+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1cfb642e0d27f64729a639c52db457e0ae906e7bc6f5fe8f5c453230400f1055"
816 "checksum zstd-sys 1.4.17+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b89249644df056b522696b1bb9e7c18c87e8ffa3e2f0dc3b0155875d6498f01b"
895 "checksum zstd-sys 1.4.17+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b89249644df056b522696b1bb9e7c18c87e8ffa3e2f0dc3b0155875d6498f01b"
@@ -1,41 +1,42 b''
1 [package]
1 [package]
2 name = "hg-core"
2 name = "hg-core"
3 version = "0.1.0"
3 version = "0.1.0"
4 authors = ["Georges Racinet <gracinet@anybox.fr>"]
4 authors = ["Georges Racinet <gracinet@anybox.fr>"]
5 description = "Mercurial pure Rust core library, with no assumption on Python bindings (FFI)"
5 description = "Mercurial pure Rust core library, with no assumption on Python bindings (FFI)"
6 edition = "2018"
6 edition = "2018"
7
7
8 [lib]
8 [lib]
9 name = "hg"
9 name = "hg"
10
10
11 [dependencies]
11 [dependencies]
12 byteorder = "1.3.4"
12 byteorder = "1.3.4"
13 hex = "0.4.2"
13 hex = "0.4.2"
14 lazy_static = "1.4.0"
14 lazy_static = "1.4.0"
15 memchr = "2.3.3"
15 memchr = "2.3.3"
16 rand = "0.7.3"
16 rand = "0.7.3"
17 rand_pcg = "0.2.1"
17 rand_pcg = "0.2.1"
18 rand_distr = "0.2.2"
18 rand_distr = "0.2.2"
19 rayon = "1.3.0"
19 rayon = "1.3.0"
20 regex = "1.3.9"
20 regex = "1.3.9"
21 twox-hash = "1.5.0"
21 twox-hash = "1.5.0"
22 same-file = "1.0.6"
22 same-file = "1.0.6"
23 crossbeam = "0.7.3"
23 crossbeam = "0.7.3"
24 micro-timer = "0.3.0"
24 micro-timer = "0.3.0"
25 log = "0.4.8"
25 log = "0.4.8"
26 memmap = "0.7.0"
26 memmap = "0.7.0"
27 zstd = "0.5.3"
27 zstd = "0.5.3"
28 rust-crypto = "0.2.36"
28
29
29 # We don't use the `miniz-oxide` backend because its minimum Rust version is
30 # We don't use the `miniz-oxide` backend because its minimum Rust version is
30 # `1.36`. However, this PR (https://github.com/Frommi/miniz_oxide/pull/84/files)
31 # `1.36`. However, this PR (https://github.com/Frommi/miniz_oxide/pull/84/files)
31 # introduces a flag `no_extern_crate_alloc` to bring the requirement back down
32 # introduces a flag `no_extern_crate_alloc` to bring the requirement back down
32 # to `1.34`.
33 # to `1.34`.
33 [dependencies.flate2]
34 [dependencies.flate2]
34 version = "1.0.16"
35 version = "1.0.16"
35 features = ["zlib"]
36 features = ["zlib"]
36 default-features = false
37 default-features = false
37
38
38 [dev-dependencies]
39 [dev-dependencies]
39 clap = "*"
40 clap = "*"
40 pretty_assertions = "0.6.1"
41 pretty_assertions = "0.6.1"
41 tempfile = "3.1.0"
42 tempfile = "3.1.0"
@@ -1,503 +1,503 b''
1 // dirstate_map.rs
1 // dirstate_map.rs
2 //
2 //
3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
4 //
4 //
5 // This software may be used and distributed according to the terms of the
5 // This software may be used and distributed according to the terms of the
6 // GNU General Public License version 2 or any later version.
6 // GNU General Public License version 2 or any later version.
7
7
8 use crate::revlog::node::NULL_NODE_ID;
8 use crate::{
9 use crate::{
9 dirstate::{parsers::PARENT_SIZE, EntryState, SIZE_FROM_OTHER_PARENT},
10 dirstate::{parsers::PARENT_SIZE, EntryState, SIZE_FROM_OTHER_PARENT},
10 pack_dirstate, parse_dirstate,
11 pack_dirstate, parse_dirstate,
11 utils::{
12 utils::{
12 files::normalize_case,
13 files::normalize_case,
13 hg_path::{HgPath, HgPathBuf},
14 hg_path::{HgPath, HgPathBuf},
14 },
15 },
15 CopyMap, DirsMultiset, DirstateEntry, DirstateError, DirstateMapError,
16 CopyMap, DirsMultiset, DirstateEntry, DirstateError, DirstateMapError,
16 DirstateParents, DirstateParseError, FastHashMap, StateMap,
17 DirstateParents, DirstateParseError, FastHashMap, StateMap,
17 };
18 };
18 use core::borrow::Borrow;
19 use core::borrow::Borrow;
19 use std::collections::HashSet;
20 use std::collections::HashSet;
20 use std::convert::TryInto;
21 use std::convert::TryInto;
21 use std::iter::FromIterator;
22 use std::iter::FromIterator;
22 use std::ops::Deref;
23 use std::ops::Deref;
23 use std::time::Duration;
24 use std::time::Duration;
24
25
25 pub type FileFoldMap = FastHashMap<HgPathBuf, HgPathBuf>;
26 pub type FileFoldMap = FastHashMap<HgPathBuf, HgPathBuf>;
26
27
27 const NULL_ID: [u8; 20] = [0; 20];
28 const MTIME_UNSET: i32 = -1;
28 const MTIME_UNSET: i32 = -1;
29
29
30 #[derive(Default)]
30 #[derive(Default)]
31 pub struct DirstateMap {
31 pub struct DirstateMap {
32 state_map: StateMap,
32 state_map: StateMap,
33 pub copy_map: CopyMap,
33 pub copy_map: CopyMap,
34 file_fold_map: Option<FileFoldMap>,
34 file_fold_map: Option<FileFoldMap>,
35 pub dirs: Option<DirsMultiset>,
35 pub dirs: Option<DirsMultiset>,
36 pub all_dirs: Option<DirsMultiset>,
36 pub all_dirs: Option<DirsMultiset>,
37 non_normal_set: Option<HashSet<HgPathBuf>>,
37 non_normal_set: Option<HashSet<HgPathBuf>>,
38 other_parent_set: Option<HashSet<HgPathBuf>>,
38 other_parent_set: Option<HashSet<HgPathBuf>>,
39 parents: Option<DirstateParents>,
39 parents: Option<DirstateParents>,
40 dirty_parents: bool,
40 dirty_parents: bool,
41 }
41 }
42
42
43 /// Should only really be used in python interface code, for clarity
43 /// Should only really be used in python interface code, for clarity
44 impl Deref for DirstateMap {
44 impl Deref for DirstateMap {
45 type Target = StateMap;
45 type Target = StateMap;
46
46
47 fn deref(&self) -> &Self::Target {
47 fn deref(&self) -> &Self::Target {
48 &self.state_map
48 &self.state_map
49 }
49 }
50 }
50 }
51
51
52 impl FromIterator<(HgPathBuf, DirstateEntry)> for DirstateMap {
52 impl FromIterator<(HgPathBuf, DirstateEntry)> for DirstateMap {
53 fn from_iter<I: IntoIterator<Item = (HgPathBuf, DirstateEntry)>>(
53 fn from_iter<I: IntoIterator<Item = (HgPathBuf, DirstateEntry)>>(
54 iter: I,
54 iter: I,
55 ) -> Self {
55 ) -> Self {
56 Self {
56 Self {
57 state_map: iter.into_iter().collect(),
57 state_map: iter.into_iter().collect(),
58 ..Self::default()
58 ..Self::default()
59 }
59 }
60 }
60 }
61 }
61 }
62
62
63 impl DirstateMap {
63 impl DirstateMap {
64 pub fn new() -> Self {
64 pub fn new() -> Self {
65 Self::default()
65 Self::default()
66 }
66 }
67
67
68 pub fn clear(&mut self) {
68 pub fn clear(&mut self) {
69 self.state_map.clear();
69 self.state_map.clear();
70 self.copy_map.clear();
70 self.copy_map.clear();
71 self.file_fold_map = None;
71 self.file_fold_map = None;
72 self.non_normal_set = None;
72 self.non_normal_set = None;
73 self.other_parent_set = None;
73 self.other_parent_set = None;
74 self.set_parents(&DirstateParents {
74 self.set_parents(&DirstateParents {
75 p1: NULL_ID,
75 p1: NULL_NODE_ID,
76 p2: NULL_ID,
76 p2: NULL_NODE_ID,
77 })
77 })
78 }
78 }
79
79
80 /// Add a tracked file to the dirstate
80 /// Add a tracked file to the dirstate
81 pub fn add_file(
81 pub fn add_file(
82 &mut self,
82 &mut self,
83 filename: &HgPath,
83 filename: &HgPath,
84 old_state: EntryState,
84 old_state: EntryState,
85 entry: DirstateEntry,
85 entry: DirstateEntry,
86 ) -> Result<(), DirstateMapError> {
86 ) -> Result<(), DirstateMapError> {
87 if old_state == EntryState::Unknown || old_state == EntryState::Removed
87 if old_state == EntryState::Unknown || old_state == EntryState::Removed
88 {
88 {
89 if let Some(ref mut dirs) = self.dirs {
89 if let Some(ref mut dirs) = self.dirs {
90 dirs.add_path(filename)?;
90 dirs.add_path(filename)?;
91 }
91 }
92 }
92 }
93 if old_state == EntryState::Unknown {
93 if old_state == EntryState::Unknown {
94 if let Some(ref mut all_dirs) = self.all_dirs {
94 if let Some(ref mut all_dirs) = self.all_dirs {
95 all_dirs.add_path(filename)?;
95 all_dirs.add_path(filename)?;
96 }
96 }
97 }
97 }
98 self.state_map.insert(filename.to_owned(), entry.to_owned());
98 self.state_map.insert(filename.to_owned(), entry.to_owned());
99
99
100 if entry.state != EntryState::Normal || entry.mtime == MTIME_UNSET {
100 if entry.state != EntryState::Normal || entry.mtime == MTIME_UNSET {
101 self.get_non_normal_other_parent_entries()
101 self.get_non_normal_other_parent_entries()
102 .0
102 .0
103 .insert(filename.to_owned());
103 .insert(filename.to_owned());
104 }
104 }
105
105
106 if entry.size == SIZE_FROM_OTHER_PARENT {
106 if entry.size == SIZE_FROM_OTHER_PARENT {
107 self.get_non_normal_other_parent_entries()
107 self.get_non_normal_other_parent_entries()
108 .1
108 .1
109 .insert(filename.to_owned());
109 .insert(filename.to_owned());
110 }
110 }
111 Ok(())
111 Ok(())
112 }
112 }
113
113
114 /// Mark a file as removed in the dirstate.
114 /// Mark a file as removed in the dirstate.
115 ///
115 ///
116 /// The `size` parameter is used to store sentinel values that indicate
116 /// The `size` parameter is used to store sentinel values that indicate
117 /// the file's previous state. In the future, we should refactor this
117 /// the file's previous state. In the future, we should refactor this
118 /// to be more explicit about what that state is.
118 /// to be more explicit about what that state is.
119 pub fn remove_file(
119 pub fn remove_file(
120 &mut self,
120 &mut self,
121 filename: &HgPath,
121 filename: &HgPath,
122 old_state: EntryState,
122 old_state: EntryState,
123 size: i32,
123 size: i32,
124 ) -> Result<(), DirstateMapError> {
124 ) -> Result<(), DirstateMapError> {
125 if old_state != EntryState::Unknown && old_state != EntryState::Removed
125 if old_state != EntryState::Unknown && old_state != EntryState::Removed
126 {
126 {
127 if let Some(ref mut dirs) = self.dirs {
127 if let Some(ref mut dirs) = self.dirs {
128 dirs.delete_path(filename)?;
128 dirs.delete_path(filename)?;
129 }
129 }
130 }
130 }
131 if old_state == EntryState::Unknown {
131 if old_state == EntryState::Unknown {
132 if let Some(ref mut all_dirs) = self.all_dirs {
132 if let Some(ref mut all_dirs) = self.all_dirs {
133 all_dirs.add_path(filename)?;
133 all_dirs.add_path(filename)?;
134 }
134 }
135 }
135 }
136
136
137 if let Some(ref mut file_fold_map) = self.file_fold_map {
137 if let Some(ref mut file_fold_map) = self.file_fold_map {
138 file_fold_map.remove(&normalize_case(filename));
138 file_fold_map.remove(&normalize_case(filename));
139 }
139 }
140 self.state_map.insert(
140 self.state_map.insert(
141 filename.to_owned(),
141 filename.to_owned(),
142 DirstateEntry {
142 DirstateEntry {
143 state: EntryState::Removed,
143 state: EntryState::Removed,
144 mode: 0,
144 mode: 0,
145 size,
145 size,
146 mtime: 0,
146 mtime: 0,
147 },
147 },
148 );
148 );
149 self.get_non_normal_other_parent_entries()
149 self.get_non_normal_other_parent_entries()
150 .0
150 .0
151 .insert(filename.to_owned());
151 .insert(filename.to_owned());
152 Ok(())
152 Ok(())
153 }
153 }
154
154
155 /// Remove a file from the dirstate.
155 /// Remove a file from the dirstate.
156 /// Returns `true` if the file was previously recorded.
156 /// Returns `true` if the file was previously recorded.
157 pub fn drop_file(
157 pub fn drop_file(
158 &mut self,
158 &mut self,
159 filename: &HgPath,
159 filename: &HgPath,
160 old_state: EntryState,
160 old_state: EntryState,
161 ) -> Result<bool, DirstateMapError> {
161 ) -> Result<bool, DirstateMapError> {
162 let exists = self.state_map.remove(filename).is_some();
162 let exists = self.state_map.remove(filename).is_some();
163
163
164 if exists {
164 if exists {
165 if old_state != EntryState::Removed {
165 if old_state != EntryState::Removed {
166 if let Some(ref mut dirs) = self.dirs {
166 if let Some(ref mut dirs) = self.dirs {
167 dirs.delete_path(filename)?;
167 dirs.delete_path(filename)?;
168 }
168 }
169 }
169 }
170 if let Some(ref mut all_dirs) = self.all_dirs {
170 if let Some(ref mut all_dirs) = self.all_dirs {
171 all_dirs.delete_path(filename)?;
171 all_dirs.delete_path(filename)?;
172 }
172 }
173 }
173 }
174 if let Some(ref mut file_fold_map) = self.file_fold_map {
174 if let Some(ref mut file_fold_map) = self.file_fold_map {
175 file_fold_map.remove(&normalize_case(filename));
175 file_fold_map.remove(&normalize_case(filename));
176 }
176 }
177 self.get_non_normal_other_parent_entries()
177 self.get_non_normal_other_parent_entries()
178 .0
178 .0
179 .remove(filename);
179 .remove(filename);
180
180
181 Ok(exists)
181 Ok(exists)
182 }
182 }
183
183
184 pub fn clear_ambiguous_times(
184 pub fn clear_ambiguous_times(
185 &mut self,
185 &mut self,
186 filenames: Vec<HgPathBuf>,
186 filenames: Vec<HgPathBuf>,
187 now: i32,
187 now: i32,
188 ) {
188 ) {
189 for filename in filenames {
189 for filename in filenames {
190 let mut changed = false;
190 let mut changed = false;
191 self.state_map
191 self.state_map
192 .entry(filename.to_owned())
192 .entry(filename.to_owned())
193 .and_modify(|entry| {
193 .and_modify(|entry| {
194 if entry.state == EntryState::Normal && entry.mtime == now
194 if entry.state == EntryState::Normal && entry.mtime == now
195 {
195 {
196 changed = true;
196 changed = true;
197 *entry = DirstateEntry {
197 *entry = DirstateEntry {
198 mtime: MTIME_UNSET,
198 mtime: MTIME_UNSET,
199 ..*entry
199 ..*entry
200 };
200 };
201 }
201 }
202 });
202 });
203 if changed {
203 if changed {
204 self.get_non_normal_other_parent_entries()
204 self.get_non_normal_other_parent_entries()
205 .0
205 .0
206 .insert(filename.to_owned());
206 .insert(filename.to_owned());
207 }
207 }
208 }
208 }
209 }
209 }
210
210
211 pub fn non_normal_entries_remove(
211 pub fn non_normal_entries_remove(
212 &mut self,
212 &mut self,
213 key: impl AsRef<HgPath>,
213 key: impl AsRef<HgPath>,
214 ) -> bool {
214 ) -> bool {
215 self.get_non_normal_other_parent_entries()
215 self.get_non_normal_other_parent_entries()
216 .0
216 .0
217 .remove(key.as_ref())
217 .remove(key.as_ref())
218 }
218 }
219 pub fn non_normal_entries_union(
219 pub fn non_normal_entries_union(
220 &mut self,
220 &mut self,
221 other: HashSet<HgPathBuf>,
221 other: HashSet<HgPathBuf>,
222 ) -> Vec<HgPathBuf> {
222 ) -> Vec<HgPathBuf> {
223 self.get_non_normal_other_parent_entries()
223 self.get_non_normal_other_parent_entries()
224 .0
224 .0
225 .union(&other)
225 .union(&other)
226 .map(ToOwned::to_owned)
226 .map(ToOwned::to_owned)
227 .collect()
227 .collect()
228 }
228 }
229
229
230 pub fn get_non_normal_other_parent_entries(
230 pub fn get_non_normal_other_parent_entries(
231 &mut self,
231 &mut self,
232 ) -> (&mut HashSet<HgPathBuf>, &mut HashSet<HgPathBuf>) {
232 ) -> (&mut HashSet<HgPathBuf>, &mut HashSet<HgPathBuf>) {
233 self.set_non_normal_other_parent_entries(false);
233 self.set_non_normal_other_parent_entries(false);
234 (
234 (
235 self.non_normal_set.as_mut().unwrap(),
235 self.non_normal_set.as_mut().unwrap(),
236 self.other_parent_set.as_mut().unwrap(),
236 self.other_parent_set.as_mut().unwrap(),
237 )
237 )
238 }
238 }
239
239
240 /// Useful to get immutable references to those sets in contexts where
240 /// Useful to get immutable references to those sets in contexts where
241 /// you only have an immutable reference to the `DirstateMap`, like when
241 /// you only have an immutable reference to the `DirstateMap`, like when
242 /// sharing references with Python.
242 /// sharing references with Python.
243 ///
243 ///
244 /// TODO, get rid of this along with the other "setter/getter" stuff when
244 /// TODO, get rid of this along with the other "setter/getter" stuff when
245 /// a nice typestate plan is defined.
245 /// a nice typestate plan is defined.
246 ///
246 ///
247 /// # Panics
247 /// # Panics
248 ///
248 ///
249 /// Will panic if either set is `None`.
249 /// Will panic if either set is `None`.
250 pub fn get_non_normal_other_parent_entries_panic(
250 pub fn get_non_normal_other_parent_entries_panic(
251 &self,
251 &self,
252 ) -> (&HashSet<HgPathBuf>, &HashSet<HgPathBuf>) {
252 ) -> (&HashSet<HgPathBuf>, &HashSet<HgPathBuf>) {
253 (
253 (
254 self.non_normal_set.as_ref().unwrap(),
254 self.non_normal_set.as_ref().unwrap(),
255 self.other_parent_set.as_ref().unwrap(),
255 self.other_parent_set.as_ref().unwrap(),
256 )
256 )
257 }
257 }
258
258
259 pub fn set_non_normal_other_parent_entries(&mut self, force: bool) {
259 pub fn set_non_normal_other_parent_entries(&mut self, force: bool) {
260 if !force
260 if !force
261 && self.non_normal_set.is_some()
261 && self.non_normal_set.is_some()
262 && self.other_parent_set.is_some()
262 && self.other_parent_set.is_some()
263 {
263 {
264 return;
264 return;
265 }
265 }
266 let mut non_normal = HashSet::new();
266 let mut non_normal = HashSet::new();
267 let mut other_parent = HashSet::new();
267 let mut other_parent = HashSet::new();
268
268
269 for (
269 for (
270 filename,
270 filename,
271 DirstateEntry {
271 DirstateEntry {
272 state, size, mtime, ..
272 state, size, mtime, ..
273 },
273 },
274 ) in self.state_map.iter()
274 ) in self.state_map.iter()
275 {
275 {
276 if *state != EntryState::Normal || *mtime == MTIME_UNSET {
276 if *state != EntryState::Normal || *mtime == MTIME_UNSET {
277 non_normal.insert(filename.to_owned());
277 non_normal.insert(filename.to_owned());
278 }
278 }
279 if *state == EntryState::Normal && *size == SIZE_FROM_OTHER_PARENT
279 if *state == EntryState::Normal && *size == SIZE_FROM_OTHER_PARENT
280 {
280 {
281 other_parent.insert(filename.to_owned());
281 other_parent.insert(filename.to_owned());
282 }
282 }
283 }
283 }
284 self.non_normal_set = Some(non_normal);
284 self.non_normal_set = Some(non_normal);
285 self.other_parent_set = Some(other_parent);
285 self.other_parent_set = Some(other_parent);
286 }
286 }
287
287
288 /// Both of these setters and their uses appear to be the simplest way to
288 /// Both of these setters and their uses appear to be the simplest way to
289 /// emulate a Python lazy property, but it is ugly and unidiomatic.
289 /// emulate a Python lazy property, but it is ugly and unidiomatic.
290 /// TODO One day, rewriting this struct using the typestate might be a
290 /// TODO One day, rewriting this struct using the typestate might be a
291 /// good idea.
291 /// good idea.
292 pub fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
292 pub fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
293 if self.all_dirs.is_none() {
293 if self.all_dirs.is_none() {
294 self.all_dirs =
294 self.all_dirs =
295 Some(DirsMultiset::from_dirstate(&self.state_map, None)?);
295 Some(DirsMultiset::from_dirstate(&self.state_map, None)?);
296 }
296 }
297 Ok(())
297 Ok(())
298 }
298 }
299
299
300 pub fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
300 pub fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
301 if self.dirs.is_none() {
301 if self.dirs.is_none() {
302 self.dirs = Some(DirsMultiset::from_dirstate(
302 self.dirs = Some(DirsMultiset::from_dirstate(
303 &self.state_map,
303 &self.state_map,
304 Some(EntryState::Removed),
304 Some(EntryState::Removed),
305 )?);
305 )?);
306 }
306 }
307 Ok(())
307 Ok(())
308 }
308 }
309
309
310 pub fn has_tracked_dir(
310 pub fn has_tracked_dir(
311 &mut self,
311 &mut self,
312 directory: &HgPath,
312 directory: &HgPath,
313 ) -> Result<bool, DirstateMapError> {
313 ) -> Result<bool, DirstateMapError> {
314 self.set_dirs()?;
314 self.set_dirs()?;
315 Ok(self.dirs.as_ref().unwrap().contains(directory))
315 Ok(self.dirs.as_ref().unwrap().contains(directory))
316 }
316 }
317
317
318 pub fn has_dir(
318 pub fn has_dir(
319 &mut self,
319 &mut self,
320 directory: &HgPath,
320 directory: &HgPath,
321 ) -> Result<bool, DirstateMapError> {
321 ) -> Result<bool, DirstateMapError> {
322 self.set_all_dirs()?;
322 self.set_all_dirs()?;
323 Ok(self.all_dirs.as_ref().unwrap().contains(directory))
323 Ok(self.all_dirs.as_ref().unwrap().contains(directory))
324 }
324 }
325
325
326 pub fn parents(
326 pub fn parents(
327 &mut self,
327 &mut self,
328 file_contents: &[u8],
328 file_contents: &[u8],
329 ) -> Result<&DirstateParents, DirstateError> {
329 ) -> Result<&DirstateParents, DirstateError> {
330 if let Some(ref parents) = self.parents {
330 if let Some(ref parents) = self.parents {
331 return Ok(parents);
331 return Ok(parents);
332 }
332 }
333 let parents;
333 let parents;
334 if file_contents.len() == PARENT_SIZE * 2 {
334 if file_contents.len() == PARENT_SIZE * 2 {
335 parents = DirstateParents {
335 parents = DirstateParents {
336 p1: file_contents[..PARENT_SIZE].try_into().unwrap(),
336 p1: file_contents[..PARENT_SIZE].try_into().unwrap(),
337 p2: file_contents[PARENT_SIZE..PARENT_SIZE * 2]
337 p2: file_contents[PARENT_SIZE..PARENT_SIZE * 2]
338 .try_into()
338 .try_into()
339 .unwrap(),
339 .unwrap(),
340 };
340 };
341 } else if file_contents.is_empty() {
341 } else if file_contents.is_empty() {
342 parents = DirstateParents {
342 parents = DirstateParents {
343 p1: NULL_ID,
343 p1: NULL_NODE_ID,
344 p2: NULL_ID,
344 p2: NULL_NODE_ID,
345 };
345 };
346 } else {
346 } else {
347 return Err(DirstateError::Parse(DirstateParseError::Damaged));
347 return Err(DirstateError::Parse(DirstateParseError::Damaged));
348 }
348 }
349
349
350 self.parents = Some(parents);
350 self.parents = Some(parents);
351 Ok(self.parents.as_ref().unwrap())
351 Ok(self.parents.as_ref().unwrap())
352 }
352 }
353
353
354 pub fn set_parents(&mut self, parents: &DirstateParents) {
354 pub fn set_parents(&mut self, parents: &DirstateParents) {
355 self.parents = Some(parents.clone());
355 self.parents = Some(parents.clone());
356 self.dirty_parents = true;
356 self.dirty_parents = true;
357 }
357 }
358
358
359 pub fn read(
359 pub fn read(
360 &mut self,
360 &mut self,
361 file_contents: &[u8],
361 file_contents: &[u8],
362 ) -> Result<Option<DirstateParents>, DirstateError> {
362 ) -> Result<Option<DirstateParents>, DirstateError> {
363 if file_contents.is_empty() {
363 if file_contents.is_empty() {
364 return Ok(None);
364 return Ok(None);
365 }
365 }
366
366
367 let (parents, entries, copies) = parse_dirstate(file_contents)?;
367 let (parents, entries, copies) = parse_dirstate(file_contents)?;
368 self.state_map.extend(
368 self.state_map.extend(
369 entries
369 entries
370 .into_iter()
370 .into_iter()
371 .map(|(path, entry)| (path.to_owned(), entry)),
371 .map(|(path, entry)| (path.to_owned(), entry)),
372 );
372 );
373 self.copy_map.extend(
373 self.copy_map.extend(
374 copies
374 copies
375 .into_iter()
375 .into_iter()
376 .map(|(path, copy)| (path.to_owned(), copy.to_owned())),
376 .map(|(path, copy)| (path.to_owned(), copy.to_owned())),
377 );
377 );
378
378
379 if !self.dirty_parents {
379 if !self.dirty_parents {
380 self.set_parents(&parents);
380 self.set_parents(&parents);
381 }
381 }
382
382
383 Ok(Some(parents))
383 Ok(Some(parents))
384 }
384 }
385
385
386 pub fn pack(
386 pub fn pack(
387 &mut self,
387 &mut self,
388 parents: DirstateParents,
388 parents: DirstateParents,
389 now: Duration,
389 now: Duration,
390 ) -> Result<Vec<u8>, DirstateError> {
390 ) -> Result<Vec<u8>, DirstateError> {
391 let packed =
391 let packed =
392 pack_dirstate(&mut self.state_map, &self.copy_map, parents, now)?;
392 pack_dirstate(&mut self.state_map, &self.copy_map, parents, now)?;
393
393
394 self.dirty_parents = false;
394 self.dirty_parents = false;
395
395
396 self.set_non_normal_other_parent_entries(true);
396 self.set_non_normal_other_parent_entries(true);
397 Ok(packed)
397 Ok(packed)
398 }
398 }
399
399
400 pub fn build_file_fold_map(&mut self) -> &FileFoldMap {
400 pub fn build_file_fold_map(&mut self) -> &FileFoldMap {
401 if let Some(ref file_fold_map) = self.file_fold_map {
401 if let Some(ref file_fold_map) = self.file_fold_map {
402 return file_fold_map;
402 return file_fold_map;
403 }
403 }
404 let mut new_file_fold_map = FileFoldMap::default();
404 let mut new_file_fold_map = FileFoldMap::default();
405 for (filename, DirstateEntry { state, .. }) in self.state_map.borrow()
405 for (filename, DirstateEntry { state, .. }) in self.state_map.borrow()
406 {
406 {
407 if *state == EntryState::Removed {
407 if *state == EntryState::Removed {
408 new_file_fold_map
408 new_file_fold_map
409 .insert(normalize_case(filename), filename.to_owned());
409 .insert(normalize_case(filename), filename.to_owned());
410 }
410 }
411 }
411 }
412 self.file_fold_map = Some(new_file_fold_map);
412 self.file_fold_map = Some(new_file_fold_map);
413 self.file_fold_map.as_ref().unwrap()
413 self.file_fold_map.as_ref().unwrap()
414 }
414 }
415 }
415 }
416
416
417 #[cfg(test)]
417 #[cfg(test)]
418 mod tests {
418 mod tests {
419 use super::*;
419 use super::*;
420
420
421 #[test]
421 #[test]
422 fn test_dirs_multiset() {
422 fn test_dirs_multiset() {
423 let mut map = DirstateMap::new();
423 let mut map = DirstateMap::new();
424 assert!(map.dirs.is_none());
424 assert!(map.dirs.is_none());
425 assert!(map.all_dirs.is_none());
425 assert!(map.all_dirs.is_none());
426
426
427 assert_eq!(map.has_dir(HgPath::new(b"nope")).unwrap(), false);
427 assert_eq!(map.has_dir(HgPath::new(b"nope")).unwrap(), false);
428 assert!(map.all_dirs.is_some());
428 assert!(map.all_dirs.is_some());
429 assert!(map.dirs.is_none());
429 assert!(map.dirs.is_none());
430
430
431 assert_eq!(map.has_tracked_dir(HgPath::new(b"nope")).unwrap(), false);
431 assert_eq!(map.has_tracked_dir(HgPath::new(b"nope")).unwrap(), false);
432 assert!(map.dirs.is_some());
432 assert!(map.dirs.is_some());
433 }
433 }
434
434
435 #[test]
435 #[test]
436 fn test_add_file() {
436 fn test_add_file() {
437 let mut map = DirstateMap::new();
437 let mut map = DirstateMap::new();
438
438
439 assert_eq!(0, map.len());
439 assert_eq!(0, map.len());
440
440
441 map.add_file(
441 map.add_file(
442 HgPath::new(b"meh"),
442 HgPath::new(b"meh"),
443 EntryState::Normal,
443 EntryState::Normal,
444 DirstateEntry {
444 DirstateEntry {
445 state: EntryState::Normal,
445 state: EntryState::Normal,
446 mode: 1337,
446 mode: 1337,
447 mtime: 1337,
447 mtime: 1337,
448 size: 1337,
448 size: 1337,
449 },
449 },
450 )
450 )
451 .unwrap();
451 .unwrap();
452
452
453 assert_eq!(1, map.len());
453 assert_eq!(1, map.len());
454 assert_eq!(0, map.get_non_normal_other_parent_entries().0.len());
454 assert_eq!(0, map.get_non_normal_other_parent_entries().0.len());
455 assert_eq!(0, map.get_non_normal_other_parent_entries().1.len());
455 assert_eq!(0, map.get_non_normal_other_parent_entries().1.len());
456 }
456 }
457
457
458 #[test]
458 #[test]
459 fn test_non_normal_other_parent_entries() {
459 fn test_non_normal_other_parent_entries() {
460 let mut map: DirstateMap = [
460 let mut map: DirstateMap = [
461 (b"f1", (EntryState::Removed, 1337, 1337, 1337)),
461 (b"f1", (EntryState::Removed, 1337, 1337, 1337)),
462 (b"f2", (EntryState::Normal, 1337, 1337, -1)),
462 (b"f2", (EntryState::Normal, 1337, 1337, -1)),
463 (b"f3", (EntryState::Normal, 1337, 1337, 1337)),
463 (b"f3", (EntryState::Normal, 1337, 1337, 1337)),
464 (b"f4", (EntryState::Normal, 1337, -2, 1337)),
464 (b"f4", (EntryState::Normal, 1337, -2, 1337)),
465 (b"f5", (EntryState::Added, 1337, 1337, 1337)),
465 (b"f5", (EntryState::Added, 1337, 1337, 1337)),
466 (b"f6", (EntryState::Added, 1337, 1337, -1)),
466 (b"f6", (EntryState::Added, 1337, 1337, -1)),
467 (b"f7", (EntryState::Merged, 1337, 1337, -1)),
467 (b"f7", (EntryState::Merged, 1337, 1337, -1)),
468 (b"f8", (EntryState::Merged, 1337, 1337, 1337)),
468 (b"f8", (EntryState::Merged, 1337, 1337, 1337)),
469 (b"f9", (EntryState::Merged, 1337, -2, 1337)),
469 (b"f9", (EntryState::Merged, 1337, -2, 1337)),
470 (b"fa", (EntryState::Added, 1337, -2, 1337)),
470 (b"fa", (EntryState::Added, 1337, -2, 1337)),
471 (b"fb", (EntryState::Removed, 1337, -2, 1337)),
471 (b"fb", (EntryState::Removed, 1337, -2, 1337)),
472 ]
472 ]
473 .iter()
473 .iter()
474 .map(|(fname, (state, mode, size, mtime))| {
474 .map(|(fname, (state, mode, size, mtime))| {
475 (
475 (
476 HgPathBuf::from_bytes(fname.as_ref()),
476 HgPathBuf::from_bytes(fname.as_ref()),
477 DirstateEntry {
477 DirstateEntry {
478 state: *state,
478 state: *state,
479 mode: *mode,
479 mode: *mode,
480 size: *size,
480 size: *size,
481 mtime: *mtime,
481 mtime: *mtime,
482 },
482 },
483 )
483 )
484 })
484 })
485 .collect();
485 .collect();
486
486
487 let mut non_normal = [
487 let mut non_normal = [
488 b"f1", b"f2", b"f5", b"f6", b"f7", b"f8", b"f9", b"fa", b"fb",
488 b"f1", b"f2", b"f5", b"f6", b"f7", b"f8", b"f9", b"fa", b"fb",
489 ]
489 ]
490 .iter()
490 .iter()
491 .map(|x| HgPathBuf::from_bytes(x.as_ref()))
491 .map(|x| HgPathBuf::from_bytes(x.as_ref()))
492 .collect();
492 .collect();
493
493
494 let mut other_parent = HashSet::new();
494 let mut other_parent = HashSet::new();
495 other_parent.insert(HgPathBuf::from_bytes(b"f4"));
495 other_parent.insert(HgPathBuf::from_bytes(b"f4"));
496 let entries = map.get_non_normal_other_parent_entries();
496 let entries = map.get_non_normal_other_parent_entries();
497
497
498 assert_eq!(
498 assert_eq!(
499 (&mut non_normal, &mut other_parent),
499 (&mut non_normal, &mut other_parent),
500 (entries.0, entries.1)
500 (entries.0, entries.1)
501 );
501 );
502 }
502 }
503 }
503 }
@@ -1,299 +1,316 b''
1 use byteorder::{BigEndian, ByteOrder};
2
1 use crate::revlog::{Revision, NULL_REVISION};
3 use crate::revlog::{Revision, NULL_REVISION};
2 use byteorder::{BigEndian, ByteOrder};
3
4
4 pub const INDEX_ENTRY_SIZE: usize = 64;
5 pub const INDEX_ENTRY_SIZE: usize = 64;
5
6
6 /// A Revlog index
7 /// A Revlog index
7 #[derive(Debug)]
8 #[derive(Debug)]
8 pub struct Index<'a> {
9 pub struct Index<'a> {
9 bytes: &'a [u8],
10 bytes: &'a [u8],
10 /// Offsets of starts of index blocks.
11 /// Offsets of starts of index blocks.
11 /// Only needed when the index is interleaved with data.
12 /// Only needed when the index is interleaved with data.
12 offsets: Option<Vec<usize>>,
13 offsets: Option<Vec<usize>>,
13 }
14 }
14
15
15 impl<'a> Index<'a> {
16 impl<'a> Index<'a> {
16 /// Create an index from bytes.
17 /// Create an index from bytes.
17 /// Calculate the start of each entry when is_inline is true.
18 /// Calculate the start of each entry when is_inline is true.
18 pub fn new(bytes: &'a [u8], is_inline: bool) -> Self {
19 pub fn new(bytes: &'a [u8], is_inline: bool) -> Self {
19 if is_inline {
20 if is_inline {
20 let mut offset: usize = 0;
21 let mut offset: usize = 0;
21 let mut offsets = Vec::new();
22 let mut offsets = Vec::new();
22
23
23 while (bytes.len() - offset) >= INDEX_ENTRY_SIZE {
24 while (bytes.len() - offset) >= INDEX_ENTRY_SIZE {
24 offsets.push(offset);
25 offsets.push(offset);
25 let end = offset + INDEX_ENTRY_SIZE;
26 let end = offset + INDEX_ENTRY_SIZE;
26 let entry = IndexEntry {
27 let entry = IndexEntry {
27 bytes: &bytes[offset..end],
28 bytes: &bytes[offset..end],
28 offset_override: None,
29 offset_override: None,
29 };
30 };
30
31
31 offset += INDEX_ENTRY_SIZE + entry.compressed_len();
32 offset += INDEX_ENTRY_SIZE + entry.compressed_len();
32 }
33 }
33
34
34 Self {
35 Self {
35 bytes,
36 bytes,
36 offsets: Some(offsets),
37 offsets: Some(offsets),
37 }
38 }
38 } else {
39 } else {
39 Self {
40 Self {
40 bytes,
41 bytes,
41 offsets: None,
42 offsets: None,
42 }
43 }
43 }
44 }
44 }
45 }
45
46
46 /// Return the index entry corresponding to the given revision if it
47 /// Return the index entry corresponding to the given revision if it
47 /// exists.
48 /// exists.
48 pub fn get_entry(&self, rev: Revision) -> Option<IndexEntry> {
49 pub fn get_entry(&self, rev: Revision) -> Option<IndexEntry> {
49 if rev == NULL_REVISION {
50 if rev == NULL_REVISION {
50 return None;
51 return None;
51 }
52 }
52 if let Some(offsets) = &self.offsets {
53 if let Some(offsets) = &self.offsets {
53 self.get_entry_inline(rev, offsets)
54 self.get_entry_inline(rev, offsets)
54 } else {
55 } else {
55 self.get_entry_separated(rev)
56 self.get_entry_separated(rev)
56 }
57 }
57 }
58 }
58
59
59 fn get_entry_inline(
60 fn get_entry_inline(
60 &self,
61 &self,
61 rev: Revision,
62 rev: Revision,
62 offsets: &[usize],
63 offsets: &[usize],
63 ) -> Option<IndexEntry> {
64 ) -> Option<IndexEntry> {
64 let start = *offsets.get(rev as usize)?;
65 let start = *offsets.get(rev as usize)?;
65 let end = start.checked_add(INDEX_ENTRY_SIZE)?;
66 let end = start.checked_add(INDEX_ENTRY_SIZE)?;
66 let bytes = &self.bytes[start..end];
67 let bytes = &self.bytes[start..end];
67
68
68 // See IndexEntry for an explanation of this override.
69 // See IndexEntry for an explanation of this override.
69 let offset_override = Some(end);
70 let offset_override = Some(end);
70
71
71 Some(IndexEntry {
72 Some(IndexEntry {
72 bytes,
73 bytes,
73 offset_override,
74 offset_override,
74 })
75 })
75 }
76 }
76
77
77 fn get_entry_separated(&self, rev: Revision) -> Option<IndexEntry> {
78 fn get_entry_separated(&self, rev: Revision) -> Option<IndexEntry> {
78 let max_rev = self.bytes.len() / INDEX_ENTRY_SIZE;
79 let max_rev = self.bytes.len() / INDEX_ENTRY_SIZE;
79 if rev as usize >= max_rev {
80 if rev as usize >= max_rev {
80 return None;
81 return None;
81 }
82 }
82 let start = rev as usize * INDEX_ENTRY_SIZE;
83 let start = rev as usize * INDEX_ENTRY_SIZE;
83 let end = start + INDEX_ENTRY_SIZE;
84 let end = start + INDEX_ENTRY_SIZE;
84 let bytes = &self.bytes[start..end];
85 let bytes = &self.bytes[start..end];
85
86
86 // See IndexEntry for an explanation of this override.
87 // See IndexEntry for an explanation of this override.
87 let offset_override = match rev {
88 let offset_override = match rev {
88 0 => Some(0),
89 0 => Some(0),
89 _ => None,
90 _ => None,
90 };
91 };
91
92
92 Some(IndexEntry {
93 Some(IndexEntry {
93 bytes,
94 bytes,
94 offset_override,
95 offset_override,
95 })
96 })
96 }
97 }
97 }
98 }
98
99
99 #[derive(Debug)]
100 #[derive(Debug)]
100 pub struct IndexEntry<'a> {
101 pub struct IndexEntry<'a> {
101 bytes: &'a [u8],
102 bytes: &'a [u8],
102 /// Allows to override the offset value of the entry.
103 /// Allows to override the offset value of the entry.
103 ///
104 ///
104 /// For interleaved index and data, the offset stored in the index
105 /// For interleaved index and data, the offset stored in the index
105 /// corresponds to the separated data offset.
106 /// corresponds to the separated data offset.
106 /// It has to be overridden with the actual offset in the interleaved
107 /// It has to be overridden with the actual offset in the interleaved
107 /// index which is just after the index block.
108 /// index which is just after the index block.
108 ///
109 ///
109 /// For separated index and data, the offset stored in the first index
110 /// For separated index and data, the offset stored in the first index
110 /// entry is mixed with the index headers.
111 /// entry is mixed with the index headers.
111 /// It has to be overridden with 0.
112 /// It has to be overridden with 0.
112 offset_override: Option<usize>,
113 offset_override: Option<usize>,
113 }
114 }
114
115
115 impl<'a> IndexEntry<'a> {
116 impl<'a> IndexEntry<'a> {
116 /// Return the offset of the data if not overridden by offset_override.
117 /// Return the offset of the data if not overridden by offset_override.
117 pub fn offset(&self) -> usize {
118 pub fn offset(&self) -> usize {
118 if let Some(offset_override) = self.offset_override {
119 if let Some(offset_override) = self.offset_override {
119 offset_override
120 offset_override
120 } else {
121 } else {
121 let mut bytes = [0; 8];
122 let mut bytes = [0; 8];
122 bytes[2..8].copy_from_slice(&self.bytes[0..=5]);
123 bytes[2..8].copy_from_slice(&self.bytes[0..=5]);
123 BigEndian::read_u64(&bytes[..]) as usize
124 BigEndian::read_u64(&bytes[..]) as usize
124 }
125 }
125 }
126 }
126
127
127 /// Return the compressed length of the data.
128 /// Return the compressed length of the data.
128 pub fn compressed_len(&self) -> usize {
129 pub fn compressed_len(&self) -> usize {
129 BigEndian::read_u32(&self.bytes[8..=11]) as usize
130 BigEndian::read_u32(&self.bytes[8..=11]) as usize
130 }
131 }
131
132
132 /// Return the uncompressed length of the data.
133 /// Return the uncompressed length of the data.
133 pub fn uncompressed_len(&self) -> usize {
134 pub fn uncompressed_len(&self) -> usize {
134 BigEndian::read_u32(&self.bytes[12..=15]) as usize
135 BigEndian::read_u32(&self.bytes[12..=15]) as usize
135 }
136 }
136
137
137 /// Return the revision upon which the data has been derived.
138 /// Return the revision upon which the data has been derived.
138 pub fn base_revision(&self) -> Revision {
139 pub fn base_revision(&self) -> Revision {
139 // TODO Maybe return an Option when base_revision == rev?
140 // TODO Maybe return an Option when base_revision == rev?
140 // Requires to add rev to IndexEntry
141 // Requires to add rev to IndexEntry
141
142
142 BigEndian::read_i32(&self.bytes[16..])
143 BigEndian::read_i32(&self.bytes[16..])
143 }
144 }
145
146 pub fn p1(&self) -> Revision {
147 BigEndian::read_i32(&self.bytes[24..])
148 }
149
150 pub fn p2(&self) -> Revision {
151 BigEndian::read_i32(&self.bytes[28..])
152 }
153
154 /// Return the hash of revision's full text.
155 ///
156 /// Currently, SHA-1 is used and only the first 20 bytes of this field
157 /// are used.
158 pub fn hash(&self) -> &[u8] {
159 &self.bytes[32..52]
160 }
144 }
161 }
145
162
146 #[cfg(test)]
163 #[cfg(test)]
147 mod tests {
164 mod tests {
148 use super::*;
165 use super::*;
149
166
150 #[cfg(test)]
167 #[cfg(test)]
151 #[derive(Debug, Copy, Clone)]
168 #[derive(Debug, Copy, Clone)]
152 pub struct IndexEntryBuilder {
169 pub struct IndexEntryBuilder {
153 is_first: bool,
170 is_first: bool,
154 is_inline: bool,
171 is_inline: bool,
155 is_general_delta: bool,
172 is_general_delta: bool,
156 version: u16,
173 version: u16,
157 offset: usize,
174 offset: usize,
158 compressed_len: usize,
175 compressed_len: usize,
159 uncompressed_len: usize,
176 uncompressed_len: usize,
160 base_revision: Revision,
177 base_revision: Revision,
161 }
178 }
162
179
163 #[cfg(test)]
180 #[cfg(test)]
164 impl IndexEntryBuilder {
181 impl IndexEntryBuilder {
165 pub fn new() -> Self {
182 pub fn new() -> Self {
166 Self {
183 Self {
167 is_first: false,
184 is_first: false,
168 is_inline: false,
185 is_inline: false,
169 is_general_delta: true,
186 is_general_delta: true,
170 version: 2,
187 version: 2,
171 offset: 0,
188 offset: 0,
172 compressed_len: 0,
189 compressed_len: 0,
173 uncompressed_len: 0,
190 uncompressed_len: 0,
174 base_revision: 0,
191 base_revision: 0,
175 }
192 }
176 }
193 }
177
194
178 pub fn is_first(&mut self, value: bool) -> &mut Self {
195 pub fn is_first(&mut self, value: bool) -> &mut Self {
179 self.is_first = value;
196 self.is_first = value;
180 self
197 self
181 }
198 }
182
199
183 pub fn with_inline(&mut self, value: bool) -> &mut Self {
200 pub fn with_inline(&mut self, value: bool) -> &mut Self {
184 self.is_inline = value;
201 self.is_inline = value;
185 self
202 self
186 }
203 }
187
204
188 pub fn with_general_delta(&mut self, value: bool) -> &mut Self {
205 pub fn with_general_delta(&mut self, value: bool) -> &mut Self {
189 self.is_general_delta = value;
206 self.is_general_delta = value;
190 self
207 self
191 }
208 }
192
209
193 pub fn with_version(&mut self, value: u16) -> &mut Self {
210 pub fn with_version(&mut self, value: u16) -> &mut Self {
194 self.version = value;
211 self.version = value;
195 self
212 self
196 }
213 }
197
214
198 pub fn with_offset(&mut self, value: usize) -> &mut Self {
215 pub fn with_offset(&mut self, value: usize) -> &mut Self {
199 self.offset = value;
216 self.offset = value;
200 self
217 self
201 }
218 }
202
219
203 pub fn with_compressed_len(&mut self, value: usize) -> &mut Self {
220 pub fn with_compressed_len(&mut self, value: usize) -> &mut Self {
204 self.compressed_len = value;
221 self.compressed_len = value;
205 self
222 self
206 }
223 }
207
224
208 pub fn with_uncompressed_len(&mut self, value: usize) -> &mut Self {
225 pub fn with_uncompressed_len(&mut self, value: usize) -> &mut Self {
209 self.uncompressed_len = value;
226 self.uncompressed_len = value;
210 self
227 self
211 }
228 }
212
229
213 pub fn with_base_revision(&mut self, value: Revision) -> &mut Self {
230 pub fn with_base_revision(&mut self, value: Revision) -> &mut Self {
214 self.base_revision = value;
231 self.base_revision = value;
215 self
232 self
216 }
233 }
217
234
218 pub fn build(&self) -> Vec<u8> {
235 pub fn build(&self) -> Vec<u8> {
219 let mut bytes = Vec::with_capacity(INDEX_ENTRY_SIZE);
236 let mut bytes = Vec::with_capacity(INDEX_ENTRY_SIZE);
220 if self.is_first {
237 if self.is_first {
221 bytes.extend(&match (self.is_general_delta, self.is_inline) {
238 bytes.extend(&match (self.is_general_delta, self.is_inline) {
222 (false, false) => [0u8, 0],
239 (false, false) => [0u8, 0],
223 (false, true) => [0u8, 1],
240 (false, true) => [0u8, 1],
224 (true, false) => [0u8, 2],
241 (true, false) => [0u8, 2],
225 (true, true) => [0u8, 3],
242 (true, true) => [0u8, 3],
226 });
243 });
227 bytes.extend(&self.version.to_be_bytes());
244 bytes.extend(&self.version.to_be_bytes());
228 // Remaining offset bytes.
245 // Remaining offset bytes.
229 bytes.extend(&[0u8; 2]);
246 bytes.extend(&[0u8; 2]);
230 } else {
247 } else {
231 // Offset is only 6 bytes will usize is 8.
248 // Offset is only 6 bytes will usize is 8.
232 bytes.extend(&self.offset.to_be_bytes()[2..]);
249 bytes.extend(&self.offset.to_be_bytes()[2..]);
233 }
250 }
234 bytes.extend(&[0u8; 2]); // Revision flags.
251 bytes.extend(&[0u8; 2]); // Revision flags.
235 bytes.extend(&self.compressed_len.to_be_bytes()[4..]);
252 bytes.extend(&self.compressed_len.to_be_bytes()[4..]);
236 bytes.extend(&self.uncompressed_len.to_be_bytes()[4..]);
253 bytes.extend(&self.uncompressed_len.to_be_bytes()[4..]);
237 bytes.extend(&self.base_revision.to_be_bytes());
254 bytes.extend(&self.base_revision.to_be_bytes());
238 bytes
255 bytes
239 }
256 }
240 }
257 }
241
258
242 #[test]
259 #[test]
243 fn test_offset() {
260 fn test_offset() {
244 let bytes = IndexEntryBuilder::new().with_offset(1).build();
261 let bytes = IndexEntryBuilder::new().with_offset(1).build();
245 let entry = IndexEntry {
262 let entry = IndexEntry {
246 bytes: &bytes,
263 bytes: &bytes,
247 offset_override: None,
264 offset_override: None,
248 };
265 };
249
266
250 assert_eq!(entry.offset(), 1)
267 assert_eq!(entry.offset(), 1)
251 }
268 }
252
269
253 #[test]
270 #[test]
254 fn test_with_overridden_offset() {
271 fn test_with_overridden_offset() {
255 let bytes = IndexEntryBuilder::new().with_offset(1).build();
272 let bytes = IndexEntryBuilder::new().with_offset(1).build();
256 let entry = IndexEntry {
273 let entry = IndexEntry {
257 bytes: &bytes,
274 bytes: &bytes,
258 offset_override: Some(2),
275 offset_override: Some(2),
259 };
276 };
260
277
261 assert_eq!(entry.offset(), 2)
278 assert_eq!(entry.offset(), 2)
262 }
279 }
263
280
264 #[test]
281 #[test]
265 fn test_compressed_len() {
282 fn test_compressed_len() {
266 let bytes = IndexEntryBuilder::new().with_compressed_len(1).build();
283 let bytes = IndexEntryBuilder::new().with_compressed_len(1).build();
267 let entry = IndexEntry {
284 let entry = IndexEntry {
268 bytes: &bytes,
285 bytes: &bytes,
269 offset_override: None,
286 offset_override: None,
270 };
287 };
271
288
272 assert_eq!(entry.compressed_len(), 1)
289 assert_eq!(entry.compressed_len(), 1)
273 }
290 }
274
291
275 #[test]
292 #[test]
276 fn test_uncompressed_len() {
293 fn test_uncompressed_len() {
277 let bytes = IndexEntryBuilder::new().with_uncompressed_len(1).build();
294 let bytes = IndexEntryBuilder::new().with_uncompressed_len(1).build();
278 let entry = IndexEntry {
295 let entry = IndexEntry {
279 bytes: &bytes,
296 bytes: &bytes,
280 offset_override: None,
297 offset_override: None,
281 };
298 };
282
299
283 assert_eq!(entry.uncompressed_len(), 1)
300 assert_eq!(entry.uncompressed_len(), 1)
284 }
301 }
285
302
286 #[test]
303 #[test]
287 fn test_base_revision() {
304 fn test_base_revision() {
288 let bytes = IndexEntryBuilder::new().with_base_revision(1).build();
305 let bytes = IndexEntryBuilder::new().with_base_revision(1).build();
289 let entry = IndexEntry {
306 let entry = IndexEntry {
290 bytes: &bytes,
307 bytes: &bytes,
291 offset_override: None,
308 offset_override: None,
292 };
309 };
293
310
294 assert_eq!(entry.base_revision(), 1)
311 assert_eq!(entry.base_revision(), 1)
295 }
312 }
296 }
313 }
297
314
298 #[cfg(test)]
315 #[cfg(test)]
299 pub use tests::IndexEntryBuilder;
316 pub use tests::IndexEntryBuilder;
@@ -1,433 +1,438 b''
1 // Copyright 2019-2020 Georges Racinet <georges.racinet@octobus.net>
1 // Copyright 2019-2020 Georges Racinet <georges.racinet@octobus.net>
2 //
2 //
3 // This software may be used and distributed according to the terms of the
3 // This software may be used and distributed according to the terms of the
4 // GNU General Public License version 2 or any later version.
4 // GNU General Public License version 2 or any later version.
5
5
6 //! Definitions and utilities for Revision nodes
6 //! Definitions and utilities for Revision nodes
7 //!
7 //!
8 //! In Mercurial code base, it is customary to call "a node" the binary SHA
8 //! In Mercurial code base, it is customary to call "a node" the binary SHA
9 //! of a revision.
9 //! of a revision.
10
10
11 use hex::{self, FromHex, FromHexError};
11 use hex::{self, FromHex, FromHexError};
12
12
13 /// The length in bytes of a `Node`
13 /// The length in bytes of a `Node`
14 ///
14 ///
15 /// This constant is meant to ease refactors of this module, and
15 /// This constant is meant to ease refactors of this module, and
16 /// are private so that calling code does not expect all nodes have
16 /// are private so that calling code does not expect all nodes have
17 /// the same size, should we support several formats concurrently in
17 /// the same size, should we support several formats concurrently in
18 /// the future.
18 /// the future.
19 const NODE_BYTES_LENGTH: usize = 20;
19 pub const NODE_BYTES_LENGTH: usize = 20;
20
21 /// Id of the null node.
22 ///
23 /// Used to indicate the absence of node.
24 pub const NULL_NODE_ID: [u8; NODE_BYTES_LENGTH] = [0u8; NODE_BYTES_LENGTH];
20
25
21 /// The length in bytes of a `Node`
26 /// The length in bytes of a `Node`
22 ///
27 ///
23 /// see also `NODES_BYTES_LENGTH` about it being private.
28 /// see also `NODES_BYTES_LENGTH` about it being private.
24 const NODE_NYBBLES_LENGTH: usize = 2 * NODE_BYTES_LENGTH;
29 const NODE_NYBBLES_LENGTH: usize = 2 * NODE_BYTES_LENGTH;
25
30
26 /// Private alias for readability and to ease future change
31 /// Private alias for readability and to ease future change
27 type NodeData = [u8; NODE_BYTES_LENGTH];
32 type NodeData = [u8; NODE_BYTES_LENGTH];
28
33
29 /// Binary revision SHA
34 /// Binary revision SHA
30 ///
35 ///
31 /// ## Future changes of hash size
36 /// ## Future changes of hash size
32 ///
37 ///
33 /// To accomodate future changes of hash size, Rust callers
38 /// To accomodate future changes of hash size, Rust callers
34 /// should use the conversion methods at the boundaries (FFI, actual
39 /// should use the conversion methods at the boundaries (FFI, actual
35 /// computation of hashes and I/O) only, and only if required.
40 /// computation of hashes and I/O) only, and only if required.
36 ///
41 ///
37 /// All other callers outside of unit tests should just handle `Node` values
42 /// All other callers outside of unit tests should just handle `Node` values
38 /// and never make any assumption on the actual length, using [`nybbles_len`]
43 /// and never make any assumption on the actual length, using [`nybbles_len`]
39 /// if they need a loop boundary.
44 /// if they need a loop boundary.
40 ///
45 ///
41 /// All methods that create a `Node` either take a type that enforces
46 /// All methods that create a `Node` either take a type that enforces
42 /// the size or fail immediately at runtime with [`ExactLengthRequired`].
47 /// the size or fail immediately at runtime with [`ExactLengthRequired`].
43 ///
48 ///
44 /// [`nybbles_len`]: #method.nybbles_len
49 /// [`nybbles_len`]: #method.nybbles_len
45 /// [`ExactLengthRequired`]: struct.NodeError#variant.ExactLengthRequired
50 /// [`ExactLengthRequired`]: struct.NodeError#variant.ExactLengthRequired
46 #[derive(Clone, Debug, PartialEq)]
51 #[derive(Clone, Debug, PartialEq)]
47 #[repr(transparent)]
52 #[repr(transparent)]
48 pub struct Node {
53 pub struct Node {
49 data: NodeData,
54 data: NodeData,
50 }
55 }
51
56
52 /// The node value for NULL_REVISION
57 /// The node value for NULL_REVISION
53 pub const NULL_NODE: Node = Node {
58 pub const NULL_NODE: Node = Node {
54 data: [0; NODE_BYTES_LENGTH],
59 data: [0; NODE_BYTES_LENGTH],
55 };
60 };
56
61
57 impl From<NodeData> for Node {
62 impl From<NodeData> for Node {
58 fn from(data: NodeData) -> Node {
63 fn from(data: NodeData) -> Node {
59 Node { data }
64 Node { data }
60 }
65 }
61 }
66 }
62
67
63 #[derive(Debug, PartialEq)]
68 #[derive(Debug, PartialEq)]
64 pub enum NodeError {
69 pub enum NodeError {
65 ExactLengthRequired(usize, String),
70 ExactLengthRequired(usize, String),
66 PrefixTooLong(String),
71 PrefixTooLong(String),
67 HexError(FromHexError, String),
72 HexError(FromHexError, String),
68 }
73 }
69
74
70 /// Low level utility function, also for prefixes
75 /// Low level utility function, also for prefixes
71 fn get_nybble(s: &[u8], i: usize) -> u8 {
76 fn get_nybble(s: &[u8], i: usize) -> u8 {
72 if i % 2 == 0 {
77 if i % 2 == 0 {
73 s[i / 2] >> 4
78 s[i / 2] >> 4
74 } else {
79 } else {
75 s[i / 2] & 0x0f
80 s[i / 2] & 0x0f
76 }
81 }
77 }
82 }
78
83
79 impl Node {
84 impl Node {
80 /// Retrieve the `i`th half-byte of the binary data.
85 /// Retrieve the `i`th half-byte of the binary data.
81 ///
86 ///
82 /// This is also the `i`th hexadecimal digit in numeric form,
87 /// This is also the `i`th hexadecimal digit in numeric form,
83 /// also called a [nybble](https://en.wikipedia.org/wiki/Nibble).
88 /// also called a [nybble](https://en.wikipedia.org/wiki/Nibble).
84 pub fn get_nybble(&self, i: usize) -> u8 {
89 pub fn get_nybble(&self, i: usize) -> u8 {
85 get_nybble(&self.data, i)
90 get_nybble(&self.data, i)
86 }
91 }
87
92
88 /// Length of the data, in nybbles
93 /// Length of the data, in nybbles
89 pub fn nybbles_len(&self) -> usize {
94 pub fn nybbles_len(&self) -> usize {
90 // public exposure as an instance method only, so that we can
95 // public exposure as an instance method only, so that we can
91 // easily support several sizes of hashes if needed in the future.
96 // easily support several sizes of hashes if needed in the future.
92 NODE_NYBBLES_LENGTH
97 NODE_NYBBLES_LENGTH
93 }
98 }
94
99
95 /// Convert from hexadecimal string representation
100 /// Convert from hexadecimal string representation
96 ///
101 ///
97 /// Exact length is required.
102 /// Exact length is required.
98 ///
103 ///
99 /// To be used in FFI and I/O only, in order to facilitate future
104 /// To be used in FFI and I/O only, in order to facilitate future
100 /// changes of hash format.
105 /// changes of hash format.
101 pub fn from_hex(hex: &str) -> Result<Node, NodeError> {
106 pub fn from_hex(hex: &str) -> Result<Node, NodeError> {
102 Ok(NodeData::from_hex(hex)
107 Ok(NodeData::from_hex(hex)
103 .map_err(|e| NodeError::from((e, hex)))?
108 .map_err(|e| NodeError::from((e, hex)))?
104 .into())
109 .into())
105 }
110 }
106
111
107 /// Convert to hexadecimal string representation
112 /// Convert to hexadecimal string representation
108 ///
113 ///
109 /// To be used in FFI and I/O only, in order to facilitate future
114 /// To be used in FFI and I/O only, in order to facilitate future
110 /// changes of hash format.
115 /// changes of hash format.
111 pub fn encode_hex(&self) -> String {
116 pub fn encode_hex(&self) -> String {
112 hex::encode(self.data)
117 hex::encode(self.data)
113 }
118 }
114
119
115 /// Provide access to binary data
120 /// Provide access to binary data
116 ///
121 ///
117 /// This is needed by FFI layers, for instance to return expected
122 /// This is needed by FFI layers, for instance to return expected
118 /// binary values to Python.
123 /// binary values to Python.
119 pub fn as_bytes(&self) -> &[u8] {
124 pub fn as_bytes(&self) -> &[u8] {
120 &self.data
125 &self.data
121 }
126 }
122 }
127 }
123
128
124 impl<T: AsRef<str>> From<(FromHexError, T)> for NodeError {
129 impl<T: AsRef<str>> From<(FromHexError, T)> for NodeError {
125 fn from(err_offender: (FromHexError, T)) -> Self {
130 fn from(err_offender: (FromHexError, T)) -> Self {
126 let (err, offender) = err_offender;
131 let (err, offender) = err_offender;
127 match err {
132 match err {
128 FromHexError::InvalidStringLength => {
133 FromHexError::InvalidStringLength => {
129 NodeError::ExactLengthRequired(
134 NodeError::ExactLengthRequired(
130 NODE_NYBBLES_LENGTH,
135 NODE_NYBBLES_LENGTH,
131 offender.as_ref().to_owned(),
136 offender.as_ref().to_owned(),
132 )
137 )
133 }
138 }
134 _ => NodeError::HexError(err, offender.as_ref().to_owned()),
139 _ => NodeError::HexError(err, offender.as_ref().to_owned()),
135 }
140 }
136 }
141 }
137 }
142 }
138
143
139 /// The beginning of a binary revision SHA.
144 /// The beginning of a binary revision SHA.
140 ///
145 ///
141 /// Since it can potentially come from an hexadecimal representation with
146 /// Since it can potentially come from an hexadecimal representation with
142 /// odd length, it needs to carry around whether the last 4 bits are relevant
147 /// odd length, it needs to carry around whether the last 4 bits are relevant
143 /// or not.
148 /// or not.
144 #[derive(Debug, PartialEq)]
149 #[derive(Debug, PartialEq)]
145 pub struct NodePrefix {
150 pub struct NodePrefix {
146 buf: Vec<u8>,
151 buf: Vec<u8>,
147 is_odd: bool,
152 is_odd: bool,
148 }
153 }
149
154
150 impl NodePrefix {
155 impl NodePrefix {
151 /// Convert from hexadecimal string representation
156 /// Convert from hexadecimal string representation
152 ///
157 ///
153 /// Similarly to `hex::decode`, can be used with Unicode string types
158 /// Similarly to `hex::decode`, can be used with Unicode string types
154 /// (`String`, `&str`) as well as bytes.
159 /// (`String`, `&str`) as well as bytes.
155 ///
160 ///
156 /// To be used in FFI and I/O only, in order to facilitate future
161 /// To be used in FFI and I/O only, in order to facilitate future
157 /// changes of hash format.
162 /// changes of hash format.
158 pub fn from_hex(hex: impl AsRef<[u8]>) -> Result<Self, NodeError> {
163 pub fn from_hex(hex: impl AsRef<[u8]>) -> Result<Self, NodeError> {
159 let hex = hex.as_ref();
164 let hex = hex.as_ref();
160 let len = hex.len();
165 let len = hex.len();
161 if len > NODE_NYBBLES_LENGTH {
166 if len > NODE_NYBBLES_LENGTH {
162 return Err(NodeError::PrefixTooLong(
167 return Err(NodeError::PrefixTooLong(
163 String::from_utf8_lossy(hex).to_owned().to_string(),
168 String::from_utf8_lossy(hex).to_owned().to_string(),
164 ));
169 ));
165 }
170 }
166
171
167 let is_odd = len % 2 == 1;
172 let is_odd = len % 2 == 1;
168 let even_part = if is_odd { &hex[..len - 1] } else { hex };
173 let even_part = if is_odd { &hex[..len - 1] } else { hex };
169 let mut buf: Vec<u8> = Vec::from_hex(&even_part)
174 let mut buf: Vec<u8> = Vec::from_hex(&even_part)
170 .map_err(|e| (e, String::from_utf8_lossy(hex)))?;
175 .map_err(|e| (e, String::from_utf8_lossy(hex)))?;
171
176
172 if is_odd {
177 if is_odd {
173 let latest_char = char::from(hex[len - 1]);
178 let latest_char = char::from(hex[len - 1]);
174 let latest_nybble = latest_char.to_digit(16).ok_or_else(|| {
179 let latest_nybble = latest_char.to_digit(16).ok_or_else(|| {
175 (
180 (
176 FromHexError::InvalidHexCharacter {
181 FromHexError::InvalidHexCharacter {
177 c: latest_char,
182 c: latest_char,
178 index: len - 1,
183 index: len - 1,
179 },
184 },
180 String::from_utf8_lossy(hex),
185 String::from_utf8_lossy(hex),
181 )
186 )
182 })? as u8;
187 })? as u8;
183 buf.push(latest_nybble << 4);
188 buf.push(latest_nybble << 4);
184 }
189 }
185 Ok(NodePrefix { buf, is_odd })
190 Ok(NodePrefix { buf, is_odd })
186 }
191 }
187
192
188 pub fn borrow(&self) -> NodePrefixRef {
193 pub fn borrow(&self) -> NodePrefixRef {
189 NodePrefixRef {
194 NodePrefixRef {
190 buf: &self.buf,
195 buf: &self.buf,
191 is_odd: self.is_odd,
196 is_odd: self.is_odd,
192 }
197 }
193 }
198 }
194 }
199 }
195
200
196 #[derive(Clone, Debug, PartialEq)]
201 #[derive(Clone, Debug, PartialEq)]
197 pub struct NodePrefixRef<'a> {
202 pub struct NodePrefixRef<'a> {
198 buf: &'a [u8],
203 buf: &'a [u8],
199 is_odd: bool,
204 is_odd: bool,
200 }
205 }
201
206
202 impl<'a> NodePrefixRef<'a> {
207 impl<'a> NodePrefixRef<'a> {
203 pub fn len(&self) -> usize {
208 pub fn len(&self) -> usize {
204 if self.is_odd {
209 if self.is_odd {
205 self.buf.len() * 2 - 1
210 self.buf.len() * 2 - 1
206 } else {
211 } else {
207 self.buf.len() * 2
212 self.buf.len() * 2
208 }
213 }
209 }
214 }
210
215
211 pub fn is_empty(&self) -> bool {
216 pub fn is_empty(&self) -> bool {
212 self.len() == 0
217 self.len() == 0
213 }
218 }
214
219
215 pub fn is_prefix_of(&self, node: &Node) -> bool {
220 pub fn is_prefix_of(&self, node: &Node) -> bool {
216 if self.is_odd {
221 if self.is_odd {
217 let buf = self.buf;
222 let buf = self.buf;
218 let last_pos = buf.len() - 1;
223 let last_pos = buf.len() - 1;
219 node.data.starts_with(buf.split_at(last_pos).0)
224 node.data.starts_with(buf.split_at(last_pos).0)
220 && node.data[last_pos] >> 4 == buf[last_pos] >> 4
225 && node.data[last_pos] >> 4 == buf[last_pos] >> 4
221 } else {
226 } else {
222 node.data.starts_with(self.buf)
227 node.data.starts_with(self.buf)
223 }
228 }
224 }
229 }
225
230
226 /// Retrieve the `i`th half-byte from the prefix.
231 /// Retrieve the `i`th half-byte from the prefix.
227 ///
232 ///
228 /// This is also the `i`th hexadecimal digit in numeric form,
233 /// This is also the `i`th hexadecimal digit in numeric form,
229 /// also called a [nybble](https://en.wikipedia.org/wiki/Nibble).
234 /// also called a [nybble](https://en.wikipedia.org/wiki/Nibble).
230 pub fn get_nybble(&self, i: usize) -> u8 {
235 pub fn get_nybble(&self, i: usize) -> u8 {
231 assert!(i < self.len());
236 assert!(i < self.len());
232 get_nybble(self.buf, i)
237 get_nybble(self.buf, i)
233 }
238 }
234
239
235 /// Return the index first nybble that's different from `node`
240 /// Return the index first nybble that's different from `node`
236 ///
241 ///
237 /// If the return value is `None` that means that `self` is
242 /// If the return value is `None` that means that `self` is
238 /// a prefix of `node`, but the current method is a bit slower
243 /// a prefix of `node`, but the current method is a bit slower
239 /// than `is_prefix_of`.
244 /// than `is_prefix_of`.
240 ///
245 ///
241 /// Returned index is as in `get_nybble`, i.e., starting at 0.
246 /// Returned index is as in `get_nybble`, i.e., starting at 0.
242 pub fn first_different_nybble(&self, node: &Node) -> Option<usize> {
247 pub fn first_different_nybble(&self, node: &Node) -> Option<usize> {
243 let buf = self.buf;
248 let buf = self.buf;
244 let until = if self.is_odd {
249 let until = if self.is_odd {
245 buf.len() - 1
250 buf.len() - 1
246 } else {
251 } else {
247 buf.len()
252 buf.len()
248 };
253 };
249 for (i, item) in buf.iter().enumerate().take(until) {
254 for (i, item) in buf.iter().enumerate().take(until) {
250 if *item != node.data[i] {
255 if *item != node.data[i] {
251 return if *item & 0xf0 == node.data[i] & 0xf0 {
256 return if *item & 0xf0 == node.data[i] & 0xf0 {
252 Some(2 * i + 1)
257 Some(2 * i + 1)
253 } else {
258 } else {
254 Some(2 * i)
259 Some(2 * i)
255 };
260 };
256 }
261 }
257 }
262 }
258 if self.is_odd && buf[until] & 0xf0 != node.data[until] & 0xf0 {
263 if self.is_odd && buf[until] & 0xf0 != node.data[until] & 0xf0 {
259 Some(until * 2)
264 Some(until * 2)
260 } else {
265 } else {
261 None
266 None
262 }
267 }
263 }
268 }
264 }
269 }
265
270
266 /// A shortcut for full `Node` references
271 /// A shortcut for full `Node` references
267 impl<'a> From<&'a Node> for NodePrefixRef<'a> {
272 impl<'a> From<&'a Node> for NodePrefixRef<'a> {
268 fn from(node: &'a Node) -> Self {
273 fn from(node: &'a Node) -> Self {
269 NodePrefixRef {
274 NodePrefixRef {
270 buf: &node.data,
275 buf: &node.data,
271 is_odd: false,
276 is_odd: false,
272 }
277 }
273 }
278 }
274 }
279 }
275
280
276 #[cfg(test)]
281 #[cfg(test)]
277 mod tests {
282 mod tests {
278 use super::*;
283 use super::*;
279
284
280 fn sample_node() -> Node {
285 fn sample_node() -> Node {
281 let mut data = [0; NODE_BYTES_LENGTH];
286 let mut data = [0; NODE_BYTES_LENGTH];
282 data.copy_from_slice(&[
287 data.copy_from_slice(&[
283 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba,
288 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba,
284 0x98, 0x76, 0x54, 0x32, 0x10, 0xde, 0xad, 0xbe, 0xef,
289 0x98, 0x76, 0x54, 0x32, 0x10, 0xde, 0xad, 0xbe, 0xef,
285 ]);
290 ]);
286 data.into()
291 data.into()
287 }
292 }
288
293
289 /// Pad an hexadecimal string to reach `NODE_NYBBLES_LENGTH`
294 /// Pad an hexadecimal string to reach `NODE_NYBBLES_LENGTH`
290 ///
295 ///
291 /// The padding is made with zeros
296 /// The padding is made with zeros
292 pub fn hex_pad_right(hex: &str) -> String {
297 pub fn hex_pad_right(hex: &str) -> String {
293 let mut res = hex.to_string();
298 let mut res = hex.to_string();
294 while res.len() < NODE_NYBBLES_LENGTH {
299 while res.len() < NODE_NYBBLES_LENGTH {
295 res.push('0');
300 res.push('0');
296 }
301 }
297 res
302 res
298 }
303 }
299
304
300 fn sample_node_hex() -> String {
305 fn sample_node_hex() -> String {
301 hex_pad_right("0123456789abcdeffedcba9876543210deadbeef")
306 hex_pad_right("0123456789abcdeffedcba9876543210deadbeef")
302 }
307 }
303
308
304 #[test]
309 #[test]
305 fn test_node_from_hex() {
310 fn test_node_from_hex() {
306 assert_eq!(Node::from_hex(&sample_node_hex()), Ok(sample_node()));
311 assert_eq!(Node::from_hex(&sample_node_hex()), Ok(sample_node()));
307
312
308 let mut short = hex_pad_right("0123");
313 let mut short = hex_pad_right("0123");
309 short.pop();
314 short.pop();
310 short.pop();
315 short.pop();
311 assert_eq!(
316 assert_eq!(
312 Node::from_hex(&short),
317 Node::from_hex(&short),
313 Err(NodeError::ExactLengthRequired(NODE_NYBBLES_LENGTH, short)),
318 Err(NodeError::ExactLengthRequired(NODE_NYBBLES_LENGTH, short)),
314 );
319 );
315
320
316 let not_hex = hex_pad_right("012... oops");
321 let not_hex = hex_pad_right("012... oops");
317 assert_eq!(
322 assert_eq!(
318 Node::from_hex(&not_hex),
323 Node::from_hex(&not_hex),
319 Err(NodeError::HexError(
324 Err(NodeError::HexError(
320 FromHexError::InvalidHexCharacter { c: '.', index: 3 },
325 FromHexError::InvalidHexCharacter { c: '.', index: 3 },
321 not_hex,
326 not_hex,
322 )),
327 )),
323 );
328 );
324 }
329 }
325
330
326 #[test]
331 #[test]
327 fn test_node_encode_hex() {
332 fn test_node_encode_hex() {
328 assert_eq!(sample_node().encode_hex(), sample_node_hex());
333 assert_eq!(sample_node().encode_hex(), sample_node_hex());
329 }
334 }
330
335
331 #[test]
336 #[test]
332 fn test_prefix_from_hex() -> Result<(), NodeError> {
337 fn test_prefix_from_hex() -> Result<(), NodeError> {
333 assert_eq!(
338 assert_eq!(
334 NodePrefix::from_hex("0e1")?,
339 NodePrefix::from_hex("0e1")?,
335 NodePrefix {
340 NodePrefix {
336 buf: vec![14, 16],
341 buf: vec![14, 16],
337 is_odd: true
342 is_odd: true
338 }
343 }
339 );
344 );
340 assert_eq!(
345 assert_eq!(
341 NodePrefix::from_hex("0e1a")?,
346 NodePrefix::from_hex("0e1a")?,
342 NodePrefix {
347 NodePrefix {
343 buf: vec![14, 26],
348 buf: vec![14, 26],
344 is_odd: false
349 is_odd: false
345 }
350 }
346 );
351 );
347
352
348 // checking limit case
353 // checking limit case
349 let node_as_vec = sample_node().data.iter().cloned().collect();
354 let node_as_vec = sample_node().data.iter().cloned().collect();
350 assert_eq!(
355 assert_eq!(
351 NodePrefix::from_hex(sample_node_hex())?,
356 NodePrefix::from_hex(sample_node_hex())?,
352 NodePrefix {
357 NodePrefix {
353 buf: node_as_vec,
358 buf: node_as_vec,
354 is_odd: false
359 is_odd: false
355 }
360 }
356 );
361 );
357
362
358 Ok(())
363 Ok(())
359 }
364 }
360
365
361 #[test]
366 #[test]
362 fn test_prefix_from_hex_errors() {
367 fn test_prefix_from_hex_errors() {
363 assert_eq!(
368 assert_eq!(
364 NodePrefix::from_hex("testgr"),
369 NodePrefix::from_hex("testgr"),
365 Err(NodeError::HexError(
370 Err(NodeError::HexError(
366 FromHexError::InvalidHexCharacter { c: 't', index: 0 },
371 FromHexError::InvalidHexCharacter { c: 't', index: 0 },
367 "testgr".to_string()
372 "testgr".to_string()
368 ))
373 ))
369 );
374 );
370 let mut long = NULL_NODE.encode_hex();
375 let mut long = NULL_NODE.encode_hex();
371 long.push('c');
376 long.push('c');
372 match NodePrefix::from_hex(&long)
377 match NodePrefix::from_hex(&long)
373 .expect_err("should be refused as too long")
378 .expect_err("should be refused as too long")
374 {
379 {
375 NodeError::PrefixTooLong(s) => assert_eq!(s, long),
380 NodeError::PrefixTooLong(s) => assert_eq!(s, long),
376 err => panic!(format!("Should have been TooLong, got {:?}", err)),
381 err => panic!(format!("Should have been TooLong, got {:?}", err)),
377 }
382 }
378 }
383 }
379
384
380 #[test]
385 #[test]
381 fn test_is_prefix_of() -> Result<(), NodeError> {
386 fn test_is_prefix_of() -> Result<(), NodeError> {
382 let mut node_data = [0; NODE_BYTES_LENGTH];
387 let mut node_data = [0; NODE_BYTES_LENGTH];
383 node_data[0] = 0x12;
388 node_data[0] = 0x12;
384 node_data[1] = 0xca;
389 node_data[1] = 0xca;
385 let node = Node::from(node_data);
390 let node = Node::from(node_data);
386 assert!(NodePrefix::from_hex("12")?.borrow().is_prefix_of(&node));
391 assert!(NodePrefix::from_hex("12")?.borrow().is_prefix_of(&node));
387 assert!(!NodePrefix::from_hex("1a")?.borrow().is_prefix_of(&node));
392 assert!(!NodePrefix::from_hex("1a")?.borrow().is_prefix_of(&node));
388 assert!(NodePrefix::from_hex("12c")?.borrow().is_prefix_of(&node));
393 assert!(NodePrefix::from_hex("12c")?.borrow().is_prefix_of(&node));
389 assert!(!NodePrefix::from_hex("12d")?.borrow().is_prefix_of(&node));
394 assert!(!NodePrefix::from_hex("12d")?.borrow().is_prefix_of(&node));
390 Ok(())
395 Ok(())
391 }
396 }
392
397
393 #[test]
398 #[test]
394 fn test_get_nybble() -> Result<(), NodeError> {
399 fn test_get_nybble() -> Result<(), NodeError> {
395 let prefix = NodePrefix::from_hex("dead6789cafe")?;
400 let prefix = NodePrefix::from_hex("dead6789cafe")?;
396 assert_eq!(prefix.borrow().get_nybble(0), 13);
401 assert_eq!(prefix.borrow().get_nybble(0), 13);
397 assert_eq!(prefix.borrow().get_nybble(7), 9);
402 assert_eq!(prefix.borrow().get_nybble(7), 9);
398 Ok(())
403 Ok(())
399 }
404 }
400
405
401 #[test]
406 #[test]
402 fn test_first_different_nybble_even_prefix() {
407 fn test_first_different_nybble_even_prefix() {
403 let prefix = NodePrefix::from_hex("12ca").unwrap();
408 let prefix = NodePrefix::from_hex("12ca").unwrap();
404 let prefref = prefix.borrow();
409 let prefref = prefix.borrow();
405 let mut node = Node::from([0; NODE_BYTES_LENGTH]);
410 let mut node = Node::from([0; NODE_BYTES_LENGTH]);
406 assert_eq!(prefref.first_different_nybble(&node), Some(0));
411 assert_eq!(prefref.first_different_nybble(&node), Some(0));
407 node.data[0] = 0x13;
412 node.data[0] = 0x13;
408 assert_eq!(prefref.first_different_nybble(&node), Some(1));
413 assert_eq!(prefref.first_different_nybble(&node), Some(1));
409 node.data[0] = 0x12;
414 node.data[0] = 0x12;
410 assert_eq!(prefref.first_different_nybble(&node), Some(2));
415 assert_eq!(prefref.first_different_nybble(&node), Some(2));
411 node.data[1] = 0xca;
416 node.data[1] = 0xca;
412 // now it is a prefix
417 // now it is a prefix
413 assert_eq!(prefref.first_different_nybble(&node), None);
418 assert_eq!(prefref.first_different_nybble(&node), None);
414 }
419 }
415
420
416 #[test]
421 #[test]
417 fn test_first_different_nybble_odd_prefix() {
422 fn test_first_different_nybble_odd_prefix() {
418 let prefix = NodePrefix::from_hex("12c").unwrap();
423 let prefix = NodePrefix::from_hex("12c").unwrap();
419 let prefref = prefix.borrow();
424 let prefref = prefix.borrow();
420 let mut node = Node::from([0; NODE_BYTES_LENGTH]);
425 let mut node = Node::from([0; NODE_BYTES_LENGTH]);
421 assert_eq!(prefref.first_different_nybble(&node), Some(0));
426 assert_eq!(prefref.first_different_nybble(&node), Some(0));
422 node.data[0] = 0x13;
427 node.data[0] = 0x13;
423 assert_eq!(prefref.first_different_nybble(&node), Some(1));
428 assert_eq!(prefref.first_different_nybble(&node), Some(1));
424 node.data[0] = 0x12;
429 node.data[0] = 0x12;
425 assert_eq!(prefref.first_different_nybble(&node), Some(2));
430 assert_eq!(prefref.first_different_nybble(&node), Some(2));
426 node.data[1] = 0xca;
431 node.data[1] = 0xca;
427 // now it is a prefix
432 // now it is a prefix
428 assert_eq!(prefref.first_different_nybble(&node), None);
433 assert_eq!(prefref.first_different_nybble(&node), None);
429 }
434 }
430 }
435 }
431
436
432 #[cfg(test)]
437 #[cfg(test)]
433 pub use tests::hex_pad_right;
438 pub use tests::hex_pad_right;
@@ -1,353 +1,412 b''
1 use std::borrow::Cow;
1 use std::borrow::Cow;
2 use std::fs::File;
2 use std::fs::File;
3 use std::io::Read;
3 use std::io::Read;
4 use std::ops::Deref;
4 use std::ops::Deref;
5 use std::path::Path;
5 use std::path::Path;
6
6
7 use byteorder::{BigEndian, ByteOrder};
7 use byteorder::{BigEndian, ByteOrder};
8 use crypto::digest::Digest;
9 use crypto::sha1::Sha1;
8 use flate2::read::ZlibDecoder;
10 use flate2::read::ZlibDecoder;
9 use memmap::{Mmap, MmapOptions};
11 use memmap::{Mmap, MmapOptions};
10 use micro_timer::timed;
12 use micro_timer::timed;
11 use zstd;
13 use zstd;
12
14
13 use super::index::Index;
15 use super::index::Index;
16 use super::node::{NODE_BYTES_LENGTH, NULL_NODE_ID};
14 use super::patch;
17 use super::patch;
15 use crate::revlog::Revision;
18 use crate::revlog::Revision;
16
19
17 pub enum RevlogError {
20 pub enum RevlogError {
18 IoError(std::io::Error),
21 IoError(std::io::Error),
19 UnsuportedVersion(u16),
22 UnsuportedVersion(u16),
20 InvalidRevision,
23 InvalidRevision,
21 Corrupted,
24 Corrupted,
22 UnknowDataFormat(u8),
25 UnknowDataFormat(u8),
23 }
26 }
24
27
25 fn mmap_open(path: &Path) -> Result<Mmap, std::io::Error> {
28 fn mmap_open(path: &Path) -> Result<Mmap, std::io::Error> {
26 let file = File::open(path)?;
29 let file = File::open(path)?;
27 let mmap = unsafe { MmapOptions::new().map(&file) }?;
30 let mmap = unsafe { MmapOptions::new().map(&file) }?;
28 Ok(mmap)
31 Ok(mmap)
29 }
32 }
30
33
31 /// Read only implementation of revlog.
34 /// Read only implementation of revlog.
32 pub struct Revlog {
35 pub struct Revlog {
33 /// When index and data are not interleaved: bytes of the revlog index.
36 /// When index and data are not interleaved: bytes of the revlog index.
34 /// When index and data are interleaved: bytes of the revlog index and
37 /// When index and data are interleaved: bytes of the revlog index and
35 /// data.
38 /// data.
36 index_bytes: Box<dyn Deref<Target = [u8]> + Send>,
39 index_bytes: Box<dyn Deref<Target = [u8]> + Send>,
37 /// When index and data are not interleaved: bytes of the revlog data
40 /// When index and data are not interleaved: bytes of the revlog data
38 data_bytes: Option<Box<dyn Deref<Target = [u8]> + Send>>,
41 data_bytes: Option<Box<dyn Deref<Target = [u8]> + Send>>,
39 }
42 }
40
43
41 impl Revlog {
44 impl Revlog {
42 /// Open a revlog index file.
45 /// Open a revlog index file.
43 ///
46 ///
44 /// It will also open the associated data file if index and data are not
47 /// It will also open the associated data file if index and data are not
45 /// interleaved.
48 /// interleaved.
46 #[timed]
49 #[timed]
47 pub fn open(index_path: &Path) -> Result<Self, RevlogError> {
50 pub fn open(index_path: &Path) -> Result<Self, RevlogError> {
48 let index_mmap =
51 let index_mmap =
49 mmap_open(&index_path).map_err(RevlogError::IoError)?;
52 mmap_open(&index_path).map_err(RevlogError::IoError)?;
50
53
51 let version = get_version(&index_mmap);
54 let version = get_version(&index_mmap);
52 if version != 1 {
55 if version != 1 {
53 return Err(RevlogError::UnsuportedVersion(version));
56 return Err(RevlogError::UnsuportedVersion(version));
54 }
57 }
55
58
56 let is_inline = is_inline(&index_mmap);
59 let is_inline = is_inline(&index_mmap);
57
60
58 let index_bytes = Box::new(index_mmap);
61 let index_bytes = Box::new(index_mmap);
59
62
60 // TODO load data only when needed //
63 // TODO load data only when needed //
61 // type annotation required
64 // type annotation required
62 // won't recognize Mmap as Deref<Target = [u8]>
65 // won't recognize Mmap as Deref<Target = [u8]>
63 let data_bytes: Option<Box<dyn Deref<Target = [u8]> + Send>> =
66 let data_bytes: Option<Box<dyn Deref<Target = [u8]> + Send>> =
64 if is_inline {
67 if is_inline {
65 None
68 None
66 } else {
69 } else {
67 let data_path = index_path.with_extension("d");
70 let data_path = index_path.with_extension("d");
68 let data_mmap =
71 let data_mmap =
69 mmap_open(&data_path).map_err(RevlogError::IoError)?;
72 mmap_open(&data_path).map_err(RevlogError::IoError)?;
70 Some(Box::new(data_mmap))
73 Some(Box::new(data_mmap))
71 };
74 };
72
75
73 Ok(Revlog {
76 Ok(Revlog {
74 index_bytes,
77 index_bytes,
75 data_bytes,
78 data_bytes,
76 })
79 })
77 }
80 }
78
81
79 /// Return the full data associated to a revision.
82 /// Return the full data associated to a revision.
80 ///
83 ///
81 /// All entries required to build the final data out of deltas will be
84 /// All entries required to build the final data out of deltas will be
82 /// retrieved as needed, and the deltas will be applied to the inital
85 /// retrieved as needed, and the deltas will be applied to the inital
83 /// snapshot to rebuild the final data.
86 /// snapshot to rebuild the final data.
84 #[timed]
87 #[timed]
85 pub fn get_rev_data(&self, rev: Revision) -> Result<Vec<u8>, RevlogError> {
88 pub fn get_rev_data(&self, rev: Revision) -> Result<Vec<u8>, RevlogError> {
86 // Todo return -> Cow
89 // Todo return -> Cow
87 let mut entry = self.get_entry(rev)?;
90 let mut entry = self.get_entry(rev)?;
88 let mut delta_chain = vec![];
91 let mut delta_chain = vec![];
89 while let Some(base_rev) = entry.base_rev {
92 while let Some(base_rev) = entry.base_rev {
90 delta_chain.push(entry);
93 delta_chain.push(entry);
91 entry = self
94 entry = self
92 .get_entry(base_rev)
95 .get_entry(base_rev)
93 .map_err(|_| RevlogError::Corrupted)?;
96 .map_err(|_| RevlogError::Corrupted)?;
94 }
97 }
95
98
96 if delta_chain.is_empty() {
99 // TODO do not look twice in the index
97 Ok(entry.data()?.into())
100 let index = self.index();
101 let index_entry =
102 index.get_entry(rev).ok_or(RevlogError::InvalidRevision)?;
103
104 let data: Vec<u8> = if delta_chain.is_empty() {
105 entry.data()?.into()
106 } else {
107 Revlog::build_data_from_deltas(entry, &delta_chain)?
108 };
109
110 if self.check_hash(
111 index_entry.p1(),
112 index_entry.p2(),
113 index_entry.hash(),
114 &data,
115 ) {
116 Ok(data)
98 } else {
117 } else {
99 Revlog::build_data_from_deltas(entry, &delta_chain)
118 Err(RevlogError::Corrupted)
100 }
119 }
101 }
120 }
102
121
122 /// Check the hash of some given data against the recorded hash.
123 pub fn check_hash(
124 &self,
125 p1: Revision,
126 p2: Revision,
127 expected: &[u8],
128 data: &[u8],
129 ) -> bool {
130 let index = self.index();
131 let e1 = index.get_entry(p1);
132 let h1 = match e1 {
133 Some(ref entry) => entry.hash(),
134 None => &NULL_NODE_ID,
135 };
136 let e2 = index.get_entry(p2);
137 let h2 = match e2 {
138 Some(ref entry) => entry.hash(),
139 None => &NULL_NODE_ID,
140 };
141
142 hash(data, &h1, &h2).as_slice() == expected
143 }
144
103 /// Build the full data of a revision out its snapshot
145 /// Build the full data of a revision out its snapshot
104 /// and its deltas.
146 /// and its deltas.
105 #[timed]
147 #[timed]
106 fn build_data_from_deltas(
148 fn build_data_from_deltas(
107 snapshot: RevlogEntry,
149 snapshot: RevlogEntry,
108 deltas: &[RevlogEntry],
150 deltas: &[RevlogEntry],
109 ) -> Result<Vec<u8>, RevlogError> {
151 ) -> Result<Vec<u8>, RevlogError> {
110 let snapshot = snapshot.data()?;
152 let snapshot = snapshot.data()?;
111 let deltas = deltas
153 let deltas = deltas
112 .iter()
154 .iter()
113 .rev()
155 .rev()
114 .map(RevlogEntry::data)
156 .map(RevlogEntry::data)
115 .collect::<Result<Vec<Cow<'_, [u8]>>, RevlogError>>()?;
157 .collect::<Result<Vec<Cow<'_, [u8]>>, RevlogError>>()?;
116 let patches: Vec<_> =
158 let patches: Vec<_> =
117 deltas.iter().map(|d| patch::PatchList::new(d)).collect();
159 deltas.iter().map(|d| patch::PatchList::new(d)).collect();
118 let patch = patch::fold_patch_lists(&patches);
160 let patch = patch::fold_patch_lists(&patches);
119 Ok(patch.apply(&snapshot))
161 Ok(patch.apply(&snapshot))
120 }
162 }
121
163
122 /// Return the revlog index.
164 /// Return the revlog index.
123 fn index(&self) -> Index {
165 fn index(&self) -> Index {
124 let is_inline = self.data_bytes.is_none();
166 let is_inline = self.data_bytes.is_none();
125 Index::new(&self.index_bytes, is_inline)
167 Index::new(&self.index_bytes, is_inline)
126 }
168 }
127
169
128 /// Return the revlog data.
170 /// Return the revlog data.
129 fn data(&self) -> &[u8] {
171 fn data(&self) -> &[u8] {
130 match self.data_bytes {
172 match self.data_bytes {
131 Some(ref data_bytes) => &data_bytes,
173 Some(ref data_bytes) => &data_bytes,
132 None => &self.index_bytes,
174 None => &self.index_bytes,
133 }
175 }
134 }
176 }
135
177
136 /// Get an entry of the revlog.
178 /// Get an entry of the revlog.
137 fn get_entry(&self, rev: Revision) -> Result<RevlogEntry, RevlogError> {
179 fn get_entry(&self, rev: Revision) -> Result<RevlogEntry, RevlogError> {
138 let index = self.index();
180 let index = self.index();
139 let index_entry =
181 let index_entry =
140 index.get_entry(rev).ok_or(RevlogError::InvalidRevision)?;
182 index.get_entry(rev).ok_or(RevlogError::InvalidRevision)?;
141 let start = index_entry.offset();
183 let start = index_entry.offset();
142 let end = start + index_entry.compressed_len();
184 let end = start + index_entry.compressed_len();
143 let entry = RevlogEntry {
185 let entry = RevlogEntry {
144 rev,
186 rev,
145 bytes: &self.data()[start..end],
187 bytes: &self.data()[start..end],
146 compressed_len: index_entry.compressed_len(),
188 compressed_len: index_entry.compressed_len(),
147 uncompressed_len: index_entry.uncompressed_len(),
189 uncompressed_len: index_entry.uncompressed_len(),
148 base_rev: if index_entry.base_revision() == rev {
190 base_rev: if index_entry.base_revision() == rev {
149 None
191 None
150 } else {
192 } else {
151 Some(index_entry.base_revision())
193 Some(index_entry.base_revision())
152 },
194 },
153 };
195 };
154 Ok(entry)
196 Ok(entry)
155 }
197 }
156 }
198 }
157
199
158 /// The revlog entry's bytes and the necessary informations to extract
200 /// The revlog entry's bytes and the necessary informations to extract
159 /// the entry's data.
201 /// the entry's data.
160 #[derive(Debug)]
202 #[derive(Debug)]
161 pub struct RevlogEntry<'a> {
203 pub struct RevlogEntry<'a> {
162 rev: Revision,
204 rev: Revision,
163 bytes: &'a [u8],
205 bytes: &'a [u8],
164 compressed_len: usize,
206 compressed_len: usize,
165 uncompressed_len: usize,
207 uncompressed_len: usize,
166 base_rev: Option<Revision>,
208 base_rev: Option<Revision>,
167 }
209 }
168
210
169 impl<'a> RevlogEntry<'a> {
211 impl<'a> RevlogEntry<'a> {
170 /// Extract the data contained in the entry.
212 /// Extract the data contained in the entry.
171 pub fn data(&self) -> Result<Cow<'_, [u8]>, RevlogError> {
213 pub fn data(&self) -> Result<Cow<'_, [u8]>, RevlogError> {
172 if self.bytes.is_empty() {
214 if self.bytes.is_empty() {
173 return Ok(Cow::Borrowed(&[]));
215 return Ok(Cow::Borrowed(&[]));
174 }
216 }
175 match self.bytes[0] {
217 match self.bytes[0] {
176 // Revision data is the entirety of the entry, including this
218 // Revision data is the entirety of the entry, including this
177 // header.
219 // header.
178 b'\0' => Ok(Cow::Borrowed(self.bytes)),
220 b'\0' => Ok(Cow::Borrowed(self.bytes)),
179 // Raw revision data follows.
221 // Raw revision data follows.
180 b'u' => Ok(Cow::Borrowed(&self.bytes[1..])),
222 b'u' => Ok(Cow::Borrowed(&self.bytes[1..])),
181 // zlib (RFC 1950) data.
223 // zlib (RFC 1950) data.
182 b'x' => Ok(Cow::Owned(self.uncompressed_zlib_data())),
224 b'x' => Ok(Cow::Owned(self.uncompressed_zlib_data())),
183 // zstd data.
225 // zstd data.
184 b'\x28' => Ok(Cow::Owned(self.uncompressed_zstd_data())),
226 b'\x28' => Ok(Cow::Owned(self.uncompressed_zstd_data())),
185 format_type => Err(RevlogError::UnknowDataFormat(format_type)),
227 format_type => Err(RevlogError::UnknowDataFormat(format_type)),
186 }
228 }
187 }
229 }
188
230
189 fn uncompressed_zlib_data(&self) -> Vec<u8> {
231 fn uncompressed_zlib_data(&self) -> Vec<u8> {
190 let mut decoder = ZlibDecoder::new(self.bytes);
232 let mut decoder = ZlibDecoder::new(self.bytes);
191 if self.is_delta() {
233 if self.is_delta() {
192 let mut buf = Vec::with_capacity(self.compressed_len);
234 let mut buf = Vec::with_capacity(self.compressed_len);
193 decoder.read_to_end(&mut buf).expect("corrupted zlib data");
235 decoder.read_to_end(&mut buf).expect("corrupted zlib data");
194 buf
236 buf
195 } else {
237 } else {
196 let mut buf = vec![0; self.uncompressed_len];
238 let mut buf = vec![0; self.uncompressed_len];
197 decoder.read_exact(&mut buf).expect("corrupted zlib data");
239 decoder.read_exact(&mut buf).expect("corrupted zlib data");
198 buf
240 buf
199 }
241 }
200 }
242 }
201
243
202 fn uncompressed_zstd_data(&self) -> Vec<u8> {
244 fn uncompressed_zstd_data(&self) -> Vec<u8> {
203 if self.is_delta() {
245 if self.is_delta() {
204 let mut buf = Vec::with_capacity(self.compressed_len);
246 let mut buf = Vec::with_capacity(self.compressed_len);
205 zstd::stream::copy_decode(self.bytes, &mut buf)
247 zstd::stream::copy_decode(self.bytes, &mut buf)
206 .expect("corrupted zstd data");
248 .expect("corrupted zstd data");
207 buf
249 buf
208 } else {
250 } else {
209 let mut buf = vec![0; self.uncompressed_len];
251 let mut buf = vec![0; self.uncompressed_len];
210 let len = zstd::block::decompress_to_buffer(self.bytes, &mut buf)
252 let len = zstd::block::decompress_to_buffer(self.bytes, &mut buf)
211 .expect("corrupted zstd data");
253 .expect("corrupted zstd data");
212 assert_eq!(len, self.uncompressed_len, "corrupted zstd data");
254 assert_eq!(len, self.uncompressed_len, "corrupted zstd data");
213 buf
255 buf
214 }
256 }
215 }
257 }
216
258
217 /// Tell if the entry is a snapshot or a delta
259 /// Tell if the entry is a snapshot or a delta
218 /// (influences on decompression).
260 /// (influences on decompression).
219 fn is_delta(&self) -> bool {
261 fn is_delta(&self) -> bool {
220 self.base_rev.is_some()
262 self.base_rev.is_some()
221 }
263 }
222 }
264 }
223
265
224 /// Value of the inline flag.
266 /// Value of the inline flag.
225 pub fn is_inline(index_bytes: &[u8]) -> bool {
267 pub fn is_inline(index_bytes: &[u8]) -> bool {
226 match &index_bytes[0..=1] {
268 match &index_bytes[0..=1] {
227 [0, 0] | [0, 2] => false,
269 [0, 0] | [0, 2] => false,
228 _ => true,
270 _ => true,
229 }
271 }
230 }
272 }
231
273
232 /// Format version of the revlog.
274 /// Format version of the revlog.
233 pub fn get_version(index_bytes: &[u8]) -> u16 {
275 pub fn get_version(index_bytes: &[u8]) -> u16 {
234 BigEndian::read_u16(&index_bytes[2..=3])
276 BigEndian::read_u16(&index_bytes[2..=3])
235 }
277 }
236
278
279 /// Calculate the hash of a revision given its data and its parents.
280 fn hash(data: &[u8], p1_hash: &[u8], p2_hash: &[u8]) -> Vec<u8> {
281 let mut hasher = Sha1::new();
282 let (a, b) = (p1_hash, p2_hash);
283 if a > b {
284 hasher.input(b);
285 hasher.input(a);
286 } else {
287 hasher.input(a);
288 hasher.input(b);
289 }
290 hasher.input(data);
291 let mut hash = vec![0; NODE_BYTES_LENGTH];
292 hasher.result(&mut hash);
293 hash
294 }
295
237 #[cfg(test)]
296 #[cfg(test)]
238 mod tests {
297 mod tests {
239 use super::*;
298 use super::*;
240
299
241 use super::super::index::IndexEntryBuilder;
300 use super::super::index::IndexEntryBuilder;
242
301
243 #[cfg(test)]
302 #[cfg(test)]
244 pub struct RevlogBuilder {
303 pub struct RevlogBuilder {
245 version: u16,
304 version: u16,
246 is_general_delta: bool,
305 is_general_delta: bool,
247 is_inline: bool,
306 is_inline: bool,
248 offset: usize,
307 offset: usize,
249 index: Vec<Vec<u8>>,
308 index: Vec<Vec<u8>>,
250 data: Vec<Vec<u8>>,
309 data: Vec<Vec<u8>>,
251 }
310 }
252
311
253 #[cfg(test)]
312 #[cfg(test)]
254 impl RevlogBuilder {
313 impl RevlogBuilder {
255 pub fn new() -> Self {
314 pub fn new() -> Self {
256 Self {
315 Self {
257 version: 2,
316 version: 2,
258 is_inline: false,
317 is_inline: false,
259 is_general_delta: true,
318 is_general_delta: true,
260 offset: 0,
319 offset: 0,
261 index: vec![],
320 index: vec![],
262 data: vec![],
321 data: vec![],
263 }
322 }
264 }
323 }
265
324
266 pub fn with_inline(&mut self, value: bool) -> &mut Self {
325 pub fn with_inline(&mut self, value: bool) -> &mut Self {
267 self.is_inline = value;
326 self.is_inline = value;
268 self
327 self
269 }
328 }
270
329
271 pub fn with_general_delta(&mut self, value: bool) -> &mut Self {
330 pub fn with_general_delta(&mut self, value: bool) -> &mut Self {
272 self.is_general_delta = value;
331 self.is_general_delta = value;
273 self
332 self
274 }
333 }
275
334
276 pub fn with_version(&mut self, value: u16) -> &mut Self {
335 pub fn with_version(&mut self, value: u16) -> &mut Self {
277 self.version = value;
336 self.version = value;
278 self
337 self
279 }
338 }
280
339
281 pub fn push(
340 pub fn push(
282 &mut self,
341 &mut self,
283 mut index: IndexEntryBuilder,
342 mut index: IndexEntryBuilder,
284 data: Vec<u8>,
343 data: Vec<u8>,
285 ) -> &mut Self {
344 ) -> &mut Self {
286 if self.index.is_empty() {
345 if self.index.is_empty() {
287 index.is_first(true);
346 index.is_first(true);
288 index.with_general_delta(self.is_general_delta);
347 index.with_general_delta(self.is_general_delta);
289 index.with_inline(self.is_inline);
348 index.with_inline(self.is_inline);
290 index.with_version(self.version);
349 index.with_version(self.version);
291 } else {
350 } else {
292 index.with_offset(self.offset);
351 index.with_offset(self.offset);
293 }
352 }
294 self.index.push(index.build());
353 self.index.push(index.build());
295 self.offset += data.len();
354 self.offset += data.len();
296 self.data.push(data);
355 self.data.push(data);
297 self
356 self
298 }
357 }
299
358
300 pub fn build_inline(&self) -> Vec<u8> {
359 pub fn build_inline(&self) -> Vec<u8> {
301 let mut bytes =
360 let mut bytes =
302 Vec::with_capacity(self.index.len() + self.data.len());
361 Vec::with_capacity(self.index.len() + self.data.len());
303 for (index, data) in self.index.iter().zip(self.data.iter()) {
362 for (index, data) in self.index.iter().zip(self.data.iter()) {
304 bytes.extend(index);
363 bytes.extend(index);
305 bytes.extend(data);
364 bytes.extend(data);
306 }
365 }
307 bytes
366 bytes
308 }
367 }
309 }
368 }
310
369
311 #[test]
370 #[test]
312 fn is_not_inline_when_no_inline_flag_test() {
371 fn is_not_inline_when_no_inline_flag_test() {
313 let bytes = RevlogBuilder::new()
372 let bytes = RevlogBuilder::new()
314 .with_general_delta(false)
373 .with_general_delta(false)
315 .with_inline(false)
374 .with_inline(false)
316 .push(IndexEntryBuilder::new(), vec![])
375 .push(IndexEntryBuilder::new(), vec![])
317 .build_inline();
376 .build_inline();
318
377
319 assert_eq!(is_inline(&bytes), false)
378 assert_eq!(is_inline(&bytes), false)
320 }
379 }
321
380
322 #[test]
381 #[test]
323 fn is_inline_when_inline_flag_test() {
382 fn is_inline_when_inline_flag_test() {
324 let bytes = RevlogBuilder::new()
383 let bytes = RevlogBuilder::new()
325 .with_general_delta(false)
384 .with_general_delta(false)
326 .with_inline(true)
385 .with_inline(true)
327 .push(IndexEntryBuilder::new(), vec![])
386 .push(IndexEntryBuilder::new(), vec![])
328 .build_inline();
387 .build_inline();
329
388
330 assert_eq!(is_inline(&bytes), true)
389 assert_eq!(is_inline(&bytes), true)
331 }
390 }
332
391
333 #[test]
392 #[test]
334 fn is_inline_when_inline_and_generaldelta_flags_test() {
393 fn is_inline_when_inline_and_generaldelta_flags_test() {
335 let bytes = RevlogBuilder::new()
394 let bytes = RevlogBuilder::new()
336 .with_general_delta(true)
395 .with_general_delta(true)
337 .with_inline(true)
396 .with_inline(true)
338 .push(IndexEntryBuilder::new(), vec![])
397 .push(IndexEntryBuilder::new(), vec![])
339 .build_inline();
398 .build_inline();
340
399
341 assert_eq!(is_inline(&bytes), true)
400 assert_eq!(is_inline(&bytes), true)
342 }
401 }
343
402
344 #[test]
403 #[test]
345 fn version_test() {
404 fn version_test() {
346 let bytes = RevlogBuilder::new()
405 let bytes = RevlogBuilder::new()
347 .with_version(1)
406 .with_version(1)
348 .push(IndexEntryBuilder::new(), vec![])
407 .push(IndexEntryBuilder::new(), vec![])
349 .build_inline();
408 .build_inline();
350
409
351 assert_eq!(get_version(&bytes), 1)
410 assert_eq!(get_version(&bytes), 1)
352 }
411 }
353 }
412 }
General Comments 0
You need to be logged in to leave comments. Login now