It's interesting how low-level operations on bytes can be a bit troublesome in purely safe and potentially high-level Rust with iterators. Git, anyway, really wants free access to memory in this case!
Unified · Split
| @@ -248,7 +248,6 @@ impl File { · 247 unmodified lines | ||
| 248 | 248 | let (result_size, consumed) = delta_header_size(&buf[consumed..]); |
| 249 | 249 | delta.header_size += consumed; |
| 250 | 250 | delta.result_size = result_size; |
| 251 | − dbg!(delta); | |
| 252 | 251 | } |
| 253 | 252 | |
| 254 | 253 | // From oldest to most recent, apply all deltas, swapping the buffer back and forth |
| @@ -285,8 +284,50 @@ impl File { · 30 unmodified lines | ||
| 285 | 284 | } |
| 286 | 285 | } |
| 287 | 286 | |
| 288 | −fn apply_delta(source: &[u8], target: &mut [u8], instructions: &[u8]) { | |
| 289 | − unimplemented!("delta application") | |
| 287 | +fn apply_delta(mut base: &[u8], mut target: &mut [u8], instructions: &[u8]) { | |
| 288 | + let mut iter = instructions.into_iter(); | |
| 289 | + while let Some(cmd) = iter.next() { | |
| 290 | + match cmd { | |
| 291 | + cmd if cmd & 0b1000_0000 != 0 => { | |
| 292 | + let (mut ofs, mut size): (u32, u32) = (0, 0); | |
| 293 | + if cmd & 0b0000_0001 != 0 { | |
| 294 | + ofs = *iter.next().unwrap() as u32; | |
| 295 | + } | |
| 296 | + if cmd & 0b0000_0010 != 0 { | |
| 297 | + ofs |= (*iter.next().unwrap() as u32) << 8; | |
| 298 | + } | |
| 299 | + if cmd & 0b0000_0100 != 0 { | |
| 300 | + ofs |= (*iter.next().unwrap() as u32) << 16; | |
| 301 | + } | |
| 302 | + if cmd & 0b0000_1000 != 0 { | |
| 303 | + ofs |= (*iter.next().unwrap() as u32) << 24; | |
| 304 | + } | |
| 305 | + if cmd & 0b0001_0000 != 0 { | |
| 306 | + size = *iter.next().unwrap() as u32; | |
| 307 | + } | |
| 308 | + if cmd & 0b0010_0000 != 0 { | |
| 309 | + size |= (*iter.next().unwrap() as u32) << 8; | |
| 310 | + } | |
| 311 | + if cmd & 0b0100_0000 != 0 { | |
| 312 | + size |= (*iter.next().unwrap() as u32) << 16; | |
| 313 | + } | |
| 314 | + if size == 0 { | |
| 315 | + size = 0x10000; // 65536 | |
| 316 | + } | |
| 317 | + let ofs = ofs as usize; | |
| 318 | + std::io::Write::write(&mut target, &base[ofs..ofs + size as usize]) | |
| 319 | + .expect("delta copy from base: byte slices must match"); | |
| 320 | + } | |
| 321 | + 0 => panic!("encounted unsupported command code: 0"), | |
| 322 | + size => { | |
| 323 | + // Fixme: must copy from instruction buffer! | |
| 324 | + let (dest, rest) = base.split_at(*size as usize); | |
| 325 | + std::io::Write::write(&mut target, dest) | |
| 326 | + .expect("delta copy data: slice sizes to match up"); | |
| 327 | + base = rest; | |
| 328 | + } | |
| 329 | + } | |
| 330 | + } | |
| 290 | 331 | } |
| 291 | 332 | |
| 292 | 333 | fn delta_header_size(d: &[u8]) -> (u64, usize) { |