1use std::io::{Read, Seek, Write};
2
3use smdiff_common::{Format, Run, MAX_INST_SIZE, MAX_WIN_SIZE};
4use smdiff_decoder::reader::SectionIterator;
5use smdiff_encoder::{writer::section_writer, SecondaryCompression};
6use smdiff_reader::Op;
7use smdiff_writer::make_sections;
8
9pub mod transcoder;
10pub type SparseOp = (u64, Op);
12
13impl MergeOp for Run {
14 fn skip(&mut self,amt:u32) {
15 self.len -= amt as u8;
16 }
17 fn trunc(&mut self,amt:u32) {
18 self.len -= amt as u8;
19 }
20}
21impl MergeOp for smdiff_common::Copy {
22 fn skip(&mut self,amt:u32) {
23 self.addr += amt as u64;
24 self.len -= amt as u16;
25 }
26 fn trunc(&mut self,amt:u32) {
27 self.len -= amt as u16;
28 }
29}
30impl MergeOp for smdiff_reader::Add {
31 fn skip(&mut self,amt:u32){
32 self.bytes = self.bytes.split_off(amt as usize);
33 }
34 fn trunc(&mut self,amt:u32){
35 self.bytes.truncate(self.bytes.len() - amt as usize);
36 }
37}
38impl MergeOp for Op{
39 fn skip(&mut self,amt:u32){
40 match self {
41 Op::Run(run) => run.skip(amt),
42 Op::Copy(copy) => copy.skip(amt),
43 Op::Add(add) => add.skip(amt),
44 }
45 }
46 fn trunc(&mut self,amt:u32){
47 match self {
48 Op::Run(run) => run.trunc(amt),
49 Op::Copy(copy) => copy.trunc(amt),
50 Op::Add(add) => add.trunc(amt),
51 }
52 }
53}
54
55pub trait MergeOp:Clone+Sized{
56 fn skip(&mut self,amt:u32);
58 fn trunc(&mut self,amt:u32);
60}
61
62pub fn find_controlling_op(ops:&[SparseOp],o_pos:u64)->Option<usize>{
69 let inst = ops.binary_search_by(|probe|{
70 let end = probe.0 + probe.1.oal() as u64;
71 if (probe.0..end).contains(&o_pos){
72 return std::cmp::Ordering::Equal
73 }else if probe.0 > o_pos {
74 return std::cmp::Ordering::Greater
75 }else{
76 return std::cmp::Ordering::Less
77 }
78 });
79 if let Ok(idx) = inst {
80 Some(idx)
81 }else {
82 None
83 }
84}
85
86pub fn get_exact_slice(ops:&[SparseOp],start:u64,len:u32)->Option<Vec<SparseOp>>{
97 let start_idx = find_controlling_op(ops,start)?;
98 let end_pos = start + len as u64;
99 let mut slice = Vec::new();
100 let mut complete = false;
101
102 for (o_start, inst) in ops[start_idx..].iter() {
103 let inst_len = inst.oal();
104 let cur_inst_end = o_start + inst_len as u64;
105 let mut cur_inst = inst.clone();
106 let op_start = if &start > o_start {
107 let skip = start - o_start;
108 cur_inst.skip(skip as u32);
109 start
110 }else{*o_start};
111 if end_pos < cur_inst_end {
112 let trunc = cur_inst_end - end_pos;
113 cur_inst.trunc(trunc as u32);
114 }
115 debug_assert!(cur_inst.oal() > 0, "The instruction length is zero");
116 slice.push((op_start,cur_inst));
117
118 if cur_inst_end >= end_pos {
119 complete = true;
120 break;
122 }
123 }
124 if !complete {
125 return None;
126 }
127 Some(slice)
128}
129
130#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
133pub struct Stats{
134 pub add_bytes:usize,
135 pub run_bytes:usize,
136 pub copy_bytes:usize,
137 pub add_cnt:usize,
138 pub run_cnt:usize,
139 pub copy_d_cnt:usize,
140 pub copy_o_cnt:usize,
141 pub output_size:usize,
142}
143
144impl Stats {
145 pub fn new() -> Self {
146 Default::default()
147 }
148 pub fn add(&mut self, len:usize){
149 self.add_bytes += len;
150 self.add_cnt += 1;
151 self.output_size += len;
152 }
153 pub fn run(&mut self, len:usize){
154 self.run_bytes += len;
155 self.run_cnt += 1;
156 self.output_size += len;
157 }
158 pub fn copy_d(&mut self, len:usize){
159 self.copy_bytes += len;
160 self.copy_d_cnt += 1;
161 self.output_size += len;
162 }
163 pub fn copy_o(&mut self, len:usize){
164 self.copy_bytes += len;
165 self.copy_o_cnt += 1;
166 self.output_size += len;
167 }
168 pub fn has_copy(&self)->bool{
169 self.copy_bytes > 0
170 }
171}
172
173pub fn extract_patch_instructions<R:Read + Seek>(patch:R)->std::io::Result<(Vec<SparseOp>, Stats)>{
176 let mut output = Vec::new();
177 let mut reader = SectionIterator::new(patch);
178 let mut o_pos_start = 0;
179 let mut stats = Stats::new();
180 while let Some(res) = reader.next() {
181 let (insts,_output_size) = res?;
182 for inst in insts{
183 let oal_len = inst.oal() as usize;
184 match &inst{
185 smdiff_common::Op::Run(_) => {
186 output.push((o_pos_start,inst));
187 stats.run(oal_len);
188 },
189 smdiff_common::Op::Copy(c) => {
190 match c.src{
191 smdiff_common::CopySrc::Dict => {
192 stats.copy_d(oal_len);
193 },
194 smdiff_common::CopySrc::Output => {
195 stats.copy_o(oal_len);
196 },
197 }
198 output.push((o_pos_start,inst));
199 stats.copy_d(oal_len);
200
201 },
202 smdiff_common::Op::Add(_) => {
203 output.push((o_pos_start,inst));
204 stats.add(oal_len);
205 },
206 }
207 o_pos_start += oal_len as u64;
208 }
209 }
210
211 Ok((output,stats))
212}
213
214pub fn deref_copy_o(extracted:Vec<SparseOp>)->Vec<SparseOp>{
216 let mut output:Vec<SparseOp> = Vec::with_capacity(extracted.len());
222 let mut cur_o_pos = 0;
223 for (_,op) in extracted {
224 match op {
225 Op::Copy(copy) if matches!(copy.src, smdiff_common::CopySrc::Output) => {
226 let o_start = copy.addr;
228 let resolved = get_exact_slice(output.as_slice(), o_start, copy.len as u32).unwrap();
229 for (_,resloved_op) in resolved {
230 let o_pos_start = cur_o_pos;
231 cur_o_pos += resloved_op.oal() as u64;
232 output.push((o_pos_start,resloved_op));
233 }
234 },
235 _ => {
236 let o_pos_start = cur_o_pos;
237 cur_o_pos += op.oal() as u64;
238 output.push((o_pos_start,op))
239
240 },
241 }
242 }
243 output
244}
245
246fn find_mergeable_copies(extract:&[SparseOp],shift:usize,dest:&mut Vec<usize>){
247 for (i,(_,op)) in extract.iter().enumerate(){
248 match op {
249 Op::Copy(copy) if matches!(copy.src, smdiff_common::CopySrc::Dict) => {
250 dest.push(i+shift);
251 },
252 _ => (),
253 }
254 }
255}
256#[derive(Clone, Debug)]
258pub struct Merger{
259 terminal_patch: Vec<SparseOp>,
261 terminal_copy_indices: Vec<usize>,
264 }
266
267impl Merger {
268 pub fn new<R:Read + Seek>(terminal_patch:R) -> std::io::Result<Result<Merger,SummaryPatch>> {
276 let (terminal_patch,stats) = extract_patch_instructions(terminal_patch)?;
277 if stats.copy_bytes == 0{
278 return Ok(Err(SummaryPatch(terminal_patch.into_iter().map(|s|s.1).collect())));
279 }
280 let mut terminal_copy_indices = Vec::new();
281 let terminal_patch = deref_copy_o(terminal_patch);
284 find_mergeable_copies(&terminal_patch,0,&mut terminal_copy_indices);
285 debug_assert!(!terminal_copy_indices.is_empty(), "terminal_copy_indices should not be empty");
286 Ok(Ok(Merger{
287 terminal_patch,
288 terminal_copy_indices,
289 }))
291 }
292 pub fn merge<R:Read + Seek>(mut self, predecessor_patch:R) -> std::io::Result<Result<Merger,SummaryPatch>> {
300 debug_assert!({
301 let mut x = 0;
302 for inst in self.terminal_patch.iter(){
303 assert_eq!(x,inst.0);
304 x += inst.1.oal() as u64;
305 }
306 true
307 });
308 let (mut predecessor_patch,stats) = extract_patch_instructions(predecessor_patch)?;
309 if stats.has_copy(){
310 predecessor_patch = deref_copy_o(predecessor_patch);
311 }
312 let mut terminal_copy_indices = Vec::with_capacity(self.terminal_copy_indices.len());
313 let mut inserts = Vec::with_capacity(self.terminal_copy_indices.len());
314 let mut shift = 0;
315 for i in self.terminal_copy_indices{
316 let (_,op) = self.terminal_patch[i].clone();
317 let copy = op.take_copy().expect("Expected Copy");
318 debug_assert!(matches!(copy.src, smdiff_common::CopySrc::Dict));
320 let o_start = copy.addr; let resolved = get_exact_slice(&predecessor_patch, o_start, copy.len as u32).unwrap();
322 find_mergeable_copies(&resolved, i+shift, &mut terminal_copy_indices);
324 shift += resolved.len() - 1;
325 inserts.push((i, resolved));
326
327 }
328 if terminal_copy_indices.is_empty(){
331
332 Ok(Err(SummaryPatch(expand_to(self.terminal_patch, inserts, |s|s.1))))
333 }else{
334 self.terminal_patch = expand_to(self.terminal_patch, inserts, |s|s);
335 self.terminal_copy_indices = terminal_copy_indices;
336 Ok(Ok(self))
337 }
338 }
339 pub fn finish(self)->SummaryPatch{
341 SummaryPatch(self.terminal_patch.into_iter().map(|s|s.1).collect())
342 }
343
344}
345
346#[derive(Debug)]
348pub struct SummaryPatch(Vec<Op>);
349impl SummaryPatch{
350 pub fn write<W:Write>(self,sink:&mut W,max_win_size:Option<usize>,format:Option<Format>,sec_comp:Option<SecondaryCompression>)->std::io::Result<()>{
357 let max_win_size = max_win_size.unwrap_or(MAX_WIN_SIZE).min(MAX_WIN_SIZE).max(MAX_INST_SIZE);
359 let format = format.unwrap_or(Format::Interleaved);
360 let mut sec_data_buffer = Vec::new();
361 for (seg_ops,mut header) in make_sections(&self.0, max_win_size){
362 header.format = format;
363 section_writer(&sec_comp, header, sink, seg_ops, &mut sec_data_buffer)?;
364 }
365 Ok(())
366 }
367 pub fn take_ops(self)->Vec<Op>{
370 self.0
371 }
372}
373
374fn expand_to<T, F>(
377 mut target: Vec<SparseOp>,
378 inserts: Vec<(usize, Vec<SparseOp>)>,
379 mut converter: F,
380) -> Vec<T>
381where
382 F: FnMut(SparseOp) -> T,
383{
384 let total_insertions: usize = inserts.iter().map(|(_, ins)| ins.len()).sum();
386 let final_length = target.len() + total_insertions;
387
388 let mut result = Vec::with_capacity(final_length);
390
391 let mut sorted_inserts = inserts;
393 sorted_inserts.sort_by_key(|k| k.0);
394
395 target.reverse();
396 let mut cur_idx = 0;
398 let mut cur_o_pos = 0;
399 for (insert_pos, insert_vec) in sorted_inserts {
400 while cur_idx < insert_pos {
402 match target.pop() {
403 Some(mut elem) => {
404 let len = elem.1.oal();
405 elem.0 = cur_o_pos;
406 cur_o_pos += len as u64;
407 result.push(converter(elem));
408 cur_idx += 1;
409 }
410 None => break,
411 }
412 }
413 for mut elem in insert_vec {
415 let len = elem.1.oal();
416 elem.0 = cur_o_pos;
417 cur_o_pos += len as u64;
418 result.push(converter(elem));
419 }
420 target.pop();cur_idx += 1;
422 }
423
424 while let Some(mut elem) = target.pop() {
426 let len = elem.1.oal();
427 elem.0 = cur_o_pos;
428 cur_o_pos += len as u64;
429 result.push(converter(elem));
430 }
431 result
432
433}
434
435
436
437#[cfg(test)]
438mod test_super {
439
440 use smdiff_common::{Copy, CopySrc, SectionHeader};
441 use smdiff_decoder::apply_patch;
442 use smdiff_reader::Add;
443 use super::*;
444 use std::io::Cursor;
471 fn copy_patch() -> Cursor<Vec<u8>> {
472 let mut sink = Cursor::new(Vec::new());
473 let header = SectionHeader {
474 num_operations:2,
475 num_add_bytes: 0,
476 output_size: 10,
477 compression_algo: 0,
478 format: Format::Interleaved,
479 more_sections: false,
480
481 };
482 smdiff_writer::write_section_header(&header, &mut sink).unwrap();
483 let ops = &[
484 Op::Copy(Copy { src: CopySrc::Dict, addr: 0, len: 5}),
485 Op::Copy(Copy { src: CopySrc::Dict, addr: 0, len: 5}),
486 ];
487 smdiff_writer::write_ops(ops, &header,&mut sink).unwrap();
488 sink.rewind().unwrap();
489 sink
490 }
491 fn add_run_patch() -> Cursor<Vec<u8>> {
492 let mut sink = Cursor::new(Vec::new());
493 let header = SectionHeader {
494 num_operations:5,
495 num_add_bytes: 0,
496 output_size: 10,
497 compression_algo: 0,
498 format: Format::Interleaved,
499 more_sections: false,
500
501 };
502 smdiff_writer::write_section_header(&header, &mut sink).unwrap();
503 let ops = &[
504 Op::Add(Add{bytes:b"A".to_vec()}),
505 Op::Copy(Copy { src: CopySrc::Dict, addr: 1, len: 2}),
506 Op::Run(Run { byte: b'X', len: 3}),
507 Op::Add(Add{bytes:b"YZ".to_vec()}),
508 Op::Copy(Copy { src: CopySrc::Dict, addr: 3, len: 2}),
509 ];
510 smdiff_writer::write_ops(ops, &header,&mut sink).unwrap();
511 sink.rewind().unwrap();
512 sink
513 }
514 fn complex_patch()->Cursor<Vec<u8>>{
515 let mut sink = Cursor::new(Vec::new());
516 let header = SectionHeader {
517 num_operations:5,
518 num_add_bytes: 0,
519 output_size: 10,
520 compression_algo: 0,
521 format: Format::Interleaved,
522 more_sections: false,
523
524 };
525 smdiff_writer::write_section_header(&header, &mut sink).unwrap();
526 let ops = &[
527 Op::Add(Add{bytes:b"Y".to_vec()}),
528 Op::Run(Run { byte: b'Z', len: 2}),
529 Op::Copy(Copy { src: CopySrc::Dict, addr: 4, len: 1}),
530 Op::Copy(Copy { src: CopySrc::Output, addr: 2, len: 2}),
531 Op::Copy(Copy { src: CopySrc::Dict, addr: 1, len: 4}),
532 ];
533 smdiff_writer::write_ops(ops, &header,&mut sink).unwrap();
534 sink.rewind().unwrap();
535 sink
536 }
537 const SRC:&[u8] = b"01234";
538 #[test]
539 fn test_copy_add(){
540 let answer = b"A12XXXYZ34";
542 let copy = copy_patch();
543 let add_run = add_run_patch();
544 let merger = Merger::new(add_run).unwrap().unwrap();
545 let merger = merger.merge(copy).unwrap().unwrap();
546 let mut merged_patch = Vec::new();
547 merger.finish().write(&mut merged_patch, None,None,None).unwrap();
548 let mut cursor = Cursor::new(merged_patch);
549 let mut output = Cursor::new(Vec::new());
550 apply_patch(&mut cursor, Some(&mut Cursor::new(SRC.to_vec())), &mut output).unwrap();
551 let output = output.into_inner();
553 let as_str = std::str::from_utf8(&output).unwrap();
554 println!("{}",as_str);
555 assert_eq!(output,answer);
556 }
557 #[test]
558 fn test_add_copy(){
559 let answer = b"A12XXA12XX";
561 let copy = copy_patch();
562 let add_run = add_run_patch();
563 let merger = Merger::new(copy).unwrap().unwrap();
564 let merger = merger.merge(add_run).unwrap().unwrap();
565 let mut merged_patch = Vec::new();
566 merger.finish().write(&mut merged_patch, None,None,None).unwrap();
567 let mut cursor = Cursor::new(merged_patch);
568 let mut output = Cursor::new(Vec::new());
569 apply_patch(&mut cursor, Some(&mut Cursor::new(SRC.to_vec())), &mut output).unwrap();
570 let output = output.into_inner();
572 let as_str = std::str::from_utf8(&output).unwrap();
573 println!("{}",as_str);
574 assert_eq!(output,answer);
575 }
576 #[test]
577 fn test_add_complex(){
578 let answer = b"YZZXZX12XX";
580 let add_run = add_run_patch();
581 let comp = complex_patch();
582 let merger = Merger::new(comp).unwrap().unwrap();
583 let merger = merger.merge(add_run).unwrap().unwrap();
584 let mut merged_patch = Vec::new();
585 merger.finish().write(&mut merged_patch, None,None,None).unwrap();
586 let mut cursor = Cursor::new(merged_patch);
587 let mut output = Cursor::new(Vec::new());
588 apply_patch(&mut cursor, Some(&mut Cursor::new(SRC.to_vec())), &mut output).unwrap();
589 let output = output.into_inner();
591 let as_str = std::str::from_utf8(&output).unwrap();
592 println!("{}",as_str);
593 assert_eq!(output,answer);
594 }
595 #[test]
596 fn test_complex_add(){
597 let answer = b"AZZXXXYZ4Z";
599 let add_run = add_run_patch();
600 let comp = complex_patch();
601 let merger = Merger::new(add_run).unwrap().unwrap();
602 let merger = merger.merge(comp).unwrap().unwrap();
603 let mut merged_patch = Vec::new();
604 merger.finish().write(&mut merged_patch, None,None,None).unwrap();
605 let mut cursor = Cursor::new(merged_patch);
606 let mut output = Cursor::new(Vec::new());
607 apply_patch(&mut cursor, Some(&mut Cursor::new(SRC.to_vec())), &mut output).unwrap();
608 let output = output.into_inner();
610 let as_str = std::str::from_utf8(&output).unwrap();
611 println!("{}",as_str);
612 assert_eq!(output,answer);
613 }
614 #[test]
615 fn test_all_seq(){
616 let answer = b"YZZXZYZZXZ";
618 let add_run = add_run_patch();
619 let comp = complex_patch();
620 let copy = copy_patch();
621 let merger = Merger::new(copy).unwrap().unwrap();
622 let merger = merger.merge(comp).unwrap().unwrap();
623 let merger = merger.merge(add_run).unwrap().unwrap_err();
624 let mut merged_patch = Vec::new();
625 merger.write(&mut merged_patch, None,None,None).unwrap();
626 let mut cursor = Cursor::new(merged_patch);
627 let mut output = Cursor::new(Vec::new());
628 apply_patch::<_, Cursor<Vec<u8>>,_>(&mut cursor, None, &mut output).unwrap();
630 let output = output.into_inner();
632 let as_str = std::str::from_utf8(&output).unwrap();
633 println!("{}",as_str);
634 assert_eq!(output,answer);
635 }
636 #[test]
637 fn test_kitchen_sink(){
638 let src = b"hello!";
642 let mut sink = Cursor::new(Vec::new());
643 let header = SectionHeader {
644 num_operations:1,
645 num_add_bytes: 0,
646 output_size: 5,
647 compression_algo: 0,
648 format: Format::Interleaved,
649 more_sections: true,
650
651 };
652 smdiff_writer::write_section_header(&header, &mut sink).unwrap();
653 let ops = &[
654 Op::Copy(Copy { src: CopySrc::Dict, addr: 0, len: 5}),
655 ];
656 smdiff_writer::write_ops(ops, &header,&mut sink).unwrap();
657
658 let header = SectionHeader {
659 num_operations:3,
660 num_add_bytes: 0,
661 output_size: 6,
662 compression_algo: 0,
663 format: Format::Interleaved,
664 more_sections: true,
665
666 };
667 smdiff_writer::write_section_header(&header, &mut sink).unwrap();
668 let ops = &[
669 Op::Add(Add{bytes:b" w".to_vec()}),
670 Op::Copy(Copy { src: CopySrc::Output, addr: 4, len: 1}),
671 Op::Add(Add{bytes:b"rld".to_vec()}),
672 ];
673 smdiff_writer::write_ops(ops, &header,&mut sink).unwrap();
674
675 let header = SectionHeader {
676 num_operations:1,
677 num_add_bytes: 0,
678 output_size: 1,
679 compression_algo: 0,
680 format: Format::Interleaved,
681 more_sections: false,
682
683 };
684 smdiff_writer::write_section_header(&header, &mut sink).unwrap();
685 let ops = &[
686 Op::Copy(Copy { src: CopySrc::Dict, addr: 5, len: 1}),
687 ];
688 smdiff_writer::write_ops(ops, &header,&mut sink).unwrap();
689 let p1 = sink.into_inner();
690 let p1_answer = b"hello world!";
691 let mut cursor = Cursor::new(p1.clone());
692 let mut output = Cursor::new(Vec::new());
693 apply_patch(&mut cursor, Some(&mut Cursor::new(src.to_vec())), &mut output).unwrap();
694 let output = output.into_inner();
695 println!("{}",std::str::from_utf8(&output).unwrap());
696 assert_eq!(output,p1_answer); let patch_1 = Cursor::new(p1);
698 let mut sink = Cursor::new(Vec::new());
699
700 let header = SectionHeader {
701 num_operations:4,
702 num_add_bytes: 0,
703 output_size: 7,
704 compression_algo: 0,
705 format: Format::Interleaved,
706 more_sections: true,
707
708 };
709 smdiff_writer::write_section_header(&header, &mut sink).unwrap();
710 let ops = &[
711 Op::Add(Add{bytes:b"H".to_vec()}),
712 Op::Copy(Copy { src: CopySrc::Dict, addr: 1, len: 4}), Op::Copy(Copy { src: CopySrc::Dict, addr: 11, len: 1}), Op::Copy(Copy { src: CopySrc::Dict, addr: 5, len: 1}), ];
716 smdiff_writer::write_ops(ops, &header,&mut sink).unwrap();
717
718 let header = SectionHeader {
719 num_operations:4,
720 num_add_bytes: 0,
721 output_size: 14,
722 compression_algo: 0,
723 format: Format::Interleaved,
724 more_sections: true,
725
726 };
727 smdiff_writer::write_section_header(&header, &mut sink).unwrap();
728 let ops = &[
729 Op::Copy(Copy { src: CopySrc::Output, addr: 0, len: 7}), Op::Copy(Copy { src: CopySrc::Output, addr: 7, len: 5}), Op::Add(Add{bytes:b".".to_vec()}),
732 Op::Copy(Copy { src: CopySrc::Output, addr: 13, len: 1}), ];
734 smdiff_writer::write_ops(ops, &header,&mut sink).unwrap();
735
736 let header = SectionHeader {
737 num_operations:2,
738 num_add_bytes: 0,
739 output_size: 7,
740 compression_algo: 0,
741 format: Format::Interleaved,
742 more_sections: true,
743
744 };
745 smdiff_writer::write_section_header(&header, &mut sink).unwrap();
746 let ops = &[
747 Op::Add(Add{bytes:b"h".to_vec()}),
748 Op::Copy(Copy { src: CopySrc::Output, addr: 15, len: 6}), ];
750 smdiff_writer::write_ops(ops, &header,&mut sink).unwrap();
751
752 let header = SectionHeader {
753 num_operations:2,
754 num_add_bytes: 0,
755 output_size: 8,
756 compression_algo: 0,
757 format: Format::Interleaved,
758 more_sections: false,
759
760 };
761 smdiff_writer::write_section_header(&header, &mut sink).unwrap();
762 let ops = &[
763 Op::Copy(Copy { src: CopySrc::Output, addr: 21, len: 5}), Op::Run(Run { byte: b'.', len: 3}),
765 ];
766 smdiff_writer::write_ops(ops, &header,&mut sink).unwrap();
767 let p2 = sink.into_inner();
768 let p2_answer = b"Hello! Hello! Hello. hello. hello...";
769 let mut cursor = Cursor::new(p2.clone());
770 let mut output = Cursor::new(Vec::new());
771 apply_patch(&mut cursor, Some(&mut Cursor::new(p1_answer.to_vec())), &mut output).unwrap();
772 let output = output.into_inner();
773 println!("{}",std::str::from_utf8(&output).unwrap());
774 assert_eq!(output,p2_answer); let patch_2 = Cursor::new(p2);
776 let merger = Merger::new(patch_2).unwrap().unwrap();
777 let merger = merger.merge(patch_1).unwrap().unwrap();
778 let mut merged_patch = Vec::new();
779 merger.finish().write(&mut merged_patch, None,None,None).unwrap();
780 let mut cursor = Cursor::new(merged_patch);
781 let mut output = Cursor::new(Vec::new());
782 let answer = b"Hello! Hello! Hello. hello. hello...";
783 apply_patch(&mut cursor, Some(&mut Cursor::new(src.to_vec())), &mut output).unwrap();
784 let output = output.into_inner();
786 let as_str = std::str::from_utf8(&output).unwrap();
787 println!("{}",as_str);
788 assert_eq!(output,answer);
789
790 }
791
792}