Mercurial > public > mercurial-scm > hg
diff 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 |
line wrap: on
line diff
--- a/rust/hg-core/src/revlog/patch.rs Thu Oct 10 10:38:35 2024 +0200 +++ b/rust/hg-core/src/revlog/patch.rs Thu Oct 10 10:34:51 2024 +0200 @@ -1,5 +1,9 @@ use byteorder::{BigEndian, ByteOrder}; +use crate::RevlogError; + +use super::inner_revlog::RevisionBuffer; + /// A chunk of data to insert, delete or replace in a patch /// /// A chunk is: @@ -61,14 +65,16 @@ impl<'a> PatchList<'a> { /// Create a `PatchList` from bytes. - pub fn new(data: &'a [u8]) -> Self { + pub fn new(data: &'a [u8]) -> Result<Self, RevlogError> { let mut chunks = vec![]; let mut data = data; while !data.is_empty() { let start = BigEndian::read_u32(&data[0..]); let end = BigEndian::read_u32(&data[4..]); let len = BigEndian::read_u32(&data[8..]); - assert!(start <= end); + if start > end { + return Err(RevlogError::corrupted("patch cannot be decoded")); + } chunks.push(Chunk { start, end, @@ -76,29 +82,23 @@ }); data = &data[12 + (len as usize)..]; } - PatchList { chunks } - } - - /// Return the final length of data after patching - /// given its initial length . - fn size(&self, initial_size: i32) -> i32 { - self.chunks - .iter() - .fold(initial_size, |acc, chunk| acc + chunk.len_diff()) + Ok(PatchList { chunks }) } /// Apply the patch to some data. - pub fn apply(&self, initial: &[u8]) -> Vec<u8> { + pub fn apply<T>( + &self, + buffer: &mut dyn RevisionBuffer<Target = T>, + initial: &[u8], + ) { let mut last: usize = 0; - let mut vec = - Vec::with_capacity(self.size(initial.len() as i32) as usize); for Chunk { start, end, data } in self.chunks.iter() { - vec.extend(&initial[last..(*start as usize)]); - vec.extend(data.iter()); + let slice = &initial[last..(*start as usize)]; + buffer.extend_from_slice(slice); + buffer.extend_from_slice(data); last = *end as usize; } - vec.extend(&initial[last..]); - vec + buffer.extend_from_slice(&initial[last..]); } /// Combine two patch lists into a single patch list. @@ -229,6 +229,8 @@ #[cfg(test)] mod tests { + use crate::inner_revlog::CoreRevisionBuffer; + use super::*; struct PatchDataBuilder { @@ -264,17 +266,18 @@ let data = vec![0u8, 0u8, 0u8]; let mut patch1_data = PatchDataBuilder::new(); patch1_data.replace(0, 1, &[1, 2]); - let mut patch1 = PatchList::new(patch1_data.get()); + let mut patch1 = PatchList::new(patch1_data.get()).unwrap(); let mut patch2_data = PatchDataBuilder::new(); patch2_data.replace(2, 4, &[3, 4]); - let mut patch2 = PatchList::new(patch2_data.get()); + let mut patch2 = PatchList::new(patch2_data.get()).unwrap(); let patch = patch1.combine(&mut patch2); - let result = patch.apply(&data); + let mut buffer = CoreRevisionBuffer::new(); + patch.apply(&mut buffer, &data); - assert_eq!(result, vec![1u8, 2, 3, 4]); + assert_eq!(buffer.finish(), vec![1u8, 2, 3, 4]); } #[test] @@ -282,17 +285,18 @@ let data = vec![0u8, 0u8, 0u8]; let mut patch1_data = PatchDataBuilder::new(); patch1_data.replace(2, 3, &[3]); - let mut patch1 = PatchList::new(patch1_data.get()); + let mut patch1 = PatchList::new(patch1_data.get()).unwrap(); let mut patch2_data = PatchDataBuilder::new(); patch2_data.replace(1, 2, &[1, 2]); - let mut patch2 = PatchList::new(patch2_data.get()); + let mut patch2 = PatchList::new(patch2_data.get()).unwrap(); let patch = patch1.combine(&mut patch2); - let result = patch.apply(&data); + let mut buffer = CoreRevisionBuffer::new(); + patch.apply(&mut buffer, &data); - assert_eq!(result, vec![0u8, 1, 2, 3]); + assert_eq!(buffer.finish(), vec![0u8, 1, 2, 3]); } #[test] @@ -300,17 +304,18 @@ let data = vec![0u8, 0, 0]; let mut patch1_data = PatchDataBuilder::new(); patch1_data.replace(1, 2, &[3, 4]); - let mut patch1 = PatchList::new(patch1_data.get()); + let mut patch1 = PatchList::new(patch1_data.get()).unwrap(); let mut patch2_data = PatchDataBuilder::new(); patch2_data.replace(1, 4, &[1, 2, 3]); - let mut patch2 = PatchList::new(patch2_data.get()); + let mut patch2 = PatchList::new(patch2_data.get()).unwrap(); let patch = patch1.combine(&mut patch2); - let result = patch.apply(&data); + let mut buffer = CoreRevisionBuffer::new(); + patch.apply(&mut buffer, &data); - assert_eq!(result, vec![0u8, 1, 2, 3]); + assert_eq!(buffer.finish(), vec![0u8, 1, 2, 3]); } #[test] @@ -318,17 +323,18 @@ let data = vec![0u8, 0, 0]; let mut patch1_data = PatchDataBuilder::new(); patch1_data.replace(0, 1, &[1, 3]); - let mut patch1 = PatchList::new(patch1_data.get()); + let mut patch1 = PatchList::new(patch1_data.get()).unwrap(); let mut patch2_data = PatchDataBuilder::new(); patch2_data.replace(1, 4, &[2, 3, 4]); - let mut patch2 = PatchList::new(patch2_data.get()); + let mut patch2 = PatchList::new(patch2_data.get()).unwrap(); let patch = patch1.combine(&mut patch2); - let result = patch.apply(&data); + let mut buffer = CoreRevisionBuffer::new(); + patch.apply(&mut buffer, &data); - assert_eq!(result, vec![1u8, 2, 3, 4]); + assert_eq!(buffer.finish(), vec![1u8, 2, 3, 4]); } #[test] @@ -336,17 +342,18 @@ let data = vec![0u8, 0, 0]; let mut patch1_data = PatchDataBuilder::new(); patch1_data.replace(1, 3, &[1, 3, 4]); - let mut patch1 = PatchList::new(patch1_data.get()); + let mut patch1 = PatchList::new(patch1_data.get()).unwrap(); let mut patch2_data = PatchDataBuilder::new(); patch2_data.replace(0, 2, &[1, 2]); - let mut patch2 = PatchList::new(patch2_data.get()); + let mut patch2 = PatchList::new(patch2_data.get()).unwrap(); let patch = patch1.combine(&mut patch2); - let result = patch.apply(&data); + let mut buffer = CoreRevisionBuffer::new(); + patch.apply(&mut buffer, &data); - assert_eq!(result, vec![1u8, 2, 3, 4]); + assert_eq!(buffer.finish(), vec![1u8, 2, 3, 4]); } #[test] @@ -354,16 +361,17 @@ let data = vec![0u8, 0, 0]; let mut patch1_data = PatchDataBuilder::new(); patch1_data.replace(0, 3, &[1, 3, 3, 4]); - let mut patch1 = PatchList::new(patch1_data.get()); + let mut patch1 = PatchList::new(patch1_data.get()).unwrap(); let mut patch2_data = PatchDataBuilder::new(); patch2_data.replace(1, 3, &[2, 3]); - let mut patch2 = PatchList::new(patch2_data.get()); + let mut patch2 = PatchList::new(patch2_data.get()).unwrap(); let patch = patch1.combine(&mut patch2); - let result = patch.apply(&data); + let mut buffer = CoreRevisionBuffer::new(); + patch.apply(&mut buffer, &data); - assert_eq!(result, vec![1u8, 2, 3, 4]); + assert_eq!(buffer.finish(), vec![1u8, 2, 3, 4]); } }