patch_rs/context/
reduce.rs1use std::{
6 cmp,
7 collections::VecDeque
8};
9
10use log::*;
11
12use crate::{
13 context::{Context, ContextHeader},
14 line::Line,
15};
16
17enum FlipState {
18 StartContext,
19 Context,
20}
21
22impl Context {
23 pub fn reduce(&self, mut context_radius: usize) -> VecDeque<Self> {
24 context_radius = cmp::max(1, context_radius);
25 context_radius = cmp::min(context_radius, self.opening_context_size());
26
27 let mut results = VecDeque::new();
28
29 let mut output = Self::default();
30 output.header.file1_l = self.header.file1_l;
31 output.header.file2_l = self.header.file2_l;
32
33 let mut state = FlipState::StartContext;
34
35 trace!("START");
36 for line in self.data.iter() {
37 match line {
38 Line::Context(_) => {
39 match state {
40 FlipState::StartContext => {
41 trace!("Context StartContext");
42 while output.opening_context_size() >= context_radius {
43 output.data.pop();
44 output.header.file1_l += 1;
45 output.header.file2_l += 1;
46 trace!("POP START");
47 }
48 output.data.push(line.clone());
49 },
50 FlipState::Context => {
51 trace!("Context Context");
52 output.data.push(line.clone());
53 let lines = output.closing_context_size();
54 if lines > 2 * context_radius {
55 let mut data = Vec::new();
56 data.push(output.data.pop().unwrap());
57 for _ in context_radius*2..lines {
58 output.data.pop();
59 trace!("POP END");
60 }
61 output.update();
62
63 trace!("PUSH OUTPUT");
64 let output_next = Context {
65 header: ContextHeader {
66 file1_l: output.header.file1_l + output.header.file1_s + lines - 2,
67 file1_s: Default::default(),
68 file2_l: output.header.file2_l + output.header.file2_s + lines - 2,
69 file2_s: Default::default(),
70 },
71 data,
72 };
73
74 if output.has_changes() {
75 results.push_back(output);
76 }
77 output = output_next;
78 }
79 },
80 }
81 },
82 Line::Delete(_) | Line::Insert(_) => {
83 if let FlipState::StartContext = state {
84 state = FlipState::Context;
85 }
86 output.data.push(line.clone());
87 },
88 }
89 }
90
91 let lines = output.closing_context_size();
92 if lines > context_radius {
93 for _ in context_radius..lines {
94 output.data.pop();
95 trace!("POP END");
96 }
97 }
98
99 output.update();
100 if output.has_changes() {
101 results.push_back(output);
102 }
103
104 trace!("END");
105
106 results
107 }
108}