comparison rust/hg-core/src/revlog/path_encode.rs @ 50159:96d31efd21f7

rhg: reduce verbosity in path_encode by using a trait for writing Hopefully this makes the code easier to read and understand and shorter overall. It also lets us later tweak the type we use as a [Sink], without having to change the encoding functions, including using two different types for size measurement and for the actual serialization.
author Arseniy Alekseyev <aalekseyev@janestreet.com>
date Thu, 16 Feb 2023 18:29:52 +0000
parents 0d2ec486d95c
children 5ce53ff6133a
comparison
equal deleted inserted replaced
50158:0d2ec486d95c 50159:96d31efd21f7
34 DH, 34 DH,
35 DHGDI, 35 DHGDI,
36 DDEFAULT, 36 DDEFAULT,
37 } 37 }
38 38
39 trait Sink {
40 fn write_byte(&mut self, c: u8);
41 fn write_bytes(&mut self, c: &[u8]);
42 }
43
39 fn inset(bitset: &[u32; 8], c: u8) -> bool { 44 fn inset(bitset: &[u32; 8], c: u8) -> bool {
40 bitset[(c as usize) >> 5] & (1 << (c & 31)) != 0 45 bitset[(c as usize) >> 5] & (1 << (c & 31)) != 0
41 } 46 }
42 47
43 fn charcopy(dest: Option<&mut [u8]>, destlen: &mut usize, c: u8) { 48 struct Dest<'a> {
44 if let Some(slice) = dest { 49 dest: Option<&'a mut [u8]>,
45 slice[*destlen] = c 50 pub len: usize,
46 } 51 }
47 *destlen += 1 52
48 } 53 impl<'a> Dest<'a> {
49 54 pub fn create(buf: &'a mut [u8]) -> Dest<'a> {
50 fn memcopy(dest: Option<&mut [u8]>, destlen: &mut usize, src: &[u8]) { 55 Dest {
51 if let Some(slice) = dest { 56 dest: Some(buf),
52 slice[*destlen..*destlen + src.len()].copy_from_slice(src) 57 len: 0,
53 } 58 }
54 *destlen += src.len(); 59 }
60
61 pub fn create_measure() -> Dest<'a> {
62 Dest { dest: None, len: 0 }
63 }
55 } 64 }
56 65
57 fn rewrap_option<'a, 'b: 'a>( 66 fn rewrap_option<'a, 'b: 'a>(
58 x: &'a mut Option<&'b mut [u8]>, 67 x: &'a mut Option<&'b mut [u8]>,
59 ) -> Option<&'a mut [u8]> { 68 ) -> Option<&'a mut [u8]> {
61 None => None, 70 None => None,
62 Some(y) => Some(y), 71 Some(y) => Some(y),
63 } 72 }
64 } 73 }
65 74
66 fn hexencode(mut dest: Option<&mut [u8]>, destlen: &mut usize, c: u8) { 75 impl<'a> Sink for Dest<'a> {
76 fn write_byte(&mut self, c: u8) {
77 if let Some(slice) = rewrap_option(&mut self.dest) {
78 slice[self.len] = c
79 }
80 self.len += 1
81 }
82
83 fn write_bytes(&mut self, src: &[u8]) {
84 if let Some(slice) = rewrap_option(&mut self.dest) {
85 slice[self.len..self.len + src.len()].copy_from_slice(src)
86 }
87 self.len += src.len();
88 }
89 }
90
91 fn hexencode(dest: &mut impl Sink, c: u8) {
67 let hexdigit = b"0123456789abcdef"; 92 let hexdigit = b"0123456789abcdef";
68 charcopy( 93 dest.write_byte(hexdigit[(c as usize) >> 4]);
69 rewrap_option(&mut dest), 94 dest.write_byte(hexdigit[(c as usize) & 15]);
70 destlen,
71 hexdigit[(c as usize) >> 4],
72 );
73 charcopy(dest, destlen, hexdigit[(c as usize) & 15]);
74 } 95 }
75 96
76 /* 3-byte escape: tilde followed by two hex digits */ 97 /* 3-byte escape: tilde followed by two hex digits */
77 fn escape3(mut dest: Option<&mut [u8]>, destlen: &mut usize, c: u8) { 98 fn escape3(dest: &mut impl Sink, c: u8) {
78 charcopy(rewrap_option(&mut dest), destlen, b'~'); 99 dest.write_byte(b'~');
79 hexencode(dest, destlen, c); 100 hexencode(dest, c);
80 } 101 }
81 102
82 fn encode_dir(mut dest: Option<&mut [u8]>, src: &[u8]) -> usize { 103 fn encode_dir(dest: &mut impl Sink, src: &[u8]) {
83 let mut state = dir_state::DDEFAULT; 104 let mut state = dir_state::DDEFAULT;
84 let mut i = 0; 105 let mut i = 0;
85 let mut destlen = 0;
86 106
87 while i < src.len() { 107 while i < src.len() {
88 match state { 108 match state {
89 dir_state::DDOT => match src[i] { 109 dir_state::DDOT => match src[i] {
90 b'd' | b'i' => { 110 b'd' | b'i' => {
91 state = dir_state::DHGDI; 111 state = dir_state::DHGDI;
92 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); 112 dest.write_byte(src[i]);
93 i += 1; 113 i += 1;
94 } 114 }
95 b'h' => { 115 b'h' => {
96 state = dir_state::DH; 116 state = dir_state::DH;
97 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); 117 dest.write_byte(src[i]);
98 i += 1; 118 i += 1;
99 } 119 }
100 _ => { 120 _ => {
101 state = dir_state::DDEFAULT; 121 state = dir_state::DDEFAULT;
102 } 122 }
103 }, 123 },
104 dir_state::DH => { 124 dir_state::DH => {
105 if src[i] == b'g' { 125 if src[i] == b'g' {
106 state = dir_state::DHGDI; 126 state = dir_state::DHGDI;
107 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); 127 dest.write_byte(src[i]);
108 i += 1; 128 i += 1;
109 } else { 129 } else {
110 state = dir_state::DDEFAULT; 130 state = dir_state::DDEFAULT;
111 } 131 }
112 } 132 }
113 dir_state::DHGDI => { 133 dir_state::DHGDI => {
114 if src[i] == b'/' { 134 if src[i] == b'/' {
115 memcopy(rewrap_option(&mut dest), &mut destlen, b".hg"); 135 dest.write_bytes(b".hg");
116 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); 136 dest.write_byte(src[i]);
117 i += 1; 137 i += 1;
118 } 138 }
119 state = dir_state::DDEFAULT; 139 state = dir_state::DDEFAULT;
120 } 140 }
121 dir_state::DDEFAULT => { 141 dir_state::DDEFAULT => {
122 if src[i] == b'.' { 142 if src[i] == b'.' {
123 state = dir_state::DDOT 143 state = dir_state::DDOT
124 } 144 }
125 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); 145 dest.write_byte(src[i]);
126 i += 1; 146 i += 1;
127 } 147 }
128 } 148 }
129 } 149 }
130 destlen
131 } 150 }
132 151
133 fn _encode( 152 fn _encode(
134 twobytes: &[u32; 8], 153 twobytes: &[u32; 8],
135 onebyte: &[u32; 8], 154 onebyte: &[u32; 8],
136 mut dest: Option<&mut [u8]>, 155 dest: &mut impl Sink,
137 src: &[u8], 156 src: &[u8],
138 encodedir: bool, 157 encodedir: bool,
139 ) -> usize { 158 ) {
140 let mut state = path_state::START; 159 let mut state = path_state::START;
141 let mut i = 0; 160 let mut i = 0;
142 let mut destlen = 0;
143 let len = src.len(); 161 let len = src.len();
144 162
145 while i < len { 163 while i < len {
146 match state { 164 match state {
147 path_state::START => match src[i] { 165 path_state::START => match src[i] {
148 b'/' => { 166 b'/' => {
149 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); 167 dest.write_byte(src[i]);
150 i += 1; 168 i += 1;
151 } 169 }
152 b'.' => { 170 b'.' => {
153 state = path_state::LDOT; 171 state = path_state::LDOT;
154 escape3(rewrap_option(&mut dest), &mut destlen, src[i]); 172 escape3(dest, src[i]);
155 i += 1; 173 i += 1;
156 } 174 }
157 b' ' => { 175 b' ' => {
158 state = path_state::DEFAULT; 176 state = path_state::DEFAULT;
159 escape3(rewrap_option(&mut dest), &mut destlen, src[i]); 177 escape3(dest, src[i]);
160 i += 1; 178 i += 1;
161 } 179 }
162 b'a' => { 180 b'a' => {
163 state = path_state::A; 181 state = path_state::A;
164 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); 182 dest.write_byte(src[i]);
165 i += 1; 183 i += 1;
166 } 184 }
167 b'c' => { 185 b'c' => {
168 state = path_state::C; 186 state = path_state::C;
169 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); 187 dest.write_byte(src[i]);
170 i += 1; 188 i += 1;
171 } 189 }
172 b'l' => { 190 b'l' => {
173 state = path_state::L; 191 state = path_state::L;
174 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); 192 dest.write_byte(src[i]);
175 i += 1; 193 i += 1;
176 } 194 }
177 b'n' => { 195 b'n' => {
178 state = path_state::N; 196 state = path_state::N;
179 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); 197 dest.write_byte(src[i]);
180 i += 1; 198 i += 1;
181 } 199 }
182 b'p' => { 200 b'p' => {
183 state = path_state::P; 201 state = path_state::P;
184 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); 202 dest.write_byte(src[i]);
185 i += 1; 203 i += 1;
186 } 204 }
187 _ => { 205 _ => {
188 state = path_state::DEFAULT; 206 state = path_state::DEFAULT;
189 } 207 }
190 }, 208 },
191 path_state::A => { 209 path_state::A => {
192 if src[i] == b'u' { 210 if src[i] == b'u' {
193 state = path_state::AU; 211 state = path_state::AU;
194 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); 212 dest.write_byte(src[i]);
195 i += 1; 213 i += 1;
196 } else { 214 } else {
197 state = path_state::DEFAULT; 215 state = path_state::DEFAULT;
198 } 216 }
199 } 217 }
206 } 224 }
207 } 225 }
208 path_state::THIRD => { 226 path_state::THIRD => {
209 state = path_state::DEFAULT; 227 state = path_state::DEFAULT;
210 match src[i] { 228 match src[i] {
211 b'.' | b'/' | b'\0' => escape3( 229 b'.' | b'/' | b'\0' => escape3(dest, src[i - 1]),
212 rewrap_option(&mut dest),
213 &mut destlen,
214 src[i - 1],
215 ),
216 _ => i -= 1, 230 _ => i -= 1,
217 } 231 }
218 } 232 }
219 path_state::C => { 233 path_state::C => {
220 if src[i] == b'o' { 234 if src[i] == b'o' {
221 state = path_state::CO; 235 state = path_state::CO;
222 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); 236 dest.write_byte(src[i]);
223 i += 1; 237 i += 1;
224 } else { 238 } else {
225 state = path_state::DEFAULT; 239 state = path_state::DEFAULT;
226 } 240 }
227 } 241 }
240 if src[i] >= b'1' && src[i] <= b'9' { 254 if src[i] >= b'1' && src[i] <= b'9' {
241 state = path_state::COMLPTn; 255 state = path_state::COMLPTn;
242 i += 1; 256 i += 1;
243 } else { 257 } else {
244 state = path_state::DEFAULT; 258 state = path_state::DEFAULT;
245 charcopy( 259 dest.write_byte(src[i - 1]);
246 rewrap_option(&mut dest),
247 &mut destlen,
248 src[i - 1],
249 );
250 } 260 }
251 } 261 }
252 path_state::COMLPTn => { 262 path_state::COMLPTn => {
253 state = path_state::DEFAULT; 263 state = path_state::DEFAULT;
254 match src[i] { 264 match src[i] {
255 b'.' | b'/' | b'\0' => { 265 b'.' | b'/' | b'\0' => {
256 escape3( 266 escape3(dest, src[i - 2]);
257 rewrap_option(&mut dest), 267 dest.write_byte(src[i - 1]);
258 &mut destlen,
259 src[i - 2],
260 );
261 charcopy(
262 rewrap_option(&mut dest),
263 &mut destlen,
264 src[i - 1],
265 );
266 } 268 }
267 _ => { 269 _ => {
268 memcopy( 270 dest.write_bytes(&src[i - 2..i]);
269 rewrap_option(&mut dest),
270 &mut destlen,
271 &src[i - 2..i],
272 );
273 } 271 }
274 } 272 }
275 } 273 }
276 path_state::L => { 274 path_state::L => {
277 if src[i] == b'p' { 275 if src[i] == b'p' {
278 state = path_state::LP; 276 state = path_state::LP;
279 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); 277 dest.write_byte(src[i]);
280 i += 1; 278 i += 1;
281 } else { 279 } else {
282 state = path_state::DEFAULT; 280 state = path_state::DEFAULT;
283 } 281 }
284 } 282 }
291 } 289 }
292 } 290 }
293 path_state::N => { 291 path_state::N => {
294 if src[i] == b'u' { 292 if src[i] == b'u' {
295 state = path_state::NU; 293 state = path_state::NU;
296 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); 294 dest.write_byte(src[i]);
297 i += 1; 295 i += 1;
298 } else { 296 } else {
299 state = path_state::DEFAULT; 297 state = path_state::DEFAULT;
300 } 298 }
301 } 299 }
308 } 306 }
309 } 307 }
310 path_state::P => { 308 path_state::P => {
311 if src[i] == b'r' { 309 if src[i] == b'r' {
312 state = path_state::PR; 310 state = path_state::PR;
313 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); 311 dest.write_byte(src[i]);
314 i += 1; 312 i += 1;
315 } else { 313 } else {
316 state = path_state::DEFAULT; 314 state = path_state::DEFAULT;
317 } 315 }
318 } 316 }
325 } 323 }
326 } 324 }
327 path_state::LDOT => match src[i] { 325 path_state::LDOT => match src[i] {
328 b'd' | b'i' => { 326 b'd' | b'i' => {
329 state = path_state::HGDI; 327 state = path_state::HGDI;
330 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); 328 dest.write_byte(src[i]);
331 i += 1; 329 i += 1;
332 } 330 }
333 b'h' => { 331 b'h' => {
334 state = path_state::H; 332 state = path_state::H;
335 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); 333 dest.write_byte(src[i]);
336 i += 1; 334 i += 1;
337 } 335 }
338 _ => { 336 _ => {
339 state = path_state::DEFAULT; 337 state = path_state::DEFAULT;
340 } 338 }
341 }, 339 },
342 path_state::DOT => match src[i] { 340 path_state::DOT => match src[i] {
343 b'/' | b'\0' => { 341 b'/' | b'\0' => {
344 state = path_state::START; 342 state = path_state::START;
345 memcopy(rewrap_option(&mut dest), &mut destlen, b"~2e"); 343 dest.write_bytes(b"~2e");
346 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); 344 dest.write_byte(src[i]);
347 i += 1; 345 i += 1;
348 } 346 }
349 b'd' | b'i' => { 347 b'd' | b'i' => {
350 state = path_state::HGDI; 348 state = path_state::HGDI;
351 charcopy(rewrap_option(&mut dest), &mut destlen, b'.'); 349 dest.write_byte(b'.');
352 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); 350 dest.write_byte(src[i]);
353 i += 1; 351 i += 1;
354 } 352 }
355 b'h' => { 353 b'h' => {
356 state = path_state::H; 354 state = path_state::H;
357 memcopy(rewrap_option(&mut dest), &mut destlen, b".h"); 355 dest.write_bytes(b".h");
358 i += 1; 356 i += 1;
359 } 357 }
360 _ => { 358 _ => {
361 state = path_state::DEFAULT; 359 state = path_state::DEFAULT;
362 charcopy(rewrap_option(&mut dest), &mut destlen, b'.'); 360 dest.write_byte(b'.');
363 } 361 }
364 }, 362 },
365 path_state::H => { 363 path_state::H => {
366 if src[i] == b'g' { 364 if src[i] == b'g' {
367 state = path_state::HGDI; 365 state = path_state::HGDI;
368 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); 366 dest.write_byte(src[i]);
369 i += 1; 367 i += 1;
370 } else { 368 } else {
371 state = path_state::DEFAULT; 369 state = path_state::DEFAULT;
372 } 370 }
373 } 371 }
374 path_state::HGDI => { 372 path_state::HGDI => {
375 if src[i] == b'/' { 373 if src[i] == b'/' {
376 state = path_state::START; 374 state = path_state::START;
377 if encodedir { 375 if encodedir {
378 memcopy( 376 dest.write_bytes(b".hg");
379 rewrap_option(&mut dest),
380 &mut destlen,
381 b".hg",
382 );
383 } 377 }
384 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); 378 dest.write_byte(src[i]);
385 i += 1 379 i += 1
386 } else { 380 } else {
387 state = path_state::DEFAULT; 381 state = path_state::DEFAULT;
388 } 382 }
389 } 383 }
390 path_state::SPACE => match src[i] { 384 path_state::SPACE => match src[i] {
391 b'/' | b'\0' => { 385 b'/' | b'\0' => {
392 state = path_state::START; 386 state = path_state::START;
393 memcopy(rewrap_option(&mut dest), &mut destlen, b"~20"); 387 dest.write_bytes(b"~20");
394 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); 388 dest.write_byte(src[i]);
395 i += 1; 389 i += 1;
396 } 390 }
397 _ => { 391 _ => {
398 state = path_state::DEFAULT; 392 state = path_state::DEFAULT;
399 charcopy(rewrap_option(&mut dest), &mut destlen, b' '); 393 dest.write_byte(b' ');
400 } 394 }
401 }, 395 },
402 path_state::DEFAULT => { 396 path_state::DEFAULT => {
403 while i != len && inset(onebyte, src[i]) { 397 while i != len && inset(onebyte, src[i]) {
404 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]); 398 dest.write_byte(src[i]);
405 i += 1; 399 i += 1;
406 } 400 }
407 if i == len { 401 if i == len {
408 break; 402 break;
409 } 403 }
416 state = path_state::SPACE; 410 state = path_state::SPACE;
417 i += 1 411 i += 1
418 } 412 }
419 b'/' => { 413 b'/' => {
420 state = path_state::START; 414 state = path_state::START;
421 charcopy(rewrap_option(&mut dest), &mut destlen, b'/'); 415 dest.write_byte(b'/');
422 i += 1; 416 i += 1;
423 } 417 }
424 _ => { 418 _ => {
425 if inset(onebyte, src[i]) { 419 if inset(onebyte, src[i]) {
426 loop { 420 loop {
427 charcopy( 421 dest.write_byte(src[i]);
428 rewrap_option(&mut dest),
429 &mut destlen,
430 src[i],
431 );
432 i += 1; 422 i += 1;
433 if !(i < len && inset(onebyte, src[i])) { 423 if !(i < len && inset(onebyte, src[i])) {
434 break; 424 break;
435 } 425 }
436 } 426 }
437 } else if inset(twobytes, src[i]) { 427 } else if inset(twobytes, src[i]) {
438 let c = src[i]; 428 let c = src[i];
439 i += 1; 429 i += 1;
440 charcopy( 430 dest.write_byte(b'_');
441 rewrap_option(&mut dest), 431 dest.write_byte(if c == b'_' {
442 &mut destlen, 432 b'_'
443 b'_', 433 } else {
444 ); 434 c + 32
445 charcopy( 435 });
446 rewrap_option(&mut dest),
447 &mut destlen,
448 if c == b'_' { b'_' } else { c + 32 },
449 );
450 } else { 436 } else {
451 escape3( 437 escape3(dest, src[i]);
452 rewrap_option(&mut dest),
453 &mut destlen,
454 src[i],
455 );
456 i += 1; 438 i += 1;
457 } 439 }
458 } 440 }
459 } 441 }
460 } 442 }
462 } 444 }
463 match state { 445 match state {
464 path_state::START => (), 446 path_state::START => (),
465 path_state::A => (), 447 path_state::A => (),
466 path_state::AU => (), 448 path_state::AU => (),
467 path_state::THIRD => { 449 path_state::THIRD => escape3(dest, src[i - 1]),
468 escape3(rewrap_option(&mut dest), &mut destlen, src[i - 1])
469 }
470 path_state::C => (), 450 path_state::C => (),
471 path_state::CO => (), 451 path_state::CO => (),
472 path_state::COMLPT => { 452 path_state::COMLPT => dest.write_byte(src[i - 1]),
473 charcopy(rewrap_option(&mut dest), &mut destlen, src[i - 1])
474 }
475 path_state::COMLPTn => { 453 path_state::COMLPTn => {
476 escape3(rewrap_option(&mut dest), &mut destlen, src[i - 2]); 454 escape3(dest, src[i - 2]);
477 charcopy(rewrap_option(&mut dest), &mut destlen, src[i - 1]); 455 dest.write_byte(src[i - 1]);
478 } 456 }
479 path_state::L => (), 457 path_state::L => (),
480 path_state::LP => (), 458 path_state::LP => (),
481 path_state::N => (), 459 path_state::N => (),
482 path_state::NU => (), 460 path_state::NU => (),
483 path_state::P => (), 461 path_state::P => (),
484 path_state::PR => (), 462 path_state::PR => (),
485 path_state::LDOT => (), 463 path_state::LDOT => (),
486 path_state::DOT => { 464 path_state::DOT => {
487 memcopy(rewrap_option(&mut dest), &mut destlen, b"~2e"); 465 dest.write_bytes(b"~2e");
488 } 466 }
489 path_state::H => (), 467 path_state::H => (),
490 path_state::HGDI => (), 468 path_state::HGDI => (),
491 path_state::SPACE => { 469 path_state::SPACE => {
492 memcopy(rewrap_option(&mut dest), &mut destlen, b"~20"); 470 dest.write_bytes(b"~20");
493 } 471 }
494 path_state::DEFAULT => (), 472 path_state::DEFAULT => (),
495 }; 473 }
496 destlen 474 }
497 } 475
498 476 fn basic_encode(dest: &mut impl Sink, src: &[u8]) {
499 fn basic_encode(dest: Option<&mut [u8]>, src: &[u8]) -> usize {
500 let twobytes: [u32; 8] = [0, 0, 0x87ff_fffe, 0, 0, 0, 0, 0]; 477 let twobytes: [u32; 8] = [0, 0, 0x87ff_fffe, 0, 0, 0, 0, 0];
501 let onebyte: [u32; 8] = 478 let onebyte: [u32; 8] =
502 [1, 0x2bff_3bfa, 0x6800_0001, 0x2fff_ffff, 0, 0, 0, 0]; 479 [1, 0x2bff_3bfa, 0x6800_0001, 0x2fff_ffff, 0, 0, 0, 0];
503 _encode(&twobytes, &onebyte, dest, src, true) 480 _encode(&twobytes, &onebyte, dest, src, true)
504 } 481 }
505 482
506 const MAXSTOREPATHLEN: usize = 120; 483 const MAXSTOREPATHLEN: usize = 120;
507 484
508 fn lower_encode(mut dest: Option<&mut [u8]>, src: &[u8]) -> usize { 485 fn lower_encode(dest: &mut impl Sink, src: &[u8]) {
509 let onebyte: [u32; 8] = 486 let onebyte: [u32; 8] =
510 [1, 0x2bff_fbfb, 0xe800_0001, 0x2fff_ffff, 0, 0, 0, 0]; 487 [1, 0x2bff_fbfb, 0xe800_0001, 0x2fff_ffff, 0, 0, 0, 0];
511 let lower: [u32; 8] = [0, 0, 0x07ff_fffe, 0, 0, 0, 0, 0]; 488 let lower: [u32; 8] = [0, 0, 0x07ff_fffe, 0, 0, 0, 0, 0];
512 let mut destlen = 0;
513 for c in src { 489 for c in src {
514 if inset(&onebyte, *c) { 490 if inset(&onebyte, *c) {
515 charcopy(rewrap_option(&mut dest), &mut destlen, *c) 491 dest.write_byte(*c)
516 } else if inset(&lower, *c) { 492 } else if inset(&lower, *c) {
517 charcopy(rewrap_option(&mut dest), &mut destlen, *c + 32) 493 dest.write_byte(*c + 32)
518 } else { 494 } else {
519 escape3(rewrap_option(&mut dest), &mut destlen, *c) 495 escape3(dest, *c)
520 } 496 }
521 } 497 }
522 destlen 498 }
523 } 499
524 500 fn aux_encode(dest: &mut impl Sink, src: &[u8]) {
525 fn aux_encode(dest: Option<&mut [u8]>, src: &[u8]) -> usize {
526 let twobytes = [0; 8]; 501 let twobytes = [0; 8];
527 let onebyte: [u32; 8] = [!0, 0xffff_3ffe, !0, !0, !0, !0, !0, !0]; 502 let onebyte: [u32; 8] = [!0, 0xffff_3ffe, !0, !0, !0, !0, !0, !0];
528 _encode(&twobytes, &onebyte, dest, src, false) 503 _encode(&twobytes, &onebyte, dest, src, false)
529 } 504 }
530 505
531 fn hash_mangle(src: &[u8], sha: &[u8]) -> Vec<u8> { 506 fn hash_mangle(src: &[u8], sha: &[u8]) -> Vec<u8> {
532 let dirprefixlen = 8; 507 let dirprefixlen = 8;
533 let maxshortdirslen = 68; 508 let maxshortdirslen = 68;
534 let mut destlen = 0;
535 509
536 let last_slash = src.iter().rposition(|b| *b == b'/'); 510 let last_slash = src.iter().rposition(|b| *b == b'/');
537 let last_dot: Option<usize> = { 511 let last_dot: Option<usize> = {
538 let s = last_slash.unwrap_or(0); 512 let s = last_slash.unwrap_or(0);
539 src[s..].iter().rposition(|b| *b == b'.').map(|i| i + s) 513 src[s..].iter().rposition(|b| *b == b'.').map(|i| i + s)
540 }; 514 };
541 515
542 let mut dest = vec![0; MAXSTOREPATHLEN]; 516 let mut dest_vec = vec![0; MAXSTOREPATHLEN];
543 memcopy(Some(&mut dest), &mut destlen, b"dh/"); 517 let mut dest = Dest::create(&mut dest_vec);
518 dest.write_bytes(b"dh/");
544 519
545 if let Some(last_slash) = last_slash { 520 if let Some(last_slash) = last_slash {
546 for slice in src[..last_slash].split(|b| *b == b'/') { 521 for slice in src[..last_slash].split(|b| *b == b'/') {
547 let slice = &slice[..std::cmp::min(slice.len(), dirprefixlen)]; 522 let slice = &slice[..std::cmp::min(slice.len(), dirprefixlen)];
548 if destlen + slice.len() > maxshortdirslen + 3 { 523 if dest.len + slice.len() > maxshortdirslen + 3 {
549 break; 524 break;
550 } else { 525 } else {
551 memcopy(Some(&mut dest), &mut destlen, slice); 526 dest.write_bytes(slice);
552 if dest[destlen - 1] == b'.' || dest[destlen - 1] == b' ' { 527 }
553 dest[destlen - 1] = b'_' 528 dest.write_byte(b'/');
554 } 529 }
555 } 530 }
556 charcopy(Some(&mut dest), &mut destlen, b'/'); 531
557 } 532 let used = dest.len + 40 + {
558 }
559
560 let used = destlen + 40 + {
561 if let Some(l) = last_dot { 533 if let Some(l) = last_dot {
562 src.len() - l 534 src.len() - l
563 } else { 535 } else {
564 0 536 0
565 } 537 }
575 if basenamelen > 0 { 547 if basenamelen > 0 {
576 let start = match last_slash { 548 let start = match last_slash {
577 Some(l) => l + 1, 549 Some(l) => l + 1,
578 None => 0, 550 None => 0,
579 }; 551 };
580 memcopy( 552 dest.write_bytes(&src[start..][..basenamelen])
581 Some(&mut dest),
582 &mut destlen,
583 &src[start..][..basenamelen],
584 )
585 } 553 }
586 } 554 }
587 for c in sha { 555 for c in sha {
588 hexencode(Some(&mut dest), &mut destlen, *c); 556 hexencode(&mut dest, *c);
589 } 557 }
590 if let Some(l) = last_dot { 558 if let Some(l) = last_dot {
591 memcopy(Some(&mut dest), &mut destlen, &src[l..]); 559 dest.write_bytes(&src[l..]);
592 } 560 }
593 if destlen == dest.len() { 561 let destlen = dest.len;
594 dest 562 if destlen == dest_vec.len() {
563 dest_vec
595 } else { 564 } else {
596 // sometimes the path are shorter than MAXSTOREPATHLEN 565 // sometimes the path are shorter than MAXSTOREPATHLEN
597 dest[..destlen].to_vec() 566 dest_vec[..destlen].to_vec()
598 } 567 }
599 } 568 }
600 569
601 const MAXENCODE: usize = 4096 * 4; 570 const MAXENCODE: usize = 4096 * 4;
602 fn hash_encode(src: &[u8]) -> Vec<u8> { 571 fn hash_encode(src: &[u8]) -> Vec<u8> {
603 let dired = &mut [0; MAXENCODE]; 572 let dired = &mut [0; MAXENCODE];
573 let mut dired_dest = Dest::create(dired);
604 let lowered = &mut [0; MAXENCODE]; 574 let lowered = &mut [0; MAXENCODE];
575 let mut lowered_dest = Dest::create(lowered);
605 let auxed = &mut [0; MAXENCODE]; 576 let auxed = &mut [0; MAXENCODE];
577 let mut auxed_dest = Dest::create(auxed);
606 let baselen = (src.len() - 5) * 3; 578 let baselen = (src.len() - 5) * 3;
607 if baselen >= MAXENCODE { 579 if baselen >= MAXENCODE {
608 panic!("path_encode::hash_encore: string too long: {}", baselen) 580 panic!("path_encode::hash_encore: string too long: {}", baselen)
609 }; 581 };
610 let dirlen = encode_dir(Some(&mut dired[..]), src); 582 encode_dir(&mut dired_dest, src);
583 let dirlen = dired_dest.len;
611 let sha = Sha1::digest(&dired[..dirlen]); 584 let sha = Sha1::digest(&dired[..dirlen]);
612 let lowerlen = lower_encode(Some(&mut lowered[..]), &dired[..dirlen][5..]); 585 lower_encode(&mut lowered_dest, &dired[..dirlen][5..]);
613 let auxlen = aux_encode(Some(&mut auxed[..]), &lowered[..lowerlen]); 586 let lowerlen = lowered_dest.len;
587 aux_encode(&mut auxed_dest, &lowered[..lowerlen]);
588 let auxlen = auxed_dest.len;
614 hash_mangle(&auxed[..auxlen], &sha) 589 hash_mangle(&auxed[..auxlen], &sha)
615 } 590 }
616 591
617 pub fn path_encode(path: &[u8]) -> Vec<u8> { 592 pub fn path_encode(path: &[u8]) -> Vec<u8> {
618 let newlen = if path.len() <= MAXSTOREPATHLEN { 593 let newlen = if path.len() <= MAXSTOREPATHLEN {
619 basic_encode(None, path) 594 let mut measure = Dest::create_measure();
595 basic_encode(&mut measure, path);
596 measure.len
620 } else { 597 } else {
621 MAXSTOREPATHLEN + 1 598 MAXSTOREPATHLEN + 1
622 }; 599 };
623 if newlen <= MAXSTOREPATHLEN { 600 if newlen <= MAXSTOREPATHLEN {
624 if newlen == path.len() { 601 if newlen == path.len() {
625 path.to_vec() 602 path.to_vec()
626 } else { 603 } else {
627 let mut res = vec![0; newlen]; 604 let mut res = vec![0; newlen];
628 basic_encode(Some(&mut res), path); 605 let mut dest = Dest::create(&mut res);
606 basic_encode(&mut dest, path);
607 assert!(dest.len == newlen);
629 res 608 res
630 } 609 }
631 } else { 610 } else {
632 hash_encode(path) 611 hash_encode(path)
633 } 612 }