@@ -3,8 +3,11 @@ use std::cmp::{min, Ordering};
33use pinocchio:: program_error:: ProgramError ;
44use rkyv:: util:: AlignedVec ;
55
6+ use crate :: error:: DlpError ;
7+
68use super :: {
7- DiffSet , SizeChanged , SIZE_OF_CHANGED_LEN , SIZE_OF_NUM_OFFSET_PAIRS , SIZE_OF_SINGLE_OFFSET_PAIR ,
9+ DiffSet , OffsetInData , SizeChanged , SIZE_OF_CHANGED_LEN , SIZE_OF_NUM_OFFSET_PAIRS ,
10+ SIZE_OF_SINGLE_OFFSET_PAIR ,
811} ;
912
1013///
@@ -229,6 +232,35 @@ pub fn apply_diff_copy(original: &[u8], diffset: &DiffSet<'_>) -> Result<Vec<u8>
229232 } )
230233}
231234
235+ /// This function constructs destination by merging original with diff such that destination
236+ /// becomes the changed version of the original.
237+ ///
238+ /// Precondition:
239+ /// - destination.len() == original.len()
240+ pub fn merge_diff_copy (
241+ destination : & mut [ u8 ] ,
242+ original : & [ u8 ] ,
243+ diffset : & DiffSet < ' _ > ,
244+ ) -> Result < ( ) , ProgramError > {
245+ if destination. len ( ) != original. len ( ) {
246+ return Err ( DlpError :: MergeDiffError . into ( ) ) ;
247+ }
248+ let mut write_index = 0 ;
249+ for item in diffset. iter ( ) {
250+ let ( diff_segment, OffsetInData { start, end } ) = item?;
251+ if write_index < start {
252+ // copy the unchanged bytes
253+ destination[ write_index..start] . copy_from_slice ( & original[ write_index..start] ) ;
254+ }
255+ destination[ start..end] . copy_from_slice ( diff_segment) ;
256+ write_index = end;
257+ }
258+ if write_index < original. len ( ) {
259+ destination[ write_index..] . copy_from_slice ( & original[ write_index..] ) ;
260+ }
261+ Ok ( ( ) )
262+ }
263+
232264// private function that does the actual work.
233265fn apply_diff_impl ( original : & mut [ u8 ] , diffset : & DiffSet < ' _ > ) -> Result < ( ) , ProgramError > {
234266 for item in diffset. iter ( ) {
@@ -247,7 +279,7 @@ mod tests {
247279 Rng , RngCore , SeedableRng ,
248280 } ;
249281
250- use crate :: { apply_diff_copy, apply_diff_in_place, compute_diff, DiffSet } ;
282+ use crate :: { apply_diff_copy, apply_diff_in_place, compute_diff, merge_diff_copy , DiffSet } ;
251283
252284 #[ test]
253285 fn test_no_change ( ) {
@@ -311,6 +343,14 @@ mod tests {
311343 let expected_changed = apply_diff_copy ( & original, & actual_diffset) . unwrap ( ) ;
312344
313345 assert_eq ! ( changed. as_slice( ) , expected_changed. as_slice( ) ) ;
346+
347+ let expected_changed = {
348+ let mut destination = vec ! [ 255 ; original. len( ) ] ;
349+ merge_diff_copy ( & mut destination, & original, & actual_diffset) . unwrap ( ) ;
350+ destination
351+ } ;
352+
353+ assert_eq ! ( changed. as_slice( ) , expected_changed. as_slice( ) ) ;
314354 }
315355
316356 #[ test]
@@ -394,11 +434,19 @@ mod tests {
394434
395435 // apply diff back to verify correctness
396436 let expected_changed = {
397- let mut copy = original;
437+ let mut copy = original. clone ( ) ;
398438 apply_diff_in_place ( & mut copy, & actual_diffset) . unwrap ( ) ;
399439 copy
400440 } ;
401441
402442 assert_eq ! ( changed, expected_changed) ;
443+
444+ let expected_changed = {
445+ let mut destination = vec ! [ 255 ; original. len( ) ] ;
446+ merge_diff_copy ( & mut destination, & original, & actual_diffset) . unwrap ( ) ;
447+ destination
448+ } ;
449+
450+ assert_eq ! ( changed, expected_changed) ;
403451 }
404452}
0 commit comments