Skip to main content

java_diff_utils_rs/unifieddiff/
unified_diff.rs

1//! Data structure representing a complete Unified Diff document containing zero or more file diffs.
2
3use super::unified_diff_file::UnifiedDiffFile;
4use crate::patch::patch_failed_exception::PatchFailedException;
5
6/// Container for unified diff header, tail, and multi-file patches.
7#[derive(Debug, Clone, Default, PartialEq, Eq)]
8pub struct UnifiedDiff {
9    header: Option<String>,
10    tail: Option<String>,
11    files: Vec<UnifiedDiffFile>,
12}
13
14impl UnifiedDiff {
15    /// Creates a new, empty `UnifiedDiff`.
16    pub fn new() -> Self {
17        Self::default()
18    }
19
20    pub fn header(&self) -> Option<&str> {
21        self.header.as_deref()
22    }
23
24    pub fn set_header(&mut self, header: impl Into<String>) {
25        self.header = Some(header.into());
26    }
27
28    pub fn add_file(&mut self, file: UnifiedDiffFile) {
29        self.files.push(file);
30    }
31
32    pub fn files(&self) -> &[UnifiedDiffFile] {
33        &self.files
34    }
35
36    pub fn files_mut(&mut self) -> &mut Vec<UnifiedDiffFile> {
37        &mut self.files
38    }
39
40    pub fn set_tail_txt(&mut self, tail_txt: impl Into<String>) {
41        self.tail = Some(tail_txt.into());
42    }
43
44    pub fn tail(&self) -> Option<&str> {
45        self.tail.as_deref()
46    }
47
48    /// Finds the target file matching `find_file` predicate and applies its patch to `original_lines`.
49    ///
50    /// If no file matches, returns `original_lines` unchanged.
51    pub fn apply_patch_to<F>(
52        &mut self,
53        find_file: F,
54        original_lines: &[String],
55    ) -> Result<Vec<String>, PatchFailedException>
56    where
57        F: Fn(&str) -> bool,
58    {
59        let target_file = self
60            .files
61            .iter_mut()
62            .find(|diff| diff.from_file().map(&find_file).unwrap_or(false));
63
64        if let Some(file) = target_file {
65            Ok(file.patch_mut().apply_to(original_lines)?)
66        } else {
67            Ok(original_lines.to_vec())
68        }
69    }
70
71    /// Constructs a `UnifiedDiff` from optional header, tail, and a sequence of files.
72    pub fn from(
73        header: Option<impl Into<String>>,
74        tail: Option<impl Into<String>>,
75        files: Vec<UnifiedDiffFile>,
76    ) -> Self {
77        let mut diff = Self::new();
78        if let Some(h) = header {
79            diff.set_header(h);
80        }
81        if let Some(t) = tail {
82            diff.set_tail_txt(t);
83        }
84        for file in files {
85            diff.add_file(file);
86        }
87        diff
88    }
89}