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