Mercurial > public > mercurial-scm > hg
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 } |