Coverage Report

Created: 2026-03-11 07:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/dmp-0.2.3/src/lib.rs
Line
Count
Source
1
mod diff;
2
#[cfg(any(test, fuzzing))]
3
pub mod fuzz;
4
mod patch;
5
6
pub use crate::diff::Diff;
7
pub use crate::patch::Patch;
8
use core::char;
9
use std::collections::HashMap;
10
use std::iter::FromIterator;
11
use std::result::Result;
12
use trice::Instant;
13
use urlencoding::decode;
14
15
pub enum LengthUnit {
16
  UnicodeScalar,
17
  UTF16,
18
}
19
20
pub struct Dmp {
21
  /// Number of seconds to map a diff before giving up (None for infinity).
22
  pub diff_timeout: Option<f32>,
23
  /// Cost of an empty edit operation in terms of edit characters.
24
  pub edit_cost: i32,
25
  /// How far to search for a match (0 = exact location, 1000+ = broad match).
26
  /// A match this many characters away from the expected location will add
27
  /// 1.0 to the score (0.0 is a perfect match).
28
  pub match_distance: i32,
29
  /// Chunk size for context length.
30
  pub patch_margin: i32,
31
  /// The number of bits in an int.
32
  /// Python has no maximum, thus to disable patch splitting set to 0.
33
  /// However to avoid long patches in certain pathological cases, use 32.
34
  /// Multiple short patches (using native ints) are much faster than long ones.
35
  pub match_maxbits: i32,
36
  /// At what point is no match declared (0.0 = perfection, 1.0 = very loose).
37
  pub match_threshold: f32,
38
  /// When deleting a large block of text (over ~64 characters), how close do
39
  /// the contents have to be to match the expected contents. (0.0 = perfection,
40
  /// 1.0 = very loose). Note that match_threshold controls how closely the
41
  /// end points of a delete need to match.
42
  pub patch_delete_threshold: f32,
43
}
44
45
0
pub fn new() -> Dmp {
46
0
  Dmp::default()
47
0
}
48
49
#[derive(Debug)]
50
pub enum Error {
51
  InvalidInput,
52
  MalformedPatch,
53
  PatternTooLong,
54
}
55
56
0
fn min(x: i32, y: i32) -> i32 {
57
0
  x.min(y)
58
0
}
59
60
0
fn min1(x: f32, y: f32) -> f32 {
61
  // return minimum element.
62
0
  if x > y {
63
0
    return y;
64
0
  }
65
0
  x
66
0
}
67
68
0
fn max(x: i32, y: i32) -> i32 {
69
0
  x.max(y)
70
0
}
71
72
/// Returns the first index of a character after a index or return -1 if not found.
73
0
fn find_char(cha: char, text: &[char], start: usize) -> i32 {
74
0
  for (i, text_item) in text.iter().enumerate().skip(start) {
75
0
    if *text_item == cha {
76
0
      return i as i32;
77
0
    }
78
  }
79
0
  -1
80
0
}
81
82
impl Default for Dmp {
83
0
  fn default() -> Self {
84
0
    Dmp {
85
0
      diff_timeout: None,
86
0
      patch_delete_threshold: 0.5,
87
0
      edit_cost: 0,
88
0
      match_distance: 1000,
89
0
      patch_margin: 4,
90
0
      match_maxbits: 32,
91
0
      match_threshold: 0.5,
92
0
    }
93
0
  }
94
}
95
96
impl Dmp {
97
  /// Find the differences between two chars.  Simplifies the problem by
98
  /// stripping any common prefix or suffix off the texts before diffing.
99
  ///
100
  /// # Args
101
  /// - text1: Old chars to be diffed.
102
  /// - text2: New chars to be diffed.
103
  /// - checklines: Optional speedup flag. If present and false, then don't run
104
  ///   a line-level diff first to identify the changed areas.
105
  ///   Defaults to true, which does a faster, slightly less optimal diff.
106
  ///
107
  /// # Return
108
  /// Vector of diffs as changes.
109
0
  pub fn diff_main(&self, text1: &str, text2: &str, checklines: bool) -> Vec<Diff> {
110
0
    self.diff_main_internal(text1, text2, checklines, Instant::now())
111
0
  }
112
113
0
  fn diff_main_internal(
114
0
    &self,
115
0
    text1: &str,
116
0
    text2: &str,
117
0
    checklines: bool,
118
0
    start_time: Instant,
119
0
  ) -> Vec<Diff> {
120
    // check for empty text
121
0
    if text1.is_empty() && text2.is_empty() {
122
0
      return vec![];
123
0
    } else if text1.is_empty() {
124
0
      return vec![Diff::new(1, text2.to_string())];
125
0
    } else if text2.is_empty() {
126
0
      return vec![Diff::new(-1, text1.to_string())];
127
0
    }
128
129
    // check for equality
130
0
    if text1 == text2 {
131
0
      return vec![Diff::new(0, text1.to_string())];
132
0
    }
133
134
0
    let mut char1: Vec<char> = text1.chars().collect();
135
0
    let mut char2: Vec<char> = text2.chars().collect();
136
    // Trim off common prefix (speedup).
137
0
    let mut commonlength = self.diff_common_prefix(&char1, &char2) as usize;
138
0
    let commonprefix = Vec::from_iter(char1[0..commonlength].iter().cloned());
139
0
    char1 = Vec::from_iter(char1[commonlength..].iter().cloned());
140
0
    char2 = Vec::from_iter(char2[commonlength..].iter().cloned());
141
142
    // Trim off common suffix (speedup).
143
0
    commonlength = self.diff_common_suffix(&char1, &char2) as usize;
144
0
    let commonsuffix =
145
0
      Vec::from_iter(char1[(char1.len() - commonlength)..char1.len()].iter().cloned());
146
0
    char1 = Vec::from_iter(char1[..(char1.len() - commonlength)].iter().cloned());
147
0
    char2 = Vec::from_iter(char2[..(char2.len() - commonlength)].iter().cloned());
148
0
    let mut diffs: Vec<Diff> = Vec::new();
149
150
    //Restore the prefix
151
0
    if !commonprefix.is_empty() {
152
0
      diffs.push(Diff::new(0, commonprefix.iter().collect()));
153
0
    }
154
155
    // Compute the diff on the middle block.
156
0
    let temp = self.diff_compute(&char1, &char2, checklines, start_time);
157
0
    for z in temp {
158
0
      diffs.push(z);
159
0
    }
160
161
    // Restore the suffix
162
0
    if !commonsuffix.is_empty() {
163
0
      diffs.push(Diff::new(0, commonsuffix.iter().collect()));
164
0
    }
165
0
    self.diff_cleanup_merge(&mut diffs);
166
0
    diffs
167
0
  }
168
169
  /// Find the differences between two texts.  Assumes that the texts do not
170
  /// have any common prefix or suffix.
171
  ///
172
  /// # Args
173
  /// - text1: Old chars to be diffed.
174
  /// - text2: New chars to be diffed.
175
  /// - checklines: Speedup flag.  If false, then don't run a line-level diff
176
  ///   first to identify the changed areas.
177
  ///   If true, then run a faster, slightly less optimal diff.
178
  ///
179
  /// # Return
180
  /// Vector of diffs as changes.
181
0
  fn diff_compute(
182
0
    &self,
183
0
    text1: &Vec<char>,
184
0
    text2: &Vec<char>,
185
0
    checklines: bool,
186
0
    start_time: Instant,
187
0
  ) -> Vec<Diff> {
188
0
    let mut diffs: Vec<Diff> = Vec::new();
189
0
    if text1.is_empty() {
190
      // Just add some text (speedup).
191
0
      diffs.push(Diff::new(1, text2.iter().collect()));
192
0
      return diffs;
193
0
    } else if text2.is_empty() {
194
      // Just delete some text (speedup).
195
0
      diffs.push(Diff::new(-1, text1.iter().collect()));
196
0
      return diffs;
197
0
    }
198
    {
199
0
      let len1 = text1.len();
200
0
      let len2 = text2.len();
201
0
      let (longtext, shorttext) = if len1 >= len2 {
202
0
        (text1, text2)
203
      } else {
204
0
        (text2, text1)
205
      };
206
0
      let i = self.kmp(longtext, shorttext, 0);
207
0
      if i != -1 {
208
        // Shorter text is inside the longer text (speedup).
209
0
        if len1 > len2 {
210
0
          if i != 0 {
211
0
            diffs.push(Diff::new(-1, (text1[0..(i as usize)]).iter().collect()));
212
0
          }
213
0
          diffs.push(Diff::new(0, text2.iter().collect()));
214
0
          if i as usize + text2.len() != text1.len() {
215
0
            diffs.push(Diff::new(
216
0
              -1,
217
0
              text1[((i as usize) + text2.len())..].iter().collect(),
218
0
            ));
219
0
          }
220
        } else {
221
0
          if i != 0 {
222
0
            diffs.push(Diff::new(1, (text2[0..(i as usize)]).iter().collect()));
223
0
          }
224
0
          diffs.push(Diff::new(0, text1.iter().collect()));
225
0
          if (i as usize) + text1.len() != text2.len() {
226
0
            diffs.push(Diff::new(
227
0
              1,
228
0
              text2[((i as usize) + text1.len())..].iter().collect(),
229
0
            ));
230
0
          }
231
        }
232
0
        return diffs;
233
0
      }
234
0
      if shorttext.len() == 1 {
235
        // Single character string.
236
        // After the previous speedup, the character can't be an equality.
237
0
        diffs.push(Diff::new(-1, text1.iter().collect()));
238
0
        diffs.push(Diff::new(1, text2.iter().collect()));
239
0
        return diffs;
240
0
      }
241
    }
242
    // Check to see if the problem can be split in two.
243
0
    let hm = self.diff_half_match(text1, text2);
244
0
    if !hm.is_empty() {
245
      // A half-match was found, sort out the return data.
246
0
      let text1_a = hm[0].clone();
247
0
      let text1_b = hm[1].clone();
248
0
      let text2_a = hm[2].clone();
249
0
      let text2_b = hm[3].clone();
250
0
      let mid_common = hm[4].clone();
251
      // Send both pairs off for separate processing.
252
0
      let mut diffs_a =
253
0
        self.diff_main_internal(text1_a.as_str(), text2_a.as_str(), checklines, start_time);
254
0
      let diffs_b =
255
0
        self.diff_main_internal(text1_b.as_str(), text2_b.as_str(), checklines, start_time);
256
0
      diffs_a.push(Diff::new(0, mid_common));
257
      // Merge the result.
258
0
      for x in diffs_b {
259
0
        diffs_a.push(x);
260
0
      }
261
0
      return diffs_a;
262
0
    }
263
0
    if checklines && text1.len() > 100 && text2.len() > 100 {
264
0
      return self.diff_linemode_internal(text1, text2, start_time);
265
0
    }
266
0
    self.diff_bisect_internal(text1, text2, start_time)
267
0
  }
268
269
  /// Find the first index after a specific index in text1 where patern is present.
270
  ///
271
  /// # Args
272
  /// - text1: Parent chars.
273
  /// - text2: Patern chars.
274
  /// - ind: index after which we have to find the patern.
275
  ///
276
  /// # Returns
277
  /// the first index where pattern is found or -1 if not found.
278
0
  fn kmp(&self, text1: &[char], text2: &[char], ind: usize) -> i32 {
279
0
    if text2.is_empty() {
280
0
      return ind as i32;
281
0
    }
282
0
    if text1.is_empty() {
283
0
      return -1;
284
0
    }
285
0
    let len1 = text1.len();
286
0
    let len2 = text2.len();
287
0
    let mut patern: Vec<usize> = Vec::new();
288
0
    patern.push(0);
289
0
    let mut len = 0;
290
0
    let mut i = 1;
291
292
    // Preprocess the pattern
293
0
    while i < len2 {
294
0
      if text2[i] == text2[len] {
295
0
        len += 1;
296
0
        patern.push(len);
297
0
        i += 1;
298
0
      } else if len == 0 {
299
0
        patern.push(0);
300
0
        i += 1;
301
0
      } else {
302
0
        len = patern[len - 1];
303
0
      }
304
    }
305
0
    i = ind;
306
0
    len = 0;
307
0
    while i < len1 {
308
0
      if text1[i] == text2[len] {
309
0
        len += 1;
310
0
        i += 1;
311
0
        if len == len2 {
312
0
          return (i - len) as i32;
313
0
        }
314
0
      } else if len == 0 {
315
0
        i += 1;
316
0
      } else {
317
0
        len = patern[len - 1];
318
0
      }
319
    }
320
0
    -1
321
0
  }
322
323
  /// Find the last index before a specific index in text1 where patern is present.
324
  ///
325
  /// # Args
326
  /// - text1: Parent chars.
327
  /// - text2: Patern chars.
328
  /// - ind: index just before we have to find the patern.
329
  ///
330
  /// # Return
331
  /// The last index where patern is found or -1 if not found.
332
0
  fn rkmp(&self, text1: &[char], text2: &[char], ind: usize) -> i32 {
333
0
    if text2.is_empty() {
334
0
      return ind as i32;
335
0
    }
336
0
    if text1.is_empty() {
337
0
      return -1;
338
0
    }
339
0
    let len2 = text2.len();
340
0
    let mut patern: Vec<usize> = Vec::new();
341
0
    patern.push(0);
342
0
    let mut len = 0;
343
0
    let mut i = 1;
344
345
    // Preprocess the pattern
346
0
    while i < len2 {
347
0
      if text2[i] == text2[len] {
348
0
        len += 1;
349
0
        patern.push(len);
350
0
        i += 1;
351
0
      } else if len == 0 {
352
0
        patern.push(0);
353
0
        i += 1;
354
0
      } else {
355
0
        len = patern[len - 1];
356
0
      }
357
    }
358
0
    i = 0;
359
0
    len = 0;
360
0
    let mut ans: i32 = -1;
361
0
    while i <= ind {
362
0
      if text1[i] == text2[len] {
363
0
        len += 1;
364
0
        i += 1;
365
0
        if len == len2 {
366
0
          ans = (i - len) as i32;
367
0
          len = patern[len - 1];
368
0
        }
369
0
      } else if len == 0 {
370
0
        i += 1;
371
0
      } else {
372
0
        len = patern[len - 1];
373
0
      }
374
    }
375
0
    ans
376
0
  }
377
378
  // Do a quick line-level diff on both chars, then rediff the parts for
379
  // greater accuracy.
380
  // This speedup can produce non-minimal diffs.
381
  //
382
  // # Args
383
  // - text1: Old chars to be diffed.
384
  // - text2: New chars to be diffed.
385
  //
386
  // # Return
387
  // Vector of diffs as changes.
388
  //pub fn diff_linemode(&self, text1: &Vec<char>, text2: &Vec<char>) -> Vec<Diff> {
389
  //    self.diff_linemode_internal(text1, text2, Instant::now())
390
  //}
391
392
0
  fn diff_linemode_internal(
393
0
    &self,
394
0
    text1: &[char],
395
0
    text2: &[char],
396
0
    start_time: Instant,
397
0
  ) -> Vec<Diff> {
398
    // Scan the text on a line-by-line basis first.
399
0
    let (text3, text4, linearray) = self.diff_lines_tochars(text1, text2);
400
401
0
    let dmp = Dmp::default();
402
0
    let mut diffs: Vec<Diff> =
403
0
      dmp.diff_main_internal(text3.as_str(), text4.as_str(), false, start_time);
404
405
    // Convert the diff back to original text.
406
0
    self.diff_chars_tolines(&mut diffs, &linearray);
407
    // Eliminate freak matches (e.g. blank lines)
408
0
    self.diff_cleanup_semantic(&mut diffs);
409
410
    // Rediff any replacement blocks, this time character-by-character.
411
    // Add a dummy entry at the end.
412
0
    diffs.push(Diff::new(0, "".to_string()));
413
0
    let mut count_delete = 0;
414
0
    let mut count_insert = 0;
415
0
    let mut text_delete: String = "".to_string();
416
0
    let mut text_insert: String = "".to_string();
417
0
    let mut pointer = 0;
418
0
    let mut temp: Vec<Diff> = vec![];
419
0
    while pointer < diffs.len() {
420
0
      if diffs[pointer].operation == 1 {
421
0
        count_insert += 1;
422
0
        text_insert += diffs[pointer].text.as_str();
423
0
      } else if diffs[pointer].operation == -1 {
424
0
        count_delete += 1;
425
0
        text_delete += diffs[pointer].text.as_str();
426
0
      } else {
427
        // Upon reaching an equality, check for prior redundancies.
428
0
        if count_delete >= 1 && count_insert >= 1 {
429
          // Delete the offending records and add the merged ones.
430
0
          let sub_diff = self.diff_main_internal(
431
0
            text_delete.as_str(),
432
0
            text_insert.as_str(),
433
            false,
434
0
            start_time,
435
          );
436
0
          for z in sub_diff {
437
0
            temp.push(z);
438
0
          }
439
0
          temp.push(Diff::new(diffs[pointer].operation, diffs[pointer].text.clone()));
440
        } else {
441
0
          if !text_delete.is_empty() {
442
0
            temp.push(Diff::new(-1, text_delete));
443
0
          }
444
0
          if !text_insert.is_empty() {
445
0
            temp.push(Diff::new(1, text_insert));
446
0
          }
447
0
          temp.push(Diff::new(diffs[pointer].operation, diffs[pointer].text.clone()));
448
        }
449
0
        count_delete = 0;
450
0
        count_insert = 0;
451
0
        text_delete = "".to_string();
452
0
        text_insert = "".to_string();
453
      }
454
0
      pointer += 1;
455
    }
456
0
    temp.pop(); //Remove the dummy entry at the end.
457
0
    temp
458
0
  }
459
460
  // Find the 'middle snake' of a diff, split the problem in two
461
  // and return the recursively constructed diff.
462
  // See Myers 1986 paper: An O(ND) Difference Algorithm and Its Variations.
463
  //
464
  // # Args
465
  // - text1: Old chars to be diffed.
466
  // - text2: New chars to be diffed.
467
  //
468
  // # Return
469
  // - Vector of diffs as changes.
470
  //fn diff_bisect(&self, char1: &Vec<char>, char2: &Vec<char>) -> Vec<Diff> {
471
  //    self.diff_bisect_internal(char1, char2, Instant::now())
472
  //}
473
474
0
  fn diff_bisect_internal(
475
0
    &self,
476
0
    char1: &[char],
477
0
    char2: &[char],
478
0
    start_time: Instant,
479
0
  ) -> Vec<Diff> {
480
0
    let text1_length = char1.len() as i32;
481
0
    let text2_length = char2.len() as i32;
482
0
    let max_d: i32 = (text1_length + text2_length + 1) / 2;
483
0
    let v_offset: i32 = max_d;
484
0
    let v_length: i32 = 2 * max_d;
485
0
    let mut v1: Vec<i32> = vec![-1; v_length as usize];
486
0
    let mut v2: Vec<i32> = vec![-1; v_length as usize];
487
0
    v1[v_offset as usize + 1] = 0;
488
0
    v2[v_offset as usize + 1] = 0;
489
0
    let delta: i32 = text1_length - text2_length;
490
    // If the total number of characters is odd, then the front path will
491
    // collide with the reverse path.
492
0
    let front: i32 = (delta % 2 != 0) as i32;
493
    // Offsets for start and end of k loop.
494
    // Prevents mapping of space beyond the grid.
495
0
    let mut k1start: i32 = 0;
496
0
    let mut k1end: i32 = 0;
497
0
    let mut k2start: i32 = 0;
498
0
    let mut k2end: i32 = 0;
499
0
    for d in 0..max_d {
500
0
      if let Some(diff_timeout) = self.diff_timeout {
501
0
        if start_time.elapsed().as_secs_f32() >= diff_timeout {
502
0
          break;
503
0
        }
504
0
      }
505
506
0
      let d1 = d;
507
0
      let mut k1 = -d1 + k1start;
508
      let mut x1: i32;
509
      let mut k1_offset: i32;
510
      let mut k2_offset;
511
      let mut x2;
512
      let mut y1;
513
      // Walk the front path one step.
514
0
      while k1 < d1 + 1 - k1end {
515
0
        k1_offset = v_offset + k1;
516
0
        if k1 == -d1
517
0
          || (k1 != d1 && v1[k1_offset as usize - 1] < v1[k1_offset as usize + 1])
518
0
        {
519
0
          x1 = v1[k1_offset as usize + 1];
520
0
        } else {
521
0
          x1 = v1[k1_offset as usize - 1] + 1;
522
0
        }
523
0
        y1 = x1 - k1;
524
0
        while x1 < text1_length && y1 < text2_length {
525
0
          let i1 = if x1 < 0 {
526
0
            text1_length + x1
527
          } else {
528
0
            x1
529
          };
530
0
          let i2 = if y1 < 0 {
531
0
            text2_length + y1
532
          } else {
533
0
            y1
534
          };
535
0
          if char1[i1 as usize] != char2[i2 as usize] {
536
0
            break;
537
0
          }
538
0
          x1 += 1;
539
0
          y1 += 1;
540
        }
541
0
        v1[k1_offset as usize] = x1;
542
0
        if x1 > text1_length {
543
0
          // Ran off the right of the graph.
544
0
          k1end += 2;
545
0
        } else if y1 > text2_length {
546
0
          // Ran off the bottom of the graph.
547
0
          k1start += 2;
548
0
        } else if front != 0 {
549
0
          k2_offset = v_offset + delta - k1;
550
0
          if k2_offset >= 0 && k2_offset < v_length && v2[k2_offset as usize] != -1 {
551
            // Mirror x2 onto top-left coordinate system.
552
0
            x2 = text1_length - v2[k2_offset as usize];
553
0
            if x1 >= x2 {
554
              // Overlap detected.
555
0
              return self.diff_bisect_split(char1, char2, x1, y1, start_time);
556
0
            }
557
0
          }
558
0
        }
559
0
        k1 += 2;
560
      }
561
0
      let mut k2 = -d1 + k2start;
562
      let mut y2;
563
      // Walk the reverse path one step.
564
0
      while k2 < d1 + 1 - k2end {
565
0
        k2_offset = v_offset + k2;
566
0
        if k2 == -d1
567
0
          || (k2 != d1 && v2[k2_offset as usize - 1] < v2[k2_offset as usize + 1])
568
0
        {
569
0
          x2 = v2[k2_offset as usize + 1];
570
0
        } else {
571
0
          x2 = v2[k2_offset as usize - 1] + 1;
572
0
        }
573
0
        y2 = x2 - k2;
574
0
        while x2 < text1_length && y2 < text2_length {
575
0
          let i1 = if text1_length - x2 > 0 {
576
0
            text1_length - x2 - 1
577
          } else {
578
0
            x2 + 1
579
          };
580
0
          let i2 = if text2_length - y2 > 0 {
581
0
            text2_length - y2 - 1
582
          } else {
583
0
            y2 + 1
584
          };
585
0
          if char1[i1 as usize] != char2[i2 as usize] {
586
0
            break;
587
0
          }
588
0
          x2 += 1;
589
0
          y2 += 1;
590
        }
591
0
        v2[k2_offset as usize] = x2;
592
0
        if x2 > text1_length {
593
0
          // Ran off the left of the graph.
594
0
          k2end += 2;
595
0
        } else if y2 > text2_length {
596
0
          // Ran off the top of the graph.
597
0
          k2start += 2;
598
0
        } else if front == 0 {
599
0
          k1_offset = v_offset + delta - k2;
600
0
          if k1_offset >= 0 && k1_offset < v_length && v1[k1_offset as usize] != -1 {
601
0
            x1 = v1[k1_offset as usize];
602
0
            y1 = v_offset + x1 - k1_offset;
603
            // Mirror x2 onto top-left coordinate system.
604
0
            x2 = text1_length - x2;
605
0
            if x1 >= x2 {
606
              // Overlap detected.
607
0
              return self.diff_bisect_split(char1, char2, x1, y1, start_time);
608
0
            }
609
0
          }
610
0
        }
611
0
        k2 += 2;
612
      }
613
    }
614
    // number of diffs equals number of characters, no commonality at all.
615
0
    vec![Diff::new(-1, char1.iter().collect()), Diff::new(1, char2.iter().collect())]
616
0
  }
617
618
  /// Given the location of the 'middle snake', split the diff in two parts
619
  /// and recurse.
620
  ///
621
  /// # Args
622
  /// - text1: Old text1 to be diffed.
623
  /// - text2: New text1 to be diffed.
624
  /// - x: Index of split point in text1.
625
  /// - y: Index of split point in text2.
626
  ///
627
  /// # Return
628
  /// Vector of diffs as changes.
629
0
  fn diff_bisect_split(
630
0
    &self,
631
0
    text1: &[char],
632
0
    text2: &[char],
633
0
    x: i32,
634
0
    y: i32,
635
0
    start_time: Instant,
636
0
  ) -> Vec<Diff> {
637
0
    let text1a: String = text1[..(x as usize)].iter().collect();
638
0
    let text2a: String = text2[..(y as usize)].iter().collect();
639
0
    let text1b: String = text1[(x as usize)..].iter().collect();
640
0
    let text2b: String = text2[(y as usize)..].iter().collect();
641
642
    // Compute both diffs serially.
643
0
    let mut diffs =
644
0
      self.diff_main_internal(text1a.as_str(), text2a.as_str(), false, start_time);
645
0
    let mut diffsb =
646
0
      self.diff_main_internal(text1b.as_str(), text2b.as_str(), false, start_time);
647
0
    diffs.append(&mut diffsb);
648
0
    diffs
649
0
  }
650
651
  /*
652
  /// Split two texts into an array of strings.  Reduce the texts to a string
653
  /// of hashes where each Unicode character represents one word.
654
  ///
655
  /// # Args
656
  /// - text1: First chars.
657
  /// - text2: Second chars.
658
  ///
659
  /// # Return
660
  /// Three element tuple, containing the encoded text1, the encoded text2 and
661
  /// the array of unique strings.  The zeroth element of the array of unique
662
  /// strings is intentionally blank.
663
  fn diff_words_tochars(
664
    &self,
665
    text1: &String,
666
    text2: &String,
667
  ) -> (String, String, Vec<String>) {
668
    let mut wordarray: Vec<String> = vec!["".to_string()];
669
    let mut wordhash: HashMap<String, u32> = HashMap::new();
670
    let chars1 = self.diff_words_tochars_munge(text1, &mut wordarray, &mut wordhash);
671
    let dmp = Dmp::new();
672
    let chars2 = dmp.diff_words_tochars_munge(text2, &mut wordarray, &mut wordhash);
673
    (chars1, chars2, wordarray)
674
  }
675
  */
676
677
  /*
678
  /// Split a text into an array of strings.  Reduce the texts to a string
679
  /// of hashes where each Unicode character represents one word.
680
  /// Modifies wordarray and wordhash through being a closure.
681
  ///
682
  /// # Args
683
  /// - text: chars to encode.
684
  ///
685
  /// # Return
686
  /// Encoded string.
687
  fn diff_words_tochars_munge(
688
    &self,
689
    text: &String,
690
    wordarray: &mut Vec<String>,
691
    wordhash: &mut HashMap<String, u32>,
692
  ) -> String {
693
    let mut chars = "".to_string();
694
695
    let re = Regex::new(r"[\s\n\r]").unwrap();
696
    let mut prev_end: usize = 0;
697
    for part in re.find_iter(&text) {
698
      if prev_end < part.start() {
699
        let word = &text[prev_end..part.start()];
700
        chars += &self.make_token_dict(word, wordarray, wordhash);
701
      }
702
      let word = &text[part.start()..part.end()];
703
      chars += &self.make_token_dict(word, wordarray, wordhash);
704
      prev_end = part.end();
705
    }
706
    if prev_end < text.len() {
707
      let word = &text[prev_end..text.len()];
708
      chars += &self.make_token_dict(word, wordarray, wordhash);
709
    }
710
    chars
711
  }
712
  */
713
714
  /*
715
  fn make_token_dict(
716
    &self,
717
    word: &str,
718
    wordarray: &mut Vec<String>,
719
    wordhash: &mut HashMap<String, u32>,
720
  ) -> String {
721
    if !wordhash.contains_key(word) {
722
      wordarray.push(word.to_string());
723
      wordhash.insert(word.to_string(), wordarray.len() as u32 - 1);
724
    }
725
    char::from_u32(wordhash[word]).unwrap().to_string()
726
  }
727
  */
728
729
  /// Split two texts into an array of strings.  Reduce the texts to a string
730
  /// of hashes where each Unicode character represents one line.
731
  ///
732
  /// Args
733
  /// - text1: First chars.
734
  /// - text2: Second chars.
735
  ///
736
  /// Return
737
  /// Three element tuple, containing the encoded text1, the encoded text2 and
738
  /// the array of unique strings.  The zeroth element of the array of unique
739
  /// strings is intentionally blank.
740
0
  fn diff_lines_tochars(&self, text1: &[char], text2: &[char]) -> (String, String, Vec<String>) {
741
0
    let mut linearray: Vec<String> = vec!["".to_string()];
742
0
    let mut linehash: HashMap<String, i32> = HashMap::new();
743
0
    let chars1 = self.diff_lines_tochars_munge(text1, &mut linearray, &mut linehash);
744
0
    let dmp = Dmp::default();
745
0
    let chars2 = dmp.diff_lines_tochars_munge(text2, &mut linearray, &mut linehash);
746
0
    (chars1, chars2, linearray)
747
0
  }
748
749
  /// Split a text into an array of strings.  Reduce the texts to a string
750
  /// of hashes where each Unicode character represents one line.
751
  /// Modifies linearray and linehash through being a closure.
752
  ///
753
  /// Args
754
  /// - text: chars to encode.
755
  ///
756
  /// Return
757
  /// Encoded string.
758
0
  fn diff_lines_tochars_munge(
759
0
    &self,
760
0
    text: &[char],
761
0
    linearray: &mut Vec<String>,
762
0
    linehash: &mut HashMap<String, i32>,
763
0
  ) -> String {
764
0
    let mut chars = "".to_string();
765
    // Walk the text, pulling out a substring for each line.
766
    // text.split('\n') would would temporarily double our memory footprint.
767
    // Modifying text would create many large strings to garbage collect.
768
0
    let mut line_start = 0;
769
0
    let mut line_end = -1;
770
    let mut line: String;
771
0
    while line_end < (text.len() as i32 - 1) {
772
0
      line_end = find_char('\n', text, line_start as usize);
773
0
      if line_end == -1 {
774
0
        line_end = text.len() as i32 - 1;
775
0
      }
776
0
      line = text[line_start as usize..=line_end as usize].iter().collect();
777
0
      if linehash.contains_key(&line) {
778
0
        if let Some(char1) = char::from_u32(linehash[&line] as u32) {
779
0
          chars.push(char1);
780
0
          line_start = line_end + 1;
781
0
        }
782
      } else {
783
0
        let mut u32char = linearray.len() as i32;
784
785
        // skip reserved range - U+D800 to U+DFFF
786
        // unicode code points in this range can't be converted to unicode scalars
787
0
        if u32char >= 55296 {
788
0
          u32char += 2048;
789
0
        }
790
791
        // 1114111 is the biggest unicode scalar, so stop here
792
0
        if u32char == 1114111 {
793
0
          line = text[(line_start as usize)..].iter().collect();
794
0
          line_end = text.len() as i32 - 1;
795
0
        }
796
797
0
        linearray.push(line.clone());
798
0
        linehash.insert(line.clone(), u32char);
799
800
0
        chars.push(char::from_u32(u32char as u32).unwrap());
801
0
        line_start = line_end + 1;
802
      }
803
    }
804
0
    chars
805
0
  }
806
807
  /// Rehydrate the text in a diff from a string of line hashes to real lines
808
  /// of text.
809
  ///
810
  /// Args
811
  /// - diffs: Vector of diffs as changes.
812
  /// - lineArray: Vector of unique strings.
813
0
  pub fn diff_chars_tolines(&self, diffs: &mut Vec<Diff>, line_array: &[String]) {
814
0
    for d in diffs {
815
0
      let mut text: String = "".to_string();
816
0
      let text1 = d.text.clone();
817
0
      let chars: Vec<char> = text1.chars().collect();
818
0
      for j in 0..chars.len() {
819
0
        text += line_array[chars[j] as usize].as_str();
820
0
      }
821
0
      d.text = text;
822
    }
823
0
  }
824
825
  /// Determine the common prefix of two chars.
826
  ///
827
  /// Args:
828
  /// - text1: First chars.
829
  /// - text2: Second chars.
830
  ///
831
  /// Returns:
832
  /// The number of characters common to the start of each chars.
833
0
  fn diff_common_prefix(&self, text1: &[char], text2: &[char]) -> i32 {
834
0
    if text1.is_empty() || text2.is_empty() {
835
0
      return 0;
836
0
    }
837
0
    let pointermax = min(text1.len() as i32, text2.len() as i32);
838
0
    let mut pointerstart = 0;
839
0
    while pointerstart < pointermax {
840
0
      if text1[pointerstart as usize] == text2[pointerstart as usize] {
841
0
        pointerstart += 1;
842
0
      } else {
843
0
        return pointerstart;
844
      }
845
    }
846
0
    pointermax
847
0
  }
848
849
  /// Determine the common suffix of two strings.
850
  ///
851
  /// # Args
852
  /// - text1: First chars.
853
  /// - text2: Second chars.
854
  ///
855
  /// # Return
856
  /// The number of characters common to the end of each chars.
857
0
  fn diff_common_suffix(&self, text1: &[char], text2: &[char]) -> i32 {
858
0
    if text1.is_empty() || text2.is_empty() {
859
0
      return 0;
860
0
    }
861
0
    let mut pointer_1 = text1.len() as i32 - 1;
862
0
    let mut pointer_2 = text2.len() as i32 - 1;
863
0
    let mut len = 0;
864
0
    while pointer_1 >= 0 && pointer_2 >= 0 {
865
0
      if text1[pointer_1 as usize] == text2[pointer_2 as usize] {
866
0
        len += 1;
867
0
      } else {
868
0
        break;
869
      }
870
0
      pointer_1 -= 1;
871
0
      pointer_2 -= 1;
872
    }
873
0
    len
874
0
  }
875
876
  /// Determine if the suffix of one chars is the prefix of another.
877
  ///
878
  /// # Args
879
  /// - text1 First chars.
880
  /// - text2 Second chars.
881
  ///
882
  /// # Return
883
  /// The number of characters common to the end of the first
884
  /// chars and the start of the second chars.
885
0
  fn diff_common_overlap(&self, text1: &[char], text2: &[char]) -> i32 {
886
0
    let text1_length = text1.len();
887
0
    let text2_length = text2.len();
888
0
    if text1_length == 0 || text2_length == 0 {
889
0
      return 0;
890
0
    }
891
    let text1_trunc;
892
    let text2_trunc;
893
0
    let len = min(text1_length as i32, text2_length as i32);
894
895
    // Truncate the longer chars.
896
0
    if text1.len() > text2.len() {
897
0
      text1_trunc = text1[(text1_length - text2_length)..].to_vec();
898
0
      text2_trunc = text2[..].to_vec();
899
0
    } else {
900
0
      text1_trunc = text1[..].to_vec();
901
0
      text2_trunc = text2[0..text1_length].to_vec();
902
0
    }
903
0
    let mut best = 0;
904
0
    let mut length = 1;
905
    // Quick check for the worst case.
906
0
    if text1_trunc == text2_trunc {
907
0
      return len;
908
0
    }
909
    /*Start by looking for a single character match
910
    and increase length until no match is found.
911
    Performance analysis: https://neil.fraser.name/news/2010/11/04/ */
912
    loop {
913
0
      let patern = text1_trunc[(len as usize - length)..(len as usize)].to_vec();
914
0
      let found = self.kmp(&text2_trunc, &patern, 0);
915
0
      if found == -1 {
916
0
        return best;
917
0
      }
918
0
      length += found as usize;
919
0
      if found == 0 {
920
0
        best = length as i32;
921
0
        length += 1;
922
0
      }
923
    }
924
0
  }
925
926
  /// split the string accoring to given character
927
  ///
928
  /// # Args
929
  /// - text: string we have to split
930
  /// - ch: character by which we have to split string
931
  ///
932
  /// # Return
933
  /// Vector of string after spliting according to character.
934
0
  fn split_by_char(&self, text: &str, ch: char) -> Vec<String> {
935
0
    text.split(ch).map(str::to_owned).collect()
936
0
  }
937
938
  /// split the string accoring to given characters "@@ ".
939
  ///
940
  /// # Args
941
  /// - text: string we have to split
942
  ///
943
  /// # Return
944
  /// Vector of string after spliting according to characters.
945
0
  fn split_by_chars(&self, text: &str) -> Vec<String> {
946
0
    text.split("@@ ").map(str::to_owned).collect()
947
0
  }
948
949
  /// Do the two texts share a substring which is at least half the length of
950
  /// the longer text?
951
  /// This speedup can produce non-minimal diffs.
952
  ///
953
  /// # Args
954
  /// - text1: First chars.
955
  /// - text2: Second chars.
956
  ///
957
  /// # Return
958
  /// Five element Vector, containing the prefix of text1, the suffix of text1,
959
  /// the prefix of text2, the suffix of text2 and the common middle.  Or empty vector
960
  /// if there was no match.
961
0
  fn diff_half_match(&self, text1: &Vec<char>, text2: &Vec<char>) -> Vec<String> {
962
    // Don't risk returning a non-optimal diff if we have unlimited time.
963
0
    if self.diff_timeout.is_none() {
964
0
      return vec![];
965
0
    }
966
967
0
    let (long_text, short_text) = if text1.len() > text2.len() {
968
0
      (text1, text2)
969
    } else {
970
0
      (text2, text1)
971
    };
972
0
    let len1 = short_text.len();
973
0
    let len2 = long_text.len();
974
0
    if len2 < 4 || len1 * 2 < len2 {
975
0
      return vec![];
976
0
    }
977
978
    let mut hm: Vec<String>;
979
    //First check if the second quarter is the seed for a half-match.
980
0
    let hm1 = self.diff_half_matchi(long_text, short_text, (len2 as i32 + 3) / 4);
981
    // Check again based on the third quarter.
982
0
    let hm2 = self.diff_half_matchi(long_text, short_text, (len2 as i32 + 1) / 2);
983
984
0
    if hm1.is_empty() && hm2.is_empty() {
985
0
      return vec![];
986
0
    } else if hm1.is_empty() {
987
0
      hm = hm2;
988
0
    } else if hm2.is_empty() {
989
0
      hm = hm1;
990
0
    } else {
991
      // Both matched.  Select the longest.
992
0
      hm = if hm1[4].len() > hm2[4].len() {
993
0
        hm1
994
      } else {
995
0
        hm2
996
      };
997
    }
998
0
    if text1.len() > text2.len() {
999
0
      return hm;
1000
0
    }
1001
0
    let mut temp2 = hm[0].clone();
1002
0
    let mut temp3 = hm[2].clone();
1003
0
    hm[0] = temp3;
1004
0
    hm[2] = temp2;
1005
0
    temp2 = hm[1].clone();
1006
0
    temp3 = hm[3].clone();
1007
0
    hm[1] = temp3;
1008
0
    hm[3] = temp2;
1009
0
    hm
1010
0
  }
1011
1012
  /// Does a substring of shorttext exist within longtext such that the
1013
  /// substring is at least half the length of longtext?
1014
  /// Closure, but does not reference any external variables.
1015
  ///
1016
  /// # Args
1017
  /// - longtext: Longer chars.
1018
  /// - shorttext: Shorter chars.
1019
  /// - i: Start index of quarter length substring within longtext.
1020
  ///
1021
  /// # Return
1022
  /// Five element vector, containing the prefix of longtext, the suffix of
1023
  /// longtext, the prefix of shorttext, the suffix of shorttext and the
1024
  /// common middle.  Or empty vector if there was no match.
1025
0
  fn diff_half_matchi(&self, long_text: &[char], short_text: &[char], i: i32) -> Vec<String> {
1026
0
    let long_len = long_text.len();
1027
0
    let seed =
1028
0
      Vec::from_iter(long_text[(i as usize)..(i as usize + long_len / 4)].iter().cloned());
1029
0
    let mut best_common = "".to_string();
1030
0
    let mut best_longtext_a = "".to_string();
1031
0
    let mut best_longtext_b = "".to_string();
1032
0
    let mut best_shorttext_a = "".to_string();
1033
0
    let mut best_shorttext_b = "".to_string();
1034
0
    let mut j: i32 = self.kmp(short_text, &seed, 0);
1035
0
    while j != -1 {
1036
0
      let prefix_length =
1037
0
        self.diff_common_prefix(&long_text[(i as usize)..], &short_text[(j as usize)..]);
1038
0
      let suffix_length =
1039
0
        self.diff_common_suffix(&long_text[..(i as usize)], &short_text[..(j as usize)]);
1040
0
      if best_common.len() < suffix_length as usize + prefix_length as usize {
1041
0
        best_common = short_text
1042
0
          [(j as usize - suffix_length as usize)..(j as usize + prefix_length as usize)]
1043
0
          .iter()
1044
0
          .collect();
1045
0
        best_longtext_a = long_text[..((i - suffix_length) as usize)].iter().collect();
1046
0
        best_longtext_b = long_text[((i + prefix_length) as usize)..].iter().collect();
1047
0
        best_shorttext_a = short_text[..((j - suffix_length) as usize)].iter().collect();
1048
0
        best_shorttext_b = short_text[((j + prefix_length) as usize)..].iter().collect();
1049
0
      }
1050
0
      j = self.kmp(short_text, &seed, j as usize + 1);
1051
    }
1052
0
    if best_common.chars().count() * 2 >= long_text.len() {
1053
0
      return vec![
1054
0
        best_longtext_a,
1055
0
        best_longtext_b,
1056
0
        best_shorttext_a,
1057
0
        best_shorttext_b,
1058
0
        best_common,
1059
      ];
1060
0
    }
1061
0
    vec![]
1062
0
  }
1063
1064
  /// Reduce the number of edits by eliminating semantically trivial
1065
  /// equalities.
1066
  ///
1067
  /// # Args
1068
  /// - diffs: Vectors of diff object.
1069
0
  pub fn diff_cleanup_semantic(&self, diffs: &mut Vec<Diff>) {
1070
0
    let mut changes = false;
1071
0
    let mut equalities: Vec<i32> = vec![]; // Stack of indices where equalities are found.
1072
0
    let mut last_equality = "".to_string(); // Always equal to diffs[equalities[-1]][1]
1073
0
    let mut pointer: i32 = 0; // Index of current position.
1074
              // Number of chars that changed prior to the equality.
1075
0
    let mut length_insertions1 = 0;
1076
0
    let mut length_deletions1 = 0;
1077
    // Number of chars that changed after the equality.
1078
0
    let mut length_insertions2 = 0;
1079
0
    let mut length_deletions2 = 0;
1080
0
    while (pointer as usize) < diffs.len() {
1081
0
      if diffs[pointer as usize].operation == 0 {
1082
0
        // Equality found.
1083
0
        equalities.push(pointer);
1084
0
        length_insertions1 = length_insertions2;
1085
0
        length_insertions2 = 0;
1086
0
        length_deletions1 = length_deletions2;
1087
0
        length_deletions2 = 0;
1088
0
        last_equality = diffs[pointer as usize].text.clone();
1089
0
      } else {
1090
        // An insertion or deletion.
1091
0
        if diffs[pointer as usize].operation == 1 {
1092
0
          length_insertions2 += diffs[pointer as usize].text.chars().count() as i32;
1093
0
        } else {
1094
0
          length_deletions2 += diffs[pointer as usize].text.chars().count() as i32;
1095
0
          // Eliminate an equality that is smaller or equal to the edits on both
1096
0
          // sides of it.
1097
0
        }
1098
0
        let last_equality_len = last_equality.chars().count() as i32;
1099
0
        if last_equality_len > 0
1100
0
          && last_equality_len <= max(length_insertions1, length_deletions1)
1101
0
          && last_equality_len <= max(length_insertions2, length_deletions2)
1102
        {
1103
          // Duplicate record.
1104
0
          diffs.insert(
1105
0
            equalities[equalities.len() - 1] as usize,
1106
0
            Diff::new(-1, last_equality.clone()),
1107
          );
1108
          // Change second copy to insert.
1109
0
          diffs[equalities[equalities.len() - 1] as usize + 1] = Diff::new(
1110
            1,
1111
0
            diffs[equalities[equalities.len() - 1] as usize + 1].text.clone(),
1112
          );
1113
          // Throw away the equality we just deleted.
1114
0
          equalities.pop();
1115
          // Throw away the previous equality (it needs to be reevaluated).
1116
0
          if !equalities.is_empty() {
1117
0
            equalities.pop();
1118
0
          }
1119
0
          if !equalities.is_empty() {
1120
0
            pointer = equalities[equalities.len() - 1];
1121
0
          } else {
1122
0
            pointer = -1;
1123
0
          }
1124
          // Reset the counters.
1125
0
          length_insertions1 = 0;
1126
0
          length_deletions1 = 0;
1127
0
          length_insertions2 = 0;
1128
0
          length_deletions2 = 0;
1129
0
          last_equality = "".to_string();
1130
0
          changes = true;
1131
0
        }
1132
      }
1133
0
      pointer += 1;
1134
    }
1135
    // Normalize the diff.
1136
0
    if changes {
1137
0
      self.diff_cleanup_merge(diffs);
1138
0
    }
1139
0
    self.diff_cleanup_semantic_lossless(diffs);
1140
1141
    let mut overlap_length1: i32;
1142
    let mut overlap_length2: i32;
1143
0
    pointer = 1;
1144
0
    while (pointer as usize) < diffs.len() {
1145
0
      if diffs[pointer as usize - 1].operation == -1 && diffs[pointer as usize].operation == 1
1146
      {
1147
0
        let deletion_vec: Vec<char> = diffs[pointer as usize - 1].text.chars().collect();
1148
0
        let insertion_vec: Vec<char> = diffs[pointer as usize].text.chars().collect();
1149
0
        overlap_length1 = self.diff_common_overlap(&deletion_vec, &insertion_vec);
1150
0
        overlap_length2 = self.diff_common_overlap(&insertion_vec, &deletion_vec);
1151
0
        if overlap_length1 >= overlap_length2 {
1152
0
          if (overlap_length1 as f32) >= (deletion_vec.len() as f32 / 2.0)
1153
0
            || (overlap_length1 as f32) >= (insertion_vec.len() as f32 / 2.0)
1154
0
          {
1155
0
            // Overlap found.  Insert an equality and trim the surrounding edits.
1156
0
            diffs.insert(
1157
0
              pointer as usize,
1158
0
              Diff::new(
1159
0
                0,
1160
0
                insertion_vec[..(overlap_length1 as usize)].iter().collect(),
1161
0
              ),
1162
0
            );
1163
0
            diffs[pointer as usize - 1] = Diff::new(
1164
0
              -1,
1165
0
              deletion_vec[..(deletion_vec.len() - overlap_length1 as usize)]
1166
0
                .iter()
1167
0
                .collect(),
1168
0
            );
1169
0
            diffs[pointer as usize + 1] = Diff::new(
1170
0
              1,
1171
0
              insertion_vec[(overlap_length1 as usize)..].iter().collect(),
1172
0
            );
1173
0
            pointer += 1;
1174
0
          }
1175
0
        } else if (overlap_length2 as f32) >= (deletion_vec.len() as f32 / 2.0)
1176
0
          || (overlap_length2 as f32) >= (insertion_vec.len() as f32 / 2.0)
1177
0
        {
1178
0
          // Reverse overlap found.
1179
0
          // Insert an equality and swap and trim the surrounding edits.
1180
0
          diffs.insert(
1181
0
            pointer as usize,
1182
0
            Diff::new(0, deletion_vec[..(overlap_length2 as usize)].iter().collect()),
1183
0
          );
1184
0
          let insertion_vec_len = insertion_vec.len();
1185
0
          diffs[pointer as usize - 1] = Diff::new(
1186
0
            1,
1187
0
            insertion_vec[..(insertion_vec_len - overlap_length2 as usize)]
1188
0
              .iter()
1189
0
              .collect(),
1190
0
          );
1191
0
          diffs[pointer as usize + 1] =
1192
0
            Diff::new(-1, deletion_vec[(overlap_length2 as usize)..].iter().collect());
1193
0
          pointer += 1;
1194
0
        }
1195
0
        pointer += 1;
1196
0
      }
1197
0
      pointer += 1;
1198
    }
1199
0
  }
1200
1201
  /// Look for single edits surrounded on both sides by equalities
1202
  /// which can be shifted sideways to align the edit to a word boundary.
1203
  /// e.g: The c<ins>at c</ins>ame. -> The <ins>cat </ins>came.
1204
  ///
1205
  /// Args:
1206
  /// - diffs: Vector of diff object.
1207
0
  pub fn diff_cleanup_semantic_lossless(&self, diffs: &mut Vec<Diff>) {
1208
0
    let mut pointer = 1;
1209
    let mut equality1;
1210
    let mut equality2;
1211
    let mut edit: String;
1212
    let mut common_offset;
1213
    let mut common_string: String;
1214
    let mut best_equality1;
1215
    let mut best_edit;
1216
    let mut best_equality2;
1217
    let mut best_score;
1218
    let mut score;
1219
1220
    //Intentionally ignore the first and last element (don't need checking).
1221
0
    while pointer < diffs.len() as i32 - 1 {
1222
0
      if diffs[pointer as usize - 1].operation == 0
1223
0
        && diffs[pointer as usize + 1].operation == 0
1224
      {
1225
        //  This is a single edit surrounded by equalities.
1226
0
        equality1 = diffs[pointer as usize - 1].text.clone();
1227
0
        edit = diffs[pointer as usize].text.clone();
1228
0
        equality2 = diffs[pointer as usize + 1].text.clone();
1229
0
        let mut edit_vec: Vec<char> = edit.chars().collect();
1230
0
        let mut equality1_vec: Vec<char> = equality1.chars().collect();
1231
0
        let mut equality2_vec: Vec<char> = equality2.chars().collect();
1232
1233
        // First, shift the edit as far left as possible.
1234
0
        common_offset = self.diff_common_suffix(&equality1_vec, &edit_vec);
1235
0
        if common_offset != 0 {
1236
0
          common_string =
1237
0
            edit_vec[(edit_vec.len() - common_offset as usize)..].iter().collect();
1238
0
          equality1 = equality1_vec[..(equality1_vec.len() - common_offset as usize)]
1239
0
            .iter()
1240
0
            .collect();
1241
0
          let temp7: String =
1242
0
            edit_vec[..(edit_vec.len() - common_offset as usize)].iter().collect();
1243
0
          edit = common_string.clone() + temp7.as_str();
1244
0
          equality2 = common_string + equality2.as_str();
1245
0
          edit_vec = edit.chars().collect();
1246
0
          equality2_vec = equality2.chars().collect();
1247
0
          equality1_vec = equality1.chars().collect();
1248
0
        }
1249
        // Second, step character by character right, looking for the best fit.
1250
0
        best_equality1 = equality1.clone();
1251
0
        best_edit = edit;
1252
0
        best_equality2 = equality2;
1253
0
        best_score = self.diff_cleanup_semantic_score(&equality1_vec, &edit_vec)
1254
0
          + self.diff_cleanup_semantic_score(&edit_vec, &equality2_vec);
1255
0
        let edit_len = edit_vec.len();
1256
0
        let mut equality2_len = equality2_vec.len();
1257
0
        while equality2_len > 0 && edit_len > 0 {
1258
0
          if edit_vec[0] != equality2_vec[0] {
1259
0
            break;
1260
0
          }
1261
0
          let ch = edit_vec[0];
1262
0
          equality1_vec.push(ch);
1263
0
          edit_vec.push(ch);
1264
0
          edit_vec = edit_vec[1..].to_vec();
1265
0
          equality2_len -= 1;
1266
0
          equality2_vec = equality2_vec[1..].to_vec();
1267
0
          score = self.diff_cleanup_semantic_score(&equality1_vec, &edit_vec)
1268
0
            + self.diff_cleanup_semantic_score(&edit_vec, &equality2_vec);
1269
          // The >= encourages trailing rather than leading whitespace on edits.
1270
0
          if score >= best_score {
1271
0
            best_score = score;
1272
0
            best_equality1 = equality1_vec[0..].iter().collect();
1273
0
            best_edit = edit_vec[..].iter().collect();
1274
0
            best_equality2 = equality2_vec[..].iter().collect();
1275
0
          }
1276
        }
1277
0
        if diffs[pointer as usize - 1].text != best_equality1 {
1278
          // We have an improvement, save it back to the diff.
1279
0
          if !best_equality1.is_empty() {
1280
0
            diffs[pointer as usize - 1] =
1281
0
              Diff::new(diffs[pointer as usize - 1].operation, best_equality1);
1282
0
          } else {
1283
0
            diffs.remove(pointer as usize - 1);
1284
0
            pointer -= 1;
1285
0
          }
1286
0
          diffs[pointer as usize] =
1287
0
            Diff::new(diffs[pointer as usize].operation, best_edit);
1288
0
          if !best_equality2.is_empty() {
1289
0
            diffs[pointer as usize + 1] =
1290
0
              Diff::new(diffs[pointer as usize + 1].operation, best_equality2);
1291
0
          } else {
1292
0
            diffs.remove(pointer as usize + 1);
1293
0
            pointer += 1;
1294
0
          }
1295
0
        }
1296
0
      }
1297
0
      pointer += 1;
1298
    }
1299
0
  }
1300
1301
  /// Given two strings, compute a score representing whether the
1302
  /// internal boundary falls on logical boundaries.
1303
  /// Scores range from 6 (best) to 0 (worst).
1304
  /// Closure, but does not reference any external variables.
1305
  ///
1306
  /// # Args
1307
  /// - one: First chars.
1308
  /// - two: Second chars.
1309
  ///
1310
  /// # Return
1311
  /// The score.
1312
0
  fn diff_cleanup_semantic_score(&self, one: &[char], two: &[char]) -> i32 {
1313
0
    if one.is_empty() || two.is_empty() {
1314
      // Edges are the best.
1315
0
      return 6;
1316
0
    }
1317
1318
    // Each port of this function behaves slightly differently due to
1319
    // subtle differences in each language's definition of things like
1320
    // 'whitespace'.  Since this function's purpose is largely cosmetic,
1321
    // the choice has been made to use each language's native features
1322
    // rather than force total conformity.
1323
0
    let char1 = one[one.len() - 1];
1324
0
    let char2 = two[0];
1325
0
    let nonalphanumeric1: bool = !char1.is_alphanumeric();
1326
0
    let nonalphanumeric2: bool = !char2.is_alphanumeric();
1327
0
    let whitespace1: bool = nonalphanumeric1 & char1.is_whitespace();
1328
0
    let whitespace2: bool = nonalphanumeric2 & char2.is_whitespace();
1329
0
    let linebreak1: bool = whitespace1 & ((char1 == '\r') | (char1 == '\n'));
1330
0
    let linebreak2: bool = whitespace2 & ((char2 == '\r') | (char2 == '\n'));
1331
0
    let mut test1: bool = false;
1332
0
    let mut test2: bool = false;
1333
0
    if one.len() > 1 && one[one.len() - 1] == '\n' && one[one.len() - 2] == '\n' {
1334
0
      test1 = true;
1335
0
    }
1336
0
    if one.len() > 2
1337
0
      && one[one.len() - 1] == '\n'
1338
0
      && one[one.len() - 3] == '\n'
1339
0
      && one[one.len() - 2] == '\r'
1340
0
    {
1341
0
      test1 = true;
1342
0
    }
1343
0
    if two.len() > 1 && two[two.len() - 1] == '\n' && two[two.len() - 2] == '\n' {
1344
0
      test2 = true;
1345
0
    }
1346
0
    if two.len() > 2
1347
0
      && two[two.len() - 1] == '\n'
1348
0
      && two[two.len() - 3] == '\n'
1349
0
      && two[two.len() - 2] == '\r'
1350
0
    {
1351
0
      test2 = true;
1352
0
    }
1353
0
    let blankline1: bool = linebreak1 & test1;
1354
0
    let blankline2: bool = linebreak2 & test2;
1355
0
    if blankline1 || blankline2 {
1356
      // Five points for blank lines.
1357
0
      return 5;
1358
0
    }
1359
0
    if linebreak1 || linebreak2 {
1360
      // Four points for line breaks.
1361
0
      return 4;
1362
0
    }
1363
0
    if nonalphanumeric1 && !whitespace1 && whitespace2 {
1364
      // Three points for end of sentences.
1365
0
      return 3;
1366
0
    }
1367
0
    if whitespace1 || whitespace2 {
1368
      // Two points for whitespace.
1369
0
      return 2;
1370
0
    }
1371
0
    if nonalphanumeric1 || nonalphanumeric2 {
1372
      // One point for non-alphanumeric.
1373
0
      return 1;
1374
0
    }
1375
0
    0
1376
0
  }
1377
1378
  /// Reduce the number of edits by eliminating operationally trivial
1379
  /// equalities.
1380
  ///
1381
  /// # Args
1382
  /// - diffs: Vector of diff object.
1383
0
  pub fn diff_cleanup_efficiency(&self, diffs: &mut Vec<Diff>) {
1384
0
    if diffs.is_empty() {
1385
0
      return;
1386
0
    }
1387
0
    let mut changes: bool = false;
1388
0
    let mut equalities: Vec<i32> = vec![]; //Stack of indices where equalities are found.
1389
0
    let mut last_equality: String = "".to_string(); // Always equal to diffs[equalities[-1]][1]
1390
0
    let mut pointer: i32 = 0; // Index of current position.
1391
0
    let mut pre_ins = false; // Is there an insertion operation before the last equality.
1392
0
    let mut pre_del = false; // Is there a deletion operation before the last equality.
1393
0
    let mut post_ins = false; // Is there an insertion operation after the last equality.
1394
0
    let mut post_del = false; // Is there a deletion operation after the last equality.
1395
0
    while (pointer as usize) < diffs.len() {
1396
0
      if diffs[pointer as usize].operation == 0 {
1397
0
        if diffs[pointer as usize].text.chars().count() < self.edit_cost as usize
1398
0
          && (post_del || post_ins)
1399
0
        {
1400
0
          // Candidate found.
1401
0
          equalities.push(pointer);
1402
0
          pre_ins = post_ins;
1403
0
          pre_del = post_del;
1404
0
          last_equality = diffs[pointer as usize].text.clone();
1405
0
        } else {
1406
0
          // Not a candidate, and can never become one.
1407
0
          equalities = vec![];
1408
0
          last_equality = "".to_string();
1409
0
        }
1410
0
        post_ins = false;
1411
0
        post_del = false;
1412
      } else {
1413
        // An insertion or deletion.
1414
0
        if diffs[pointer as usize].operation == -1 {
1415
0
          post_del = true;
1416
0
        } else {
1417
0
          post_ins = true;
1418
0
        }
1419
1420
        /*
1421
        Five types to be split:
1422
        <ins>A</ins><del>B</del>XY<ins>C</ins><del>D</del>
1423
        <ins>A</ins>X<ins>C</ins><del>D</del>
1424
        <ins>A</ins><del>B</del>X<ins>C</ins>
1425
        <ins>A</del>X<ins>C</ins><del>D</del>
1426
        <ins>A</ins><del>B</del>X<del>C</del>
1427
        */
1428
1429
0
        if !last_equality.is_empty()
1430
0
          && ((pre_ins && pre_del && post_del && post_ins)
1431
0
            || ((last_equality.chars().count() as i32) < self.edit_cost / 2
1432
0
              && (pre_ins as i32
1433
0
                + pre_del as i32 + post_del as i32
1434
0
                + post_ins as i32) == 3))
1435
        {
1436
          // Duplicate record.
1437
0
          diffs.insert(
1438
0
            equalities[equalities.len() - 1] as usize,
1439
0
            Diff::new(-1, last_equality),
1440
          );
1441
          // Change second copy to insert.
1442
0
          diffs[equalities[equalities.len() - 1] as usize + 1] = Diff::new(
1443
            1,
1444
0
            diffs[equalities[equalities.len() - 1] as usize + 1].text.clone(),
1445
          );
1446
0
          equalities.pop(); // Throw away the equality we just deleted.
1447
0
          last_equality = "".to_string();
1448
0
          if pre_ins && pre_del {
1449
0
            // No changes made which could affect previous entry, keep going.
1450
0
            post_del = true;
1451
0
            post_ins = true;
1452
0
            equalities = vec![];
1453
0
          } else {
1454
0
            if !equalities.is_empty() {
1455
0
              equalities.pop(); // Throw away the previous equality.
1456
0
            }
1457
0
            if !equalities.is_empty() {
1458
0
              pointer = equalities[equalities.len() - 1];
1459
0
            } else {
1460
0
              pointer = -1;
1461
0
            }
1462
0
            post_ins = false;
1463
0
            post_del = false;
1464
          }
1465
0
          changes = true;
1466
0
        }
1467
      }
1468
0
      pointer += 1;
1469
    }
1470
0
    if changes {
1471
0
      self.diff_cleanup_merge(diffs);
1472
0
    }
1473
0
  }
1474
1475
  /// Reorder and merge like edit sections. Merge equalities.
1476
  /// Any edit section can move as long as it doesn't cross an equality.
1477
  ///
1478
  /// # Args
1479
  /// - diffs: vectors of diff object.
1480
0
  pub fn diff_cleanup_merge(&self, diffs: &mut Vec<Diff>) {
1481
0
    if diffs.is_empty() {
1482
0
      return;
1483
0
    }
1484
0
    diffs.push(Diff::new(0, "".to_string()));
1485
0
    let mut text_insert: String = "".to_string();
1486
0
    let mut text_delete: String = "".to_string();
1487
0
    let mut i: i32 = 0;
1488
0
    let mut count_insert = 0;
1489
0
    let mut count_delete = 0;
1490
0
    while (i as usize) < diffs.len() {
1491
0
      if diffs[i as usize].operation == -1 {
1492
0
        text_delete += diffs[i as usize].text.as_str();
1493
0
        count_delete += 1;
1494
0
        i += 1;
1495
0
      } else if diffs[i as usize].operation == 1 {
1496
0
        text_insert += diffs[i as usize].text.as_str();
1497
0
        count_insert += 1;
1498
0
        i += 1;
1499
0
      } else {
1500
        // Upon reaching an equality, check for prior redundancies.
1501
0
        if count_delete + count_insert > 1 {
1502
0
          let mut delete_vec: Vec<char> = text_delete.chars().collect();
1503
0
          let mut insert_vec: Vec<char> = text_insert.chars().collect();
1504
0
          if count_delete > 0 && count_insert > 0 {
1505
            // Factor out any common prefixies.
1506
0
            let mut commonlength = self.diff_common_prefix(&insert_vec, &delete_vec);
1507
0
            if commonlength != 0 {
1508
0
              let temp1: String =
1509
0
                (&insert_vec)[..(commonlength as usize)].iter().collect();
1510
0
              let x = i - count_delete - count_insert - 1;
1511
0
              if x >= 0 && diffs[x as usize].operation == 0 {
1512
0
                diffs[x as usize] = Diff::new(
1513
0
                  diffs[x as usize].operation,
1514
0
                  diffs[x as usize].text.clone() + temp1.as_str(),
1515
0
                );
1516
0
              } else {
1517
0
                diffs.insert(0, Diff::new(0, temp1));
1518
0
                i += 1;
1519
0
              }
1520
0
              insert_vec = insert_vec[(commonlength as usize)..].to_vec();
1521
0
              delete_vec = delete_vec[(commonlength as usize)..].to_vec();
1522
0
            }
1523
1524
            // Factor out any common suffixies.
1525
0
            commonlength = self.diff_common_suffix(&insert_vec, &delete_vec);
1526
0
            if commonlength != 0 {
1527
0
              let temp1: String = (&insert_vec)
1528
0
                [(insert_vec.len() - commonlength as usize)..]
1529
0
                .iter()
1530
0
                .collect();
1531
0
              diffs[i as usize] = Diff::new(
1532
0
                diffs[i as usize].operation,
1533
0
                temp1 + diffs[i as usize].text.as_str(),
1534
0
              );
1535
0
              insert_vec =
1536
0
                insert_vec[..(insert_vec.len() - commonlength as usize)].to_vec();
1537
0
              delete_vec =
1538
0
                delete_vec[..(delete_vec.len() - commonlength as usize)].to_vec();
1539
0
            }
1540
0
          }
1541
1542
          // Delete the offending records and add the merged ones.
1543
0
          i -= count_delete + count_insert;
1544
0
          for _j in 0..(count_delete + count_insert) as usize {
1545
0
            diffs.remove(i as usize);
1546
0
          }
1547
0
          if !delete_vec.is_empty() {
1548
0
            diffs.insert(i as usize, Diff::new(-1, delete_vec.iter().collect()));
1549
0
            i += 1;
1550
0
          }
1551
0
          if !insert_vec.is_empty() {
1552
0
            diffs.insert(i as usize, Diff::new(1, insert_vec.iter().collect()));
1553
0
            i += 1;
1554
0
          }
1555
0
          i += 1;
1556
0
        } else if i != 0 && diffs[i as usize - 1].operation == 0 {
1557
0
          // Merge this equality with the previous one.
1558
0
          diffs[i as usize - 1] = Diff::new(
1559
0
            diffs[i as usize - 1].operation,
1560
0
            diffs[i as usize - 1].text.clone() + diffs[i as usize].text.as_str(),
1561
0
          );
1562
0
          diffs.remove(i as usize);
1563
0
        } else {
1564
0
          i += 1;
1565
0
        }
1566
0
        count_delete = 0;
1567
0
        text_delete = "".to_string();
1568
0
        text_insert = "".to_string();
1569
0
        count_insert = 0;
1570
      }
1571
    }
1572
    // Remove the dummy entry at the end.
1573
0
    if diffs[diffs.len() - 1].text.is_empty() {
1574
0
      diffs.pop();
1575
0
    }
1576
1577
    /*
1578
    Second pass: look for single edits surrounded on both sides by equalities
1579
    which can be shifted sideways to eliminate an equality.
1580
    e.g: A<ins>BA</ins>C -> <ins>AB</ins>AC
1581
    */
1582
0
    let mut changes = false;
1583
0
    i = 1;
1584
    // Intentionally ignore the first and last element (don't need checking).
1585
0
    while (i as usize) < diffs.len() - 1 {
1586
0
      if diffs[i as usize - 1].operation == 0 && diffs[i as usize + 1].operation == 0 {
1587
        // This is a single edit surrounded by equalities.
1588
0
        let text_vec: Vec<char> = diffs[i as usize].text.chars().collect();
1589
0
        let text1_vec: Vec<char> = diffs[i as usize - 1].text.chars().collect();
1590
0
        let text2_vec: Vec<char> = diffs[i as usize + 1].text.chars().collect();
1591
0
        if self.endswith(&text_vec, &text1_vec) {
1592
          // Shift the edit over the previous equality.
1593
0
          if !diffs[i as usize - 1].text.is_empty() {
1594
0
            let temp1: String = diffs[i as usize - 1].text.clone();
1595
0
            let temp2: String =
1596
0
              text_vec[..(text_vec.len() - text1_vec.len())].iter().collect();
1597
0
            diffs[i as usize].text = temp1 + temp2.as_str();
1598
0
            diffs[i as usize + 1].text = diffs[i as usize - 1].text.clone()
1599
0
              + diffs[i as usize + 1].text.as_str();
1600
0
          }
1601
0
          diffs.remove(i as usize - 1);
1602
0
          changes = true;
1603
0
        } else if self.startswith(&text_vec, &text2_vec) {
1604
0
          // Shift the edit over the next equality.
1605
0
          diffs[i as usize - 1].text =
1606
0
            diffs[i as usize - 1].text.clone() + diffs[i as usize + 1].text.as_str();
1607
0
          let temp1: String = text_vec[text2_vec.len()..].iter().collect();
1608
0
          diffs[i as usize].text = temp1 + diffs[i as usize + 1].text.as_str();
1609
0
          diffs.remove(i as usize + 1);
1610
0
          changes = true;
1611
0
        }
1612
0
      }
1613
0
      i += 1;
1614
    }
1615
    // If shifts were made, the diff needs reordering and another shift sweep.
1616
0
    if changes {
1617
0
      self.diff_cleanup_merge(diffs);
1618
0
    }
1619
0
  }
1620
1621
  /// It will check if first chars vector is endswith second chars vector or not.
1622
  ///
1623
  /// # Args
1624
  /// - first: First chars,
1625
  /// - second: Second chars.
1626
  ///
1627
  /// # Return
1628
  /// Return true if first chars vector endswith second chars vector, false otherwise.
1629
0
  fn endswith(&self, first: &[char], second: &[char]) -> bool {
1630
0
    let mut len1 = first.len();
1631
0
    let mut len2 = second.len();
1632
0
    if len1 < len2 {
1633
0
      return false;
1634
0
    }
1635
0
    while len2 > 0 {
1636
0
      if first[len1 - 1] != second[len2 - 1] {
1637
0
        return false;
1638
0
      }
1639
0
      len1 -= 1;
1640
0
      len2 -= 1;
1641
    }
1642
0
    true
1643
0
  }
1644
1645
  /// It will check if first chars vector is startswith second chars vector or not.
1646
  ///
1647
  /// # Args:
1648
  /// - first: First chars,
1649
  /// - second: Secodn chars.
1650
  ///
1651
  /// # Return
1652
  /// Return true if first chars vector startswith second chars vector, false otherwise.
1653
0
  fn startswith(&self, first: &[char], second: &[char]) -> bool {
1654
0
    let len1 = first.len();
1655
0
    let len2 = second.len();
1656
0
    if len1 < len2 {
1657
0
      return false;
1658
0
    }
1659
0
    for i in 0..len2 {
1660
0
      if first[i] != second[i] {
1661
0
        return false;
1662
0
      }
1663
    }
1664
0
    true
1665
0
  }
1666
1667
  /// loc is a location in text1, compute and return the equivalent location
1668
  /// in text2.  e.g. "The cat" vs "The big cat", 1->1, 5->8
1669
  ///
1670
  /// # Args
1671
  /// - diffs: Vector of diff object.
1672
  /// - loc: Location within text1.
1673
  ///
1674
  /// # Return
1675
  /// Location within text2.
1676
0
  fn diff_xindex(&self, diffs: &Vec<Diff>, loc: i32) -> i32 {
1677
0
    let mut chars1 = 0;
1678
0
    let mut chars2 = 0;
1679
0
    let mut last_chars1 = 0;
1680
0
    let mut last_chars2 = 0;
1681
0
    let mut lastdiff = Diff::new(0, "".to_string());
1682
0
    let z = 0;
1683
0
    for diffs_item in diffs {
1684
0
      if diffs_item.operation != 1 {
1685
0
        // Equality or deletion.
1686
0
        chars1 += diffs_item.text.chars().count() as i32;
1687
0
      }
1688
0
      if diffs_item.operation != -1 {
1689
0
        // Equality or insertion.
1690
0
        chars2 += diffs_item.text.chars().count() as i32;
1691
0
      }
1692
0
      if chars1 > loc {
1693
        // Overshot the location.
1694
0
        lastdiff = Diff::new(diffs_item.operation, diffs_item.text.clone());
1695
0
        break;
1696
0
      }
1697
0
      last_chars1 = chars1;
1698
0
      last_chars2 = chars2;
1699
    }
1700
0
    if lastdiff.operation == -1 && diffs.len() != z {
1701
      // The location was deleted.
1702
0
      return last_chars2;
1703
0
    }
1704
    // Add the remaining len(character).
1705
0
    last_chars2 + (loc - last_chars1)
1706
0
  }
1707
1708
  /// Compute and return the source text (all equalities and deletions).
1709
  ///
1710
  /// # Args
1711
  /// - diffs: Vector of diff object.
1712
  ///
1713
  /// # Return
1714
  /// Source text.
1715
0
  pub fn diff_text1(&self, diffs: &Vec<Diff>) -> String {
1716
0
    let mut text: String = "".to_string();
1717
0
    for adiff in diffs {
1718
0
      if adiff.operation != 1 {
1719
0
        text += adiff.text.as_str();
1720
0
      }
1721
    }
1722
0
    text
1723
0
  }
1724
1725
  /// Compute and return the destination text (all equalities and insertions).
1726
  ///
1727
  /// # Args
1728
  /// - diffs: Vector of diff object.
1729
  ///
1730
  /// # Return
1731
  /// Destination text.
1732
0
  pub fn diff_text2(&self, diffs: &mut Vec<Diff>) -> String {
1733
0
    let mut text: String = "".to_string();
1734
0
    for adiff in diffs {
1735
0
      if adiff.operation != -1 {
1736
0
        text += adiff.text.as_str();
1737
0
      }
1738
    }
1739
0
    text
1740
0
  }
1741
1742
  /// Compute the Levenshtein distance; the number of inserted, deleted or
1743
  /// substituted characters.
1744
  ///
1745
  /// # Args
1746
  /// - diffs: Vector of diff object.
1747
  ///
1748
  /// # Return
1749
  /// Number of changes.
1750
0
  pub fn diff_levenshtein(&self, diffs: &Vec<Diff>) -> i32 {
1751
0
    let mut levenshtein = 0;
1752
0
    let mut insertions = 0;
1753
0
    let mut deletions = 0;
1754
0
    for adiff in diffs {
1755
0
      if adiff.operation == 1 {
1756
0
        insertions += adiff.text.chars().count();
1757
0
      } else if adiff.operation == -1 {
1758
0
        deletions += adiff.text.chars().count();
1759
0
      } else {
1760
0
        // A deletion and an insertion is one substitution.
1761
0
        levenshtein += max(insertions as i32, deletions as i32);
1762
0
        insertions = 0;
1763
0
        deletions = 0;
1764
0
      }
1765
    }
1766
0
    levenshtein += max(insertions as i32, deletions as i32);
1767
0
    levenshtein
1768
0
  }
1769
1770
  //fn diff_todelta(&self, diffs: &mut Vec<Diff>) -> String {
1771
  //    self.diff_todelta_unit(diffs, LengthUnit::UnicodeScalar)
1772
  //}
1773
1774
  /*
1775
  /// Crush the diff into an encoded string which describes the operations
1776
  /// required to transform text1 into text2.
1777
  /// E.g. =3\t-2\t+ing  -> Keep 3 chars, delete 2 chars, insert 'ing'.
1778
  /// Operations are tab-separated.  Inserted text is escaped using %xx notation.
1779
  ///
1780
  /// # Args
1781
  /// - diffs: Vector of diff object.
1782
  /// - length_unit: Unit of length.
1783
  ///     For example diff from "🅰🅱" -> "🅱" can have different delta:
1784
  ///      * When operating on unicode scalars delta will be "-1\t=1"
1785
  ///      * For UTF-16 delta will be "-2\t=2"
1786
  ///
1787
  /// # Return
1788
  /// Delta text.
1789
  fn diff_todelta_unit(&self, diffs: &mut Vec<Diff>, length_unit: LengthUnit) -> String {
1790
    let mut text: String = "".to_string();
1791
    let len = diffs.len();
1792
    for (k, diffs_item) in diffs.iter().enumerate() {
1793
      if diffs_item.operation == 1 {
1794
        // High ascii will raise UnicodeDecodeError.  Use Unicode instead.
1795
        let temp5: Vec<char> = vec![
1796
          '!', '~', '*', '(', ')', ';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '#',
1797
          ' ', '\'',
1798
        ];
1799
        let temp4: Vec<char> = diffs_item.text.chars().collect();
1800
        text += "+";
1801
        for temp4_item in &temp4 {
1802
          let mut is = false;
1803
          for temp5_item in &temp5 {
1804
            if *temp5_item == *temp4_item {
1805
              text.push(*temp4_item);
1806
              is = true;
1807
              break;
1808
            }
1809
          }
1810
          if is {
1811
            continue;
1812
          }
1813
          let mut temp6 = "".to_string();
1814
          temp6.push(*temp4_item);
1815
          temp6 = encode(temp6.as_str()).into_owned();
1816
          text += temp6.as_str();
1817
        }
1818
      } else {
1819
        if diffs_item.operation == -1 {
1820
          text += "-";
1821
        } else {
1822
          text += "=";
1823
        }
1824
1825
        let count: usize;
1826
        match length_unit {
1827
          LengthUnit::UnicodeScalar => {
1828
            count = diffs_item.text.chars().count();
1829
          }
1830
          LengthUnit::UTF16 => {
1831
            count = diffs_item.text.encode_utf16().count();
1832
          }
1833
        }
1834
        text += count.to_string().as_str();
1835
      }
1836
1837
      if k < len - 1 {
1838
        text += "\t";
1839
      }
1840
    }
1841
    text
1842
  }
1843
  */
1844
1845
  /// Locate the best instance of 'pattern' in 'text' near 'loc'.
1846
  ///
1847
  /// # Args
1848
  /// - text: The text to search.
1849
  /// - pattern: The pattern to search for.
1850
  /// - loc: The location to search around.
1851
  ///
1852
  /// # Return
1853
  /// Best match index or -1.
1854
0
  pub fn match_main(&self, text1: &str, patern1: &str, mut loc: i32) -> Result<i32, Error> {
1855
0
    loc = max(0, min(loc, text1.len() as i32));
1856
0
    if patern1.is_empty() {
1857
0
      return Ok(loc);
1858
0
    }
1859
0
    if text1.is_empty() {
1860
0
      return Ok(-1);
1861
0
    }
1862
0
    let text: Vec<char> = (text1.to_string()).chars().collect();
1863
0
    let patern: Vec<char> = (patern1.to_string()).chars().collect();
1864
0
    if text == patern {
1865
      // Shortcut (potentially not guaranteed by the algorithm)
1866
0
      return Ok(0);
1867
0
    } else if loc as usize + patern.len() <= text.len()
1868
0
      && text[(loc as usize)..(loc as usize + patern.len())].to_vec() == patern
1869
    {
1870
      // Perfect match at the perfect spot!  (Includes case of null pattern)
1871
0
      return Ok(loc);
1872
0
    }
1873
0
    self.match_bitap(&text, &patern, loc)
1874
0
  }
1875
1876
  /// Locate the best instance of 'pattern' in 'text' near 'loc' using the
1877
  /// Bitap algorithm.
1878
  ///
1879
  /// # Args:
1880
  /// - text: The text to search.
1881
  /// - pattern: The pattern to search for.
1882
  /// - loc: The location to search around.
1883
  ///
1884
  /// # Return
1885
  /// Best match index or -1.
1886
0
  fn match_bitap(&self, text: &[char], patern: &[char], loc: i32) -> Result<i32, Error> {
1887
    // check for maxbits limit.
1888
0
    if !(self.match_maxbits == 0 || patern.len() as i32 <= self.match_maxbits) {
1889
0
      return Err(Error::PatternTooLong);
1890
0
    }
1891
    // Initialise the alphabet.
1892
0
    let s: HashMap<char, i32> = self.match_alphabet(patern);
1893
1894
    // Highest score beyond which we give up.
1895
0
    let mut score_threshold: f32 = self.match_threshold;
1896
    // Is there a nearby exact match? (speedup)
1897
0
    let mut best_loc = self.kmp(text, patern, loc as usize);
1898
0
    if best_loc != -1 {
1899
0
      score_threshold =
1900
0
        min1(self.match_bitap_score(0, best_loc, loc, patern), score_threshold);
1901
      // What about in the other direction? (speedup)
1902
0
      best_loc = self.rkmp(text, patern, loc as usize + patern.len());
1903
0
      if best_loc != -1 {
1904
0
        score_threshold =
1905
0
          min1(score_threshold, self.match_bitap_score(0, best_loc, loc, patern));
1906
0
      }
1907
0
    }
1908
    // Initialise the bit arrays.
1909
0
    let matchmask = 1 << (patern.len() - 1); //>
1910
0
    best_loc = -1;
1911
    let mut bin_min: i32;
1912
    let mut bin_mid: i32;
1913
0
    let mut bin_max: i32 = (patern.len() + text.len()) as i32;
1914
    // Empty initialization added to appease pychecker.
1915
0
    let mut last_rd: Vec<i32> = vec![];
1916
0
    for d in 0..patern.len() {
1917
      /*
1918
      Scan for the best match each iteration allows for one more error.
1919
      Run a binary search to determine how far from 'loc' we can stray at
1920
      this error level.
1921
      */
1922
0
      let mut rd: Vec<i32> = vec![];
1923
0
      bin_min = 0;
1924
0
      bin_mid = bin_max;
1925
      // Use the result from this iteration as the maximum for the next.
1926
0
      while bin_min < bin_mid {
1927
0
        if self.match_bitap_score(d as i32, loc + bin_mid, loc, patern) <= score_threshold {
1928
0
          bin_min = bin_mid;
1929
0
        } else {
1930
0
          bin_max = bin_mid;
1931
0
        }
1932
0
        bin_mid = bin_min + (bin_max - bin_min) / 2;
1933
      }
1934
0
      bin_max = bin_mid;
1935
0
      let mut start = max(1, loc - bin_mid + 1);
1936
0
      let finish = min(loc + bin_mid, text.len() as i32) + patern.len() as i32;
1937
0
      rd.resize((finish + 2) as usize, 0);
1938
0
      rd[(finish + 1) as usize] = (1 << d) - 1; //>
1939
0
      let mut j = finish;
1940
0
      while j >= start {
1941
        let char_match: i32;
1942
0
        if text.len() < j as usize {
1943
0
          // Out of range.
1944
0
          char_match = 0;
1945
0
        } else {
1946
          // Subsequent passes: fuzzy match.
1947
0
          match s.get(&(text[j as usize - 1])) {
1948
0
            Some(num) => {
1949
0
              char_match = *num;
1950
0
            }
1951
0
            None => {
1952
0
              char_match = 0;
1953
0
            }
1954
          }
1955
        }
1956
0
        if d == 0 {
1957
0
          // First pass: exact match.
1958
0
          rd[j as usize] = ((rd[j as usize + 1] << 1) | 1) & char_match;
1959
0
        //>>
1960
0
        } else {
1961
0
          rd[j as usize] = (((rd[j as usize + 1] << 1) | 1) & char_match)
1962
0
            | (((last_rd[j as usize + 1] | last_rd[j as usize]) << 1) | 1)
1963
0
            | last_rd[j as usize + 1]; //>>>>
1964
0
        }
1965
0
        if (rd[j as usize] & matchmask) != 0 {
1966
0
          let score: f32 = self.match_bitap_score(d as i32, j - 1, loc, patern);
1967
          // This match will almost certainly be better than any existing match.
1968
          // But check anyway.
1969
0
          if score <= score_threshold {
1970
            // Told you so.
1971
0
            score_threshold = score;
1972
0
            best_loc = j - 1;
1973
0
            if best_loc > loc {
1974
0
              // When passing loc, don't exceed our current distance from loc.
1975
0
              start = max(1, 2 * loc - best_loc);
1976
0
            } else {
1977
              // Already passed loc, downhill from here on in.
1978
0
              break;
1979
            }
1980
0
          }
1981
0
        }
1982
0
        j -= 1;
1983
      }
1984
      // No hope for a (better) match at greater error levels.
1985
0
      if self.match_bitap_score(d as i32 + 1, loc, loc, patern) > score_threshold {
1986
0
        break;
1987
0
      }
1988
0
      last_rd = rd;
1989
    }
1990
0
    Ok(best_loc)
1991
0
  }
1992
1993
  /// Compute and return the score for a match with e errors and x location.
1994
  /// Accesses loc and pattern through being a closure.
1995
  ///
1996
  /// # Args
1997
  /// - e: Number of errors in match.
1998
  /// - x: Location of match.
1999
  ///
2000
  /// # Return
2001
  /// Overall score for match (0.0 = good, 1.0 = bad).
2002
0
  fn match_bitap_score(&self, e: i32, x: i32, loc: i32, pattern: &[char]) -> f32 {
2003
0
    let accuracy: f32 = (e as f32) / (pattern.len() as f32);
2004
0
    let proximity: i32 = (loc - x).abs();
2005
0
    if self.match_distance == 0 {
2006
      // Dodge divide by zero error.
2007
0
      if proximity == 0 {
2008
0
        return accuracy;
2009
      } else {
2010
0
        return 1.0;
2011
      }
2012
0
    }
2013
0
    accuracy + ((proximity as f32) / (self.match_distance as f32))
2014
0
  }
2015
2016
  /// Initialise the alphabet for the Bitap algorithm.
2017
  ///
2018
  /// # Args:
2019
  /// - pattern: The text to encode.
2020
  ///
2021
  /// # Return
2022
  /// Hash of character locations.
2023
0
  fn match_alphabet(&self, pattern: &[char]) -> HashMap<char, i32> {
2024
0
    let mut s: HashMap<char, i32> = HashMap::new();
2025
0
    for patern_item in pattern {
2026
0
      s.insert(*patern_item, 0);
2027
0
    }
2028
0
    for i in 0..pattern.len() {
2029
0
      let ch: char = pattern[i];
2030
0
      let mut temp: i32 = 0;
2031
0
      if let Some(num) = s.get(&ch) {
2032
0
        temp = num | (1 << (pattern.len() - i - 1)); //>>
2033
0
      }
2034
0
      s.insert(ch, temp);
2035
    }
2036
0
    s
2037
0
  }
2038
2039
  /// Increase the context until it is unique,
2040
  /// but don't let the pattern expand beyond Match_MaxBits.
2041
  ///
2042
  /// Args:
2043
  /// - patch: The patch to grow.
2044
  /// - text: Source text.
2045
0
  fn patch_add_context(&self, patch: &mut Patch, text: &mut [char]) {
2046
0
    if text.is_empty() {
2047
0
      return;
2048
0
    }
2049
0
    let mut pattern: Vec<char> =
2050
0
      text[patch.start2 as usize..(patch.length1 as usize + patch.start2 as usize)].to_vec();
2051
0
    let mut padding: i32 = 0;
2052
2053
    // Look for the first and last matches of pattern in text.  If two different
2054
    // matches are found, increase the pattern length.
2055
0
    let mut rst = 0;
2056
0
    while self.kmp(text, &pattern, 0) != self.rkmp(text, &pattern, text.len() - 1)
2057
0
      && (pattern.len() as i32) < (self.match_maxbits - self.patch_margin * 2)
2058
    {
2059
0
      padding += self.patch_margin;
2060
0
      pattern = text[max(0, patch.start2 - padding) as usize
2061
0
        ..min(text.len() as i32, patch.start2 + patch.length1 + padding) as usize]
2062
0
        .to_vec();
2063
0
      rst += 1;
2064
0
      if rst > 5 {
2065
0
        break;
2066
0
      }
2067
    }
2068
    // Add one chunk for good luck.
2069
0
    padding += self.patch_margin;
2070
2071
    // Add the prefix.
2072
0
    let prefix: String =
2073
0
      text[max(0, patch.start2 - padding) as usize..patch.start2 as usize].iter().collect();
2074
0
    let prefix_length = prefix.chars().count() as i32;
2075
0
    if !prefix.is_empty() {
2076
0
      patch.diffs.insert(0, Diff::new(0, prefix.clone()));
2077
0
    }
2078
2079
    // Add the suffix.
2080
0
    let suffix: String = text[(patch.start2 + patch.length1) as usize
2081
0
      ..min(text.len() as i32, patch.start2 + patch.length1 + padding) as usize]
2082
0
      .iter()
2083
0
      .collect();
2084
0
    let suffix_length = suffix.chars().count() as i32;
2085
0
    if !suffix.is_empty() {
2086
0
      patch.diffs.push(Diff::new(0, suffix));
2087
0
    }
2088
    // Roll back the start points.
2089
0
    patch.start1 -= prefix_length;
2090
0
    patch.start2 -= prefix_length;
2091
    // Extend lengths.
2092
0
    patch.length1 += prefix_length + suffix_length;
2093
0
    patch.length2 += prefix_length + suffix_length;
2094
0
  }
2095
2096
  /// Compute a list of patches to turn text1 into text2.
2097
  /// compute diffs.
2098
  ///
2099
  /// # Args
2100
  /// - text1: First string.
2101
  /// - text2: Second string.
2102
  ///
2103
  /// # Return
2104
  /// Vector of Patch objects.
2105
0
  pub fn patch_make1(&self, text1: &str, text2: &str) -> Vec<Patch> {
2106
0
    let mut diffs: Vec<Diff> = self.diff_main(text1, text2, true);
2107
0
    if diffs.len() > 2 {
2108
0
      self.diff_cleanup_semantic(&mut diffs);
2109
0
      self.diff_cleanup_efficiency(&mut diffs);
2110
0
    }
2111
0
    self.patch_make4(text1, &diffs)
2112
0
  }
2113
2114
  /// Compute a list of patches to turn text1 into text2.
2115
  /// Use diffs to compute first text.
2116
  ///
2117
  /// # Args
2118
  /// - diffs: Vector of diff object.
2119
  ///
2120
  /// # Return
2121
  /// Vector of Patch objects.
2122
0
  pub fn patch_make2(&self, diffs: &Vec<Diff>) -> Vec<Patch> {
2123
0
    let text1 = self.diff_text1(diffs);
2124
0
    self.patch_make4(text1.as_str(), diffs)
2125
0
  }
2126
2127
  /// Compute a list of patches to turn text1 into text2.
2128
  ///
2129
  /// # Args
2130
  /// - text1: First string.
2131
  /// - text2: Second string.
2132
  /// - diffs: Vector of diff.
2133
  ///
2134
  /// # Return
2135
  /// Vector of Patch objects.
2136
0
  pub fn patch_make3(&self, text1: &str, _text2: &str, diffs: &[Diff]) -> Vec<Patch> {
2137
0
    self.patch_make4(text1, diffs)
2138
0
  }
2139
2140
  /// Compute a list of patches to turn text1 into text2.
2141
  ///
2142
  /// # Args
2143
  /// - text1: First string.
2144
  /// - diffs: Vector of diff object.
2145
  ///
2146
  /// # Return
2147
  /// Array of Patch objects.
2148
0
  pub fn patch_make4(&self, text1: &str, diffs: &[Diff]) -> Vec<Patch> {
2149
0
    let mut patches: Vec<Patch> = vec![];
2150
0
    if diffs.is_empty() {
2151
0
      return patches; // Get rid of the None case.
2152
0
    }
2153
0
    let mut patch: Patch = Patch::new(vec![], 0, 0, 0, 0);
2154
0
    let mut char_count1 = 0; // Number of characters into the text1 string.
2155
0
    let mut char_count2 = 0; // Number of characters into the text2 string.
2156
0
    let mut prepatch: Vec<char> = (text1.to_string()).chars().collect(); // Recreate the patches to determine context info.
2157
0
    let mut postpatch: Vec<char> = (text1.to_string()).chars().collect();
2158
0
    for i in 0..diffs.len() {
2159
0
      let temp1: &Vec<char> = &(diffs[i].text.chars().collect());
2160
0
      if patch.diffs.is_empty() && diffs[i].operation != 0 {
2161
0
        // A new patch starts here.
2162
0
        patch.start1 = char_count1;
2163
0
        patch.start2 = char_count2;
2164
0
      }
2165
0
      if diffs[i].operation == 1 {
2166
        // Insertion
2167
0
        patch.diffs.push(Diff::new(diffs[i].operation, diffs[i].text.clone()));
2168
0
        let temp: Vec<char> = postpatch[char_count2 as usize..].to_vec();
2169
0
        postpatch = postpatch[..char_count2 as usize].to_vec();
2170
0
        patch.length2 += temp1.len() as i32;
2171
0
        for ch in temp1 {
2172
0
          postpatch.push(*ch);
2173
0
        }
2174
0
        for ch in temp {
2175
0
          postpatch.push(ch);
2176
0
        }
2177
0
      } else if diffs[i].operation == -1 {
2178
        // Deletion.
2179
0
        patch.diffs.push(Diff::new(diffs[i].operation, diffs[i].text.clone()));
2180
0
        let temp: Vec<char> = postpatch[(temp1.len() + char_count2 as usize)..].to_vec();
2181
0
        postpatch = postpatch[..char_count2 as usize].to_vec();
2182
0
        patch.length1 += temp1.len() as i32;
2183
0
        for ch in &temp {
2184
0
          postpatch.push(*ch);
2185
0
        }
2186
      } else {
2187
0
        if temp1.len() as i32 <= self.patch_margin * 2
2188
0
          && !patch.diffs.is_empty()
2189
0
          && i != diffs.len() - 1
2190
0
        {
2191
0
          // Small equality inside a patch.
2192
0
          patch.diffs.push(Diff::new(diffs[i].operation, diffs[i].text.clone()));
2193
0
          patch.length1 += temp1.len() as i32;
2194
0
          patch.length2 += temp1.len() as i32;
2195
0
        }
2196
2197
        // Time for a new patch.
2198
0
        if temp1.len() as i32 >= 2 * self.patch_margin && !patch.diffs.is_empty() {
2199
0
          self.patch_add_context(&mut patch, &mut prepatch);
2200
0
          patches.push(patch);
2201
0
          patch = Patch::new(vec![], 0, 0, 0, 0);
2202
0
          prepatch = postpatch.clone();
2203
0
          char_count1 = char_count2;
2204
0
        }
2205
      }
2206
2207
      // Update the current character count.
2208
0
      if diffs[i].operation != 1 {
2209
0
        char_count1 += temp1.len() as i32;
2210
0
      }
2211
0
      if diffs[i].operation != -1 {
2212
0
        char_count2 += temp1.len() as i32;
2213
0
      }
2214
    }
2215
2216
    // Pick up the leftover patch if not empty.
2217
0
    if !patch.diffs.is_empty() {
2218
0
      self.patch_add_context(&mut patch, &mut prepatch);
2219
0
      // println!("{:?}", prepatch);
2220
0
      patches.push(patch);
2221
0
    }
2222
0
    patches
2223
0
  }
2224
2225
  /// Given an Vector of patches, return another Vector that is identical.
2226
  ///
2227
  /// Args:
2228
  /// - patches: Vector of Patch objects.
2229
  ///
2230
  /// Returns:
2231
  /// Vector of Patch objects.
2232
0
  fn patch_deep_copy(&self, patches: &[Patch]) -> Vec<Patch> {
2233
0
    patches.to_vec()
2234
0
  }
2235
2236
  /// Merge a set of patches onto the text.  Return a patched text, as well
2237
  /// as a list of true/false values indicating which patches were applied.
2238
  ///
2239
  /// # Args
2240
  /// - patches: Vector of Patch objects.
2241
  /// - text: Old text.
2242
  ///
2243
  /// # Return
2244
  /// Two element Vector, containing the new chars and an Vector of boolean values.
2245
0
  pub fn patch_apply(
2246
0
    &self,
2247
0
    patches: &[Patch],
2248
0
    source_text: &str,
2249
0
  ) -> Result<(Vec<char>, Vec<bool>), Error> {
2250
0
    if patches.is_empty() {
2251
0
      return Ok((source_text.chars().collect(), vec![]));
2252
0
    }
2253
2254
    // Deep copy the patches so that no changes are made to originals.
2255
0
    let mut patches_copy: Vec<Patch> = self.patch_deep_copy(patches);
2256
2257
0
    let null_padding: Vec<char> = self.patch_add_padding(&mut patches_copy)?;
2258
2259
0
    let mut text = null_padding.clone();
2260
0
    text.extend(source_text.chars());
2261
0
    text.extend(&null_padding);
2262
2263
0
    self.patch_splitmax(&mut patches_copy);
2264
2265
    // delta keeps track of the offset between the expected and actual location
2266
    // of the previous patch.  If there are patches expected at positions 10 and
2267
    // 20, but the first patch was found at 12, delta is 2 and the second patch
2268
    // has an effective expected position of 22.
2269
0
    let mut delta: i32 = 0;
2270
0
    let mut results: Vec<bool> = vec![false; patches_copy.len()];
2271
0
    for x in 0..patches_copy.len() {
2272
0
      let expected_loc: i32 = patches_copy[x].start2 + delta;
2273
0
      let text1: Vec<char> = self.diff_text1(&patches_copy[x].diffs).chars().collect();
2274
      let mut start_loc: i32;
2275
0
      let mut end_loc = -1;
2276
0
      if text1.len() as i32 > self.match_maxbits {
2277
        // patch_splitMax will only provide an oversized pattern in the case of
2278
        // a monster delete.
2279
0
        let first: String = (text[..]).iter().collect();
2280
0
        let second: String = text1[..self.match_maxbits as usize].iter().collect();
2281
0
        let second1: String =
2282
0
          text1[text1.len() - self.match_maxbits as usize..].iter().collect();
2283
0
        start_loc = self.match_main(first.as_str(), second.as_str(), expected_loc)?;
2284
0
        if start_loc != -1 {
2285
0
          end_loc = self.match_main(
2286
0
            first.as_str(),
2287
0
            second1.as_str(),
2288
0
            expected_loc + text1.len() as i32 - self.match_maxbits,
2289
0
          )?;
2290
0
          if end_loc == -1 || start_loc >= end_loc {
2291
0
            // Can't find valid trailing context.  Drop this patch.
2292
0
            start_loc = -1;
2293
0
          }
2294
0
        }
2295
      } else {
2296
0
        let first: String = text[..].iter().collect();
2297
0
        let second: String = text1[..].iter().collect();
2298
0
        start_loc = self.match_main(first.as_str(), second.as_str(), expected_loc)?;
2299
      }
2300
0
      if start_loc == -1 {
2301
0
        // No match found.  :(
2302
0
        results[x] = false;
2303
0
        // Subtract the delta for this failed patch from subsequent patches.
2304
0
        delta -= patches_copy[x].length2 - patches_copy[x].length1;
2305
0
      } else {
2306
        // Found a match.  :)
2307
0
        results[x] = true;
2308
0
        delta = start_loc - expected_loc;
2309
2310
        let mut end_index: usize;
2311
0
        if end_loc == -1 {
2312
0
          end_index = start_loc as usize + text1.len();
2313
0
        } else {
2314
0
          end_index = (end_loc + self.match_maxbits) as usize;
2315
0
        }
2316
0
        end_index = std::cmp::min(text.len(), end_index);
2317
2318
0
        let text2: Vec<char> = text[start_loc as usize..end_index].to_vec();
2319
2320
0
        if text1 == text2 {
2321
0
          // Perfect match, just shove the replacement text in.
2322
0
          let temp3: String = text[..start_loc as usize].iter().collect();
2323
0
          let temp4 = self.diff_text2(&mut patches_copy[x].diffs);
2324
0
          let temp5: String = text[(start_loc as usize + text1.len())..].iter().collect();
2325
0
          let temp6 = temp3 + temp4.as_str() + temp5.as_str();
2326
0
          text = temp6.chars().collect();
2327
0
        } else {
2328
          // Imperfect match.
2329
          // Run a diff to get a framework of equivalent indices.
2330
0
          let temp3: String = text1[..].iter().collect();
2331
0
          let temp4: String = text2[..].iter().collect();
2332
0
          let mut diffs: Vec<Diff> =
2333
0
            self.diff_main(temp3.as_str(), temp4.as_str(), false);
2334
0
          if text1.len() as i32 > self.match_maxbits
2335
0
            && (self.diff_levenshtein(&diffs) as f32 / (text1.len() as f32)
2336
0
              > self.patch_delete_threshold)
2337
0
          {
2338
0
            // The end points match, but the content is unacceptably bad.
2339
0
            results[x] = false;
2340
0
          } else {
2341
0
            self.diff_cleanup_semantic_lossless(&mut diffs);
2342
0
            let mut index1: i32 = 0;
2343
0
            for y in 0..patches_copy[x].diffs.len() {
2344
0
              let mod1 = patches_copy[x].diffs[y].clone();
2345
0
              if mod1.operation != 0 {
2346
0
                let index2: i32 = self.diff_xindex(&diffs, index1);
2347
0
                if mod1.operation == 1 {
2348
0
                  // Insertion
2349
0
                  let temp3: String =
2350
0
                    text[..(start_loc + index2) as usize].iter().collect();
2351
0
                  let temp4: String =
2352
0
                    text[(start_loc + index2) as usize..].iter().collect();
2353
0
                  let temp5 = temp3 + mod1.text.as_str() + temp4.as_str();
2354
0
                  text = temp5.chars().collect();
2355
0
                } else if mod1.operation == -1 {
2356
                  // Deletion
2357
0
                  let temp3: String =
2358
0
                    text[..(start_loc + index2) as usize].iter().collect();
2359
0
                  let diffs_text_len = mod1.text.chars().count();
2360
0
                  let temp4: String = text
2361
0
                    .get(
2362
0
                      (start_loc
2363
0
                        + self.diff_xindex(
2364
0
                          &diffs,
2365
0
                          index1 + diffs_text_len as i32,
2366
0
                        )) as usize..,
2367
0
                    )
2368
0
                    .ok_or(Error::MalformedPatch)?
2369
0
                    .iter()
2370
0
                    .collect();
2371
0
                  let temp5 = temp3 + temp4.as_str();
2372
0
                  text = temp5.chars().collect();
2373
0
                }
2374
0
              }
2375
0
              if mod1.operation != -1 {
2376
0
                index1 += mod1.text.chars().count() as i32;
2377
0
              }
2378
            }
2379
          }
2380
        }
2381
      }
2382
    }
2383
    // Strip the padding off.
2384
0
    text = text
2385
0
      .get(null_padding.len()..(text.len() - null_padding.len()))
2386
0
      .ok_or(Error::MalformedPatch)?
2387
0
      .to_vec();
2388
0
    Ok((text, results))
2389
0
  }
2390
2391
  /// Add some padding on text start and end so that edges can match
2392
  /// something.  Intended to be called only from within patch_apply.
2393
  ///
2394
  /// # Args
2395
  /// - patches: Array of Patch objects.
2396
  ///
2397
  /// # Return
2398
  /// The padding chars added to each side.
2399
0
  fn patch_add_padding(&self, patches: &mut Vec<Patch>) -> Result<Vec<char>, Error> {
2400
0
    let padding_length = self.patch_margin;
2401
0
    let mut nullpadding: Vec<char> = vec![];
2402
0
    for i in 0..padding_length {
2403
0
      if let Some(ch) = char::from_u32(1 + i as u32) {
2404
0
        nullpadding.push(ch);
2405
0
      }
2406
    }
2407
2408
    // Bump all the patches forward.
2409
0
    for p in &mut *patches {
2410
0
      p.start1 += padding_length;
2411
0
      p.start2 += padding_length;
2412
0
    }
2413
0
    let mut patch = patches[0].clone();
2414
0
    let mut diffs = patch.diffs;
2415
0
    if diffs.is_empty() {
2416
0
      return Err(Error::InvalidInput);
2417
0
    }
2418
0
    let mut text_len = diffs[0].text.chars().count() as i32;
2419
0
    if diffs.is_empty() || diffs[0].operation != 0 {
2420
0
      // Add nullPadding equality.
2421
0
      diffs.insert(0, Diff::new(0, nullpadding.clone().iter().collect()));
2422
0
      patch.start1 -= padding_length; // Should be 0.
2423
0
      patch.start2 -= padding_length; // Should be 0.
2424
0
      patch.length1 += padding_length;
2425
0
      patch.length2 += padding_length;
2426
0
    } else if padding_length > text_len {
2427
0
      // Grow first equality.
2428
0
      let extra_length = padding_length - text_len;
2429
0
      let mut new_text: String = nullpadding[text_len as usize..].iter().collect();
2430
0
      new_text += diffs[0].text.as_str();
2431
0
      diffs[0] = Diff::new(diffs[0].operation, new_text);
2432
0
      patch.start1 -= extra_length;
2433
0
      patch.start2 -= extra_length;
2434
0
      patch.length1 += extra_length;
2435
0
      patch.length2 += extra_length;
2436
0
    }
2437
2438
    // Add some padding on end of last diff.
2439
0
    patch.diffs = diffs;
2440
0
    patches[0] = patch;
2441
0
    patch = patches[patches.len() - 1].clone();
2442
0
    diffs = patch.diffs;
2443
0
    if diffs.is_empty() {
2444
0
      return Err(Error::InvalidInput);
2445
0
    }
2446
0
    text_len = diffs[diffs.len() - 1].text.chars().count() as i32;
2447
0
    if diffs.is_empty() || diffs[diffs.len() - 1].operation != 0 {
2448
0
      // Add nullPadding equality.
2449
0
      diffs.push(Diff::new(0, nullpadding.clone().iter().collect()));
2450
0
      patch.length1 += padding_length;
2451
0
      patch.length2 += padding_length;
2452
0
    } else if padding_length > text_len {
2453
0
      // Grow last equality.
2454
0
      let extra_length = padding_length - text_len;
2455
0
      let mut new_text: String = nullpadding[..extra_length as usize].iter().collect();
2456
0
      let diffs_len = diffs.len();
2457
0
      new_text = diffs[diffs_len - 1].text.clone() + new_text.as_str();
2458
0
      diffs[diffs_len - 1] = Diff::new(diffs[diffs_len - 1].operation, new_text);
2459
0
      patch.length1 += extra_length;
2460
0
      patch.length2 += extra_length;
2461
0
    }
2462
0
    patch.diffs = diffs;
2463
0
    let patches_len = patches.len();
2464
0
    patches[patches_len - 1] = patch;
2465
0
    Ok(nullpadding)
2466
0
  }
2467
2468
  /// Look through the patches and break up any which are longer than the
2469
  /// maximum limit of the match algorithm.
2470
  /// Intended to be called only from within patch_apply.
2471
  ///
2472
  /// # Args
2473
  /// - patches: Array of Patch objects.
2474
0
  fn patch_splitmax(&self, patches: &mut Vec<Patch>) {
2475
0
    let patch_size = self.match_maxbits;
2476
0
    if patch_size == 0 {
2477
0
      return;
2478
0
    }
2479
0
    let mut x: i32 = 0;
2480
0
    while (x as usize) < patches.len() {
2481
0
      if patches[x as usize].length1 <= patch_size {
2482
0
        x += 1;
2483
0
        continue;
2484
0
      }
2485
      // Remove the big old patch.
2486
0
      let mut bigpatch = patches.remove(x as usize);
2487
0
      x -= 1;
2488
0
      let mut start1 = bigpatch.start1;
2489
0
      let mut start2 = bigpatch.start2;
2490
0
      let mut precontext: Vec<char> = vec![];
2491
0
      while !bigpatch.diffs.is_empty() {
2492
        // Create one of several smaller patches.
2493
0
        let mut patch = Patch::new(vec![], 0, 0, 0, 0);
2494
0
        let mut empty = true;
2495
0
        patch.start1 = start1 - precontext.len() as i32;
2496
0
        patch.start2 = start2 - precontext.len() as i32;
2497
0
        if !precontext.is_empty() {
2498
0
          patch.length1 = precontext.len() as i32;
2499
0
          patch.length2 = precontext.len() as i32;
2500
0
          patch.diffs.push(Diff::new(0, precontext.clone().iter().collect()));
2501
0
        }
2502
0
        while !bigpatch.diffs.is_empty() && patch.length1 < patch_size - self.patch_margin {
2503
0
          let diff_type = bigpatch.diffs[0].operation;
2504
0
          let mut diff_text: Vec<char> = bigpatch.diffs[0].text.chars().collect();
2505
0
          if diff_type == 1 {
2506
0
            // Insertions are harmless.
2507
0
            patch.length2 += diff_text.len() as i32;
2508
0
            start2 += diff_text.len() as i32;
2509
0
            patch.diffs.push(bigpatch.diffs[0].clone());
2510
0
            bigpatch.diffs.remove(0);
2511
0
            empty = false;
2512
0
          } else if diff_type == -1
2513
0
            && patch.diffs.len() == 1
2514
0
            && patch.diffs[0].operation == 0
2515
0
            && (diff_text.len() as i32) > 2 * patch_size
2516
0
          {
2517
0
            // This is a large deletion.  Let it pass in one chunk.
2518
0
            patch.length1 += diff_text.len() as i32;
2519
0
            start1 += diff_text.len() as i32;
2520
0
            empty = false;
2521
0
            patch.diffs.push(Diff::new(diff_type, diff_text.iter().collect()));
2522
0
            bigpatch.diffs.remove(0);
2523
0
          } else {
2524
            // Deletion or equality.  Only take as much as we can stomach.
2525
0
            let diff_text_len: i32 = diff_text.len() as i32;
2526
0
            diff_text = diff_text[..min(
2527
0
              diff_text_len,
2528
0
              patch_size - patch.length1 - self.patch_margin,
2529
0
            ) as usize]
2530
0
              .to_vec();
2531
0
            patch.length1 += diff_text.len() as i32;
2532
0
            start1 += diff_text.len() as i32;
2533
0
            if diff_type == 0 {
2534
0
              patch.length2 += diff_text.len() as i32;
2535
0
              start2 += diff_text.len() as i32;
2536
0
            } else {
2537
0
              empty = false;
2538
0
            }
2539
0
            patch.diffs.push(Diff::new(diff_type, diff_text.clone().iter().collect()));
2540
0
            let temp: String = diff_text[..].iter().collect();
2541
0
            if temp == bigpatch.diffs[0].text.clone() {
2542
0
              bigpatch.diffs.remove(0);
2543
0
            } else {
2544
0
              let temp1: Vec<char> = bigpatch.diffs[0].text.chars().collect();
2545
0
              bigpatch.diffs[0].text = temp1[diff_text.len()..].iter().collect();
2546
0
            }
2547
          }
2548
        }
2549
        // Compute the head context for the next patch.
2550
0
        precontext = self.diff_text2(&mut patch.diffs).chars().collect();
2551
0
        precontext = precontext[(precontext.len()
2552
0
          - min(self.patch_margin, precontext.len() as i32) as usize)..]
2553
0
          .to_vec();
2554
        // Append the end context for this patch.
2555
0
        let postcontext = if self.diff_text1(&bigpatch.diffs).chars().count() as i32
2556
0
          > self.patch_margin
2557
        {
2558
0
          let temp: Vec<char> = self.diff_text1(&bigpatch.diffs).chars().collect();
2559
0
          temp[..self.patch_margin as usize].iter().collect()
2560
        } else {
2561
0
          self.diff_text1(&bigpatch.diffs)
2562
        };
2563
0
        let postcontext_len = postcontext.chars().count() as i32;
2564
0
        if !postcontext.is_empty() {
2565
0
          patch.length1 += postcontext_len;
2566
0
          patch.length2 += postcontext_len;
2567
0
          if !patch.diffs.is_empty() && patch.diffs[patch.diffs.len() - 1].operation == 0
2568
0
          {
2569
0
            let len = patch.diffs.len();
2570
0
            patch.diffs[len - 1].text += postcontext.as_str();
2571
0
          } else {
2572
0
            patch.diffs.push(Diff::new(0, postcontext));
2573
0
          }
2574
0
        }
2575
0
        if !empty {
2576
0
          x += 1;
2577
0
          patches.insert(x as usize, patch);
2578
0
        }
2579
      }
2580
0
      x += 1;
2581
    }
2582
0
  }
2583
2584
  /// Take a list of patches and return a textual representation.
2585
  ///
2586
  /// # Args
2587
  /// - patches: Vector of Patch objects.
2588
  ///
2589
  /// # Return
2590
  /// Text representation of patches.
2591
0
  pub fn patch_to_text(&self, patches: &[Patch]) -> String {
2592
0
    let mut text: String = String::new();
2593
0
    for patches_item in patches {
2594
0
      text += (patches_item.to_string()).as_str();
2595
0
    }
2596
0
    text
2597
0
  }
2598
2599
  /// Parse a textual representation of patches and return a list of patch
2600
  /// objects.
2601
  ///
2602
  /// # Args
2603
  /// - textline: Text representation of patches.
2604
  ///
2605
  /// # Return
2606
  /// Vector of Patch objects or error in case of invalid input.
2607
0
  pub fn patch_from_text(&self, textline: String) -> Result<Vec<Patch>, Error> {
2608
0
    let text: Vec<String> = self.split_by_chars(textline.as_str());
2609
0
    let mut patches: Vec<Patch> = vec![];
2610
0
    for (i, text_item) in text.iter().enumerate() {
2611
0
      if text_item.is_empty() {
2612
0
        if i == 0 {
2613
0
          continue;
2614
0
        }
2615
0
        return Err(Error::InvalidInput);
2616
0
      }
2617
0
      patches.push(self.patch1_from_text(text_item.clone())?);
2618
    }
2619
0
    Ok(patches)
2620
0
  }
2621
2622
0
  pub fn patch1_from_text(&self, textline: String) -> Result<Patch, Error> {
2623
0
    let text: Vec<String> = self.split_by_char(textline.as_str(), '\n');
2624
0
    let mut text_vec: Vec<char> = text[0].chars().collect();
2625
0
    if text_vec.len() < 8
2626
0
      || text_vec[text_vec.len() - 1] != '@'
2627
0
      || text_vec[text_vec.len() - 2] != '@'
2628
    {
2629
0
      return Err(Error::InvalidInput);
2630
0
    }
2631
0
    let mut patch = Patch::new(vec![], 0, 0, 0, 0);
2632
0
    let mut i = 0;
2633
0
    let mut temp: i32 = 0;
2634
0
    while i < text_vec.len() {
2635
0
      if text_vec[i] < '0' || text_vec[i] > '9' {
2636
0
        i += 1;
2637
0
        continue;
2638
0
      }
2639
0
      if (temp == 1 || temp == 3) && text_vec[i - 1] != ',' {
2640
0
        temp += 1;
2641
0
      }
2642
0
      let mut s = "".to_string();
2643
0
      while i < text_vec.len() && text_vec[i] >= '0' && text_vec[i] <= '9' {
2644
0
        s.push(text_vec[i]);
2645
0
        i += 1;
2646
0
      }
2647
0
      if temp == 0 {
2648
0
        patch.start1 = s.parse::<i32>().map_err(|_| Error::InvalidInput)? - 1;
2649
0
        temp += 1;
2650
0
      } else if temp == 1 {
2651
0
        patch.length1 = s.parse::<i32>().map_err(|_| Error::InvalidInput)?;
2652
0
        temp += 1;
2653
0
      } else if temp == 2 {
2654
0
        patch.start2 = s.parse::<i32>().map_err(|_| Error::InvalidInput)? - 1;
2655
0
        temp += 1;
2656
0
      } else if temp == 3 {
2657
0
        patch.length2 = s.parse::<i32>().map_err(|_| Error::InvalidInput)?;
2658
0
        temp += 1;
2659
      } else {
2660
0
        return Err(Error::InvalidInput);
2661
      }
2662
0
      i += 1;
2663
    }
2664
0
    patch.length1 = 0;
2665
0
    patch.length2 = 0;
2666
0
    for text_item in text.iter().take(text.len() - 1).skip(1) {
2667
0
      text_vec = text_item.chars().collect();
2668
0
      match text_vec.first().ok_or(Error::InvalidInput)? {
2669
        '+' => {
2670
          // Insertion.
2671
0
          let mut temp6: String = text_vec[1..].iter().collect();
2672
0
          temp6 = decode(temp6.as_str()).map_err(|_| Error::InvalidInput)?.into_owned();
2673
0
          patch.length2 += temp6.chars().count() as i32;
2674
0
          patch.diffs.push(Diff::new(1, temp6));
2675
        }
2676
        '-' => {
2677
          // Deletion.
2678
0
          let mut temp6: String = text_vec[1..].iter().collect();
2679
0
          temp6 = decode(temp6.as_str()).map_err(|_| Error::InvalidInput)?.into_owned();
2680
0
          patch.length1 += temp6.chars().count() as i32;
2681
0
          patch.diffs.push(Diff::new(-1, temp6));
2682
        }
2683
        ' ' => {
2684
          // Minor equality.
2685
0
          let mut temp6: String = text_vec[1..].iter().collect();
2686
0
          temp6 = decode(temp6.as_str()).map_err(|_| Error::InvalidInput)?.into_owned();
2687
0
          patch.length1 += temp6.chars().count() as i32;
2688
0
          patch.length2 += temp6.chars().count() as i32;
2689
0
          patch.diffs.push(Diff::new(0, temp6));
2690
        }
2691
        _ => {
2692
0
          return Err(Error::InvalidInput);
2693
        }
2694
      }
2695
    }
2696
0
    Ok(patch)
2697
0
  }
2698
}