comparison rust/hg-core/src/revlog/patch.rs @ 52160:e01e84e5e426

rust-revlog: add a Rust-only `InnerRevlog` This mirrors the Python `InnerRevlog` and will be used in a future patch to replace said Python implementation. This allows us to start doing more things in pure Rust, in particular reading and writing operations. A lot of changes have to be introduced all at once, it wouldn't be very useful to separate this patch IMO since all of them are either interlocked or only useful with the rest.
author Rapha?l Gom?s <rgomes@octobus.net>
date Thu, 10 Oct 2024 10:34:51 +0200
parents b68b19104d16
children bd8081e9fd62
comparison
equal deleted inserted replaced
52159:44823c5011fe 52160:e01e84e5e426
1 use byteorder::{BigEndian, ByteOrder}; 1 use byteorder::{BigEndian, ByteOrder};
2
3 use crate::RevlogError;
4
5 use super::inner_revlog::RevisionBuffer;
2 6
3 /// A chunk of data to insert, delete or replace in a patch 7 /// A chunk of data to insert, delete or replace in a patch
4 /// 8 ///
5 /// A chunk is: 9 /// A chunk is:
6 /// - an insertion when `!data.is_empty() && start == end` 10 /// - an insertion when `!data.is_empty() && start == end`
59 chunks: Vec<Chunk<'a>>, 63 chunks: Vec<Chunk<'a>>,
60 } 64 }
61 65
62 impl<'a> PatchList<'a> { 66 impl<'a> PatchList<'a> {
63 /// Create a `PatchList` from bytes. 67 /// Create a `PatchList` from bytes.
64 pub fn new(data: &'a [u8]) -> Self { 68 pub fn new(data: &'a [u8]) -> Result<Self, RevlogError> {
65 let mut chunks = vec![]; 69 let mut chunks = vec![];
66 let mut data = data; 70 let mut data = data;
67 while !data.is_empty() { 71 while !data.is_empty() {
68 let start = BigEndian::read_u32(&data[0..]); 72 let start = BigEndian::read_u32(&data[0..]);
69 let end = BigEndian::read_u32(&data[4..]); 73 let end = BigEndian::read_u32(&data[4..]);
70 let len = BigEndian::read_u32(&data[8..]); 74 let len = BigEndian::read_u32(&data[8..]);
71 assert!(start <= end); 75 if start > end {
76 return Err(RevlogError::corrupted("patch cannot be decoded"));
77 }
72 chunks.push(Chunk { 78 chunks.push(Chunk {
73 start, 79 start,
74 end, 80 end,
75 data: &data[12..12 + (len as usize)], 81 data: &data[12..12 + (len as usize)],
76 }); 82 });
77 data = &data[12 + (len as usize)..]; 83 data = &data[12 + (len as usize)..];
78 } 84 }
79 PatchList { chunks } 85 Ok(PatchList { chunks })
80 }
81
82 /// Return the final length of data after patching
83 /// given its initial length .
84 fn size(&self, initial_size: i32) -> i32 {
85 self.chunks
86 .iter()
87 .fold(initial_size, |acc, chunk| acc + chunk.len_diff())
88 } 86 }
89 87
90 /// Apply the patch to some data. 88 /// Apply the patch to some data.
91 pub fn apply(&self, initial: &[u8]) -> Vec<u8> { 89 pub fn apply<T>(
90 &self,
91 buffer: &mut dyn RevisionBuffer<Target = T>,
92 initial: &[u8],
93 ) {
92 let mut last: usize = 0; 94 let mut last: usize = 0;
93 let mut vec =
94 Vec::with_capacity(self.size(initial.len() as i32) as usize);
95 for Chunk { start, end, data } in self.chunks.iter() { 95 for Chunk { start, end, data } in self.chunks.iter() {
96 vec.extend(&initial[last..(*start as usize)]); 96 let slice = &initial[last..(*start as usize)];
97 vec.extend(data.iter()); 97 buffer.extend_from_slice(slice);
98 buffer.extend_from_slice(data);
98 last = *end as usize; 99 last = *end as usize;
99 } 100 }
100 vec.extend(&initial[last..]); 101 buffer.extend_from_slice(&initial[last..]);
101 vec
102 } 102 }
103 103
104 /// Combine two patch lists into a single patch list. 104 /// Combine two patch lists into a single patch list.
105 /// 105 ///
106 /// Applying consecutive patches can lead to waste of time and memory 106 /// Applying consecutive patches can lead to waste of time and memory
227 } 227 }
228 } 228 }
229 229
230 #[cfg(test)] 230 #[cfg(test)]
231 mod tests { 231 mod tests {
232 use crate::inner_revlog::CoreRevisionBuffer;
233
232 use super::*; 234 use super::*;
233 235
234 struct PatchDataBuilder { 236 struct PatchDataBuilder {
235 data: Vec<u8>, 237 data: Vec<u8>,
236 } 238 }
262 #[test] 264 #[test]
263 fn test_ends_before() { 265 fn test_ends_before() {
264 let data = vec![0u8, 0u8, 0u8]; 266 let data = vec![0u8, 0u8, 0u8];
265 let mut patch1_data = PatchDataBuilder::new(); 267 let mut patch1_data = PatchDataBuilder::new();
266 patch1_data.replace(0, 1, &[1, 2]); 268 patch1_data.replace(0, 1, &[1, 2]);
267 let mut patch1 = PatchList::new(patch1_data.get()); 269 let mut patch1 = PatchList::new(patch1_data.get()).unwrap();
268 270
269 let mut patch2_data = PatchDataBuilder::new(); 271 let mut patch2_data = PatchDataBuilder::new();
270 patch2_data.replace(2, 4, &[3, 4]); 272 patch2_data.replace(2, 4, &[3, 4]);
271 let mut patch2 = PatchList::new(patch2_data.get()); 273 let mut patch2 = PatchList::new(patch2_data.get()).unwrap();
272 274
273 let patch = patch1.combine(&mut patch2); 275 let patch = patch1.combine(&mut patch2);
274 276
275 let result = patch.apply(&data); 277 let mut buffer = CoreRevisionBuffer::new();
276 278 patch.apply(&mut buffer, &data);
277 assert_eq!(result, vec![1u8, 2, 3, 4]); 279
280 assert_eq!(buffer.finish(), vec![1u8, 2, 3, 4]);
278 } 281 }
279 282
280 #[test] 283 #[test]
281 fn test_starts_after() { 284 fn test_starts_after() {
282 let data = vec![0u8, 0u8, 0u8]; 285 let data = vec![0u8, 0u8, 0u8];
283 let mut patch1_data = PatchDataBuilder::new(); 286 let mut patch1_data = PatchDataBuilder::new();
284 patch1_data.replace(2, 3, &[3]); 287 patch1_data.replace(2, 3, &[3]);
285 let mut patch1 = PatchList::new(patch1_data.get()); 288 let mut patch1 = PatchList::new(patch1_data.get()).unwrap();
286 289
287 let mut patch2_data = PatchDataBuilder::new(); 290 let mut patch2_data = PatchDataBuilder::new();
288 patch2_data.replace(1, 2, &[1, 2]); 291 patch2_data.replace(1, 2, &[1, 2]);
289 let mut patch2 = PatchList::new(patch2_data.get()); 292 let mut patch2 = PatchList::new(patch2_data.get()).unwrap();
290 293
291 let patch = patch1.combine(&mut patch2); 294 let patch = patch1.combine(&mut patch2);
292 295
293 let result = patch.apply(&data); 296 let mut buffer = CoreRevisionBuffer::new();
294 297 patch.apply(&mut buffer, &data);
295 assert_eq!(result, vec![0u8, 1, 2, 3]); 298
299 assert_eq!(buffer.finish(), vec![0u8, 1, 2, 3]);
296 } 300 }
297 301
298 #[test] 302 #[test]
299 fn test_overridden() { 303 fn test_overridden() {
300 let data = vec![0u8, 0, 0]; 304 let data = vec![0u8, 0, 0];
301 let mut patch1_data = PatchDataBuilder::new(); 305 let mut patch1_data = PatchDataBuilder::new();
302 patch1_data.replace(1, 2, &[3, 4]); 306 patch1_data.replace(1, 2, &[3, 4]);
303 let mut patch1 = PatchList::new(patch1_data.get()); 307 let mut patch1 = PatchList::new(patch1_data.get()).unwrap();
304 308
305 let mut patch2_data = PatchDataBuilder::new(); 309 let mut patch2_data = PatchDataBuilder::new();
306 patch2_data.replace(1, 4, &[1, 2, 3]); 310 patch2_data.replace(1, 4, &[1, 2, 3]);
307 let mut patch2 = PatchList::new(patch2_data.get()); 311 let mut patch2 = PatchList::new(patch2_data.get()).unwrap();
308 312
309 let patch = patch1.combine(&mut patch2); 313 let patch = patch1.combine(&mut patch2);
310 314
311 let result = patch.apply(&data); 315 let mut buffer = CoreRevisionBuffer::new();
312 316 patch.apply(&mut buffer, &data);
313 assert_eq!(result, vec![0u8, 1, 2, 3]); 317
318 assert_eq!(buffer.finish(), vec![0u8, 1, 2, 3]);
314 } 319 }
315 320
316 #[test] 321 #[test]
317 fn test_right_most_part_is_overridden() { 322 fn test_right_most_part_is_overridden() {
318 let data = vec![0u8, 0, 0]; 323 let data = vec![0u8, 0, 0];
319 let mut patch1_data = PatchDataBuilder::new(); 324 let mut patch1_data = PatchDataBuilder::new();
320 patch1_data.replace(0, 1, &[1, 3]); 325 patch1_data.replace(0, 1, &[1, 3]);
321 let mut patch1 = PatchList::new(patch1_data.get()); 326 let mut patch1 = PatchList::new(patch1_data.get()).unwrap();
322 327
323 let mut patch2_data = PatchDataBuilder::new(); 328 let mut patch2_data = PatchDataBuilder::new();
324 patch2_data.replace(1, 4, &[2, 3, 4]); 329 patch2_data.replace(1, 4, &[2, 3, 4]);
325 let mut patch2 = PatchList::new(patch2_data.get()); 330 let mut patch2 = PatchList::new(patch2_data.get()).unwrap();
326 331
327 let patch = patch1.combine(&mut patch2); 332 let patch = patch1.combine(&mut patch2);
328 333
329 let result = patch.apply(&data); 334 let mut buffer = CoreRevisionBuffer::new();
330 335 patch.apply(&mut buffer, &data);
331 assert_eq!(result, vec![1u8, 2, 3, 4]); 336
337 assert_eq!(buffer.finish(), vec![1u8, 2, 3, 4]);
332 } 338 }
333 339
334 #[test] 340 #[test]
335 fn test_left_most_part_is_overridden() { 341 fn test_left_most_part_is_overridden() {
336 let data = vec![0u8, 0, 0]; 342 let data = vec![0u8, 0, 0];
337 let mut patch1_data = PatchDataBuilder::new(); 343 let mut patch1_data = PatchDataBuilder::new();
338 patch1_data.replace(1, 3, &[1, 3, 4]); 344 patch1_data.replace(1, 3, &[1, 3, 4]);
339 let mut patch1 = PatchList::new(patch1_data.get()); 345 let mut patch1 = PatchList::new(patch1_data.get()).unwrap();
340 346
341 let mut patch2_data = PatchDataBuilder::new(); 347 let mut patch2_data = PatchDataBuilder::new();
342 patch2_data.replace(0, 2, &[1, 2]); 348 patch2_data.replace(0, 2, &[1, 2]);
343 let mut patch2 = PatchList::new(patch2_data.get()); 349 let mut patch2 = PatchList::new(patch2_data.get()).unwrap();
344 350
345 let patch = patch1.combine(&mut patch2); 351 let patch = patch1.combine(&mut patch2);
346 352
347 let result = patch.apply(&data); 353 let mut buffer = CoreRevisionBuffer::new();
348 354 patch.apply(&mut buffer, &data);
349 assert_eq!(result, vec![1u8, 2, 3, 4]); 355
356 assert_eq!(buffer.finish(), vec![1u8, 2, 3, 4]);
350 } 357 }
351 358
352 #[test] 359 #[test]
353 fn test_mid_is_overridden() { 360 fn test_mid_is_overridden() {
354 let data = vec![0u8, 0, 0]; 361 let data = vec![0u8, 0, 0];
355 let mut patch1_data = PatchDataBuilder::new(); 362 let mut patch1_data = PatchDataBuilder::new();
356 patch1_data.replace(0, 3, &[1, 3, 3, 4]); 363 patch1_data.replace(0, 3, &[1, 3, 3, 4]);
357 let mut patch1 = PatchList::new(patch1_data.get()); 364 let mut patch1 = PatchList::new(patch1_data.get()).unwrap();
358 365
359 let mut patch2_data = PatchDataBuilder::new(); 366 let mut patch2_data = PatchDataBuilder::new();
360 patch2_data.replace(1, 3, &[2, 3]); 367 patch2_data.replace(1, 3, &[2, 3]);
361 let mut patch2 = PatchList::new(patch2_data.get()); 368 let mut patch2 = PatchList::new(patch2_data.get()).unwrap();
362 369
363 let patch = patch1.combine(&mut patch2); 370 let patch = patch1.combine(&mut patch2);
364 371
365 let result = patch.apply(&data); 372 let mut buffer = CoreRevisionBuffer::new();
366 373 patch.apply(&mut buffer, &data);
367 assert_eq!(result, vec![1u8, 2, 3, 4]); 374
368 } 375 assert_eq!(buffer.finish(), vec![1u8, 2, 3, 4]);
369 } 376 }
377 }