Skip to content

Commit 7446d02

Browse files
committed
Add xdiff patch application code and share it with GitChangesetPatch
1 parent a1b5ba6 commit 7446d02

File tree

2 files changed

+33
-17
lines changed

2 files changed

+33
-17
lines changed

helper/store.rs

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use crate::libgit::{BlobId, CommitId, RawBlob, RawCommit};
1919
use crate::oid::{HgObjectId, ObjectId};
2020
use crate::oid_type;
2121
use crate::util::{FromBytes, SliceExt};
22+
use crate::xdiff::{apply, PatchInfo};
2223

2324
macro_rules! hg2git {
2425
($h:ident => $g:ident($i:ident)) => {
@@ -194,19 +195,22 @@ impl<'a> Iterator for ChangesetFilesIter<'a> {
194195
pub struct GitChangesetPatch<'a>(&'a [u8]);
195196

196197
impl<'a> GitChangesetPatch<'a> {
198+
pub fn iter(&self) -> Option<impl Iterator<Item = PatchInfo<Cow<'a, [u8]>>>> {
199+
self.0
200+
.split(|c| *c == b'\0')
201+
.map(|part| {
202+
let (start, end, data) = part.split3(b',')?;
203+
let start = usize::from_bytes(start).ok()?;
204+
let end = usize::from_bytes(end).ok()?;
205+
let data = Cow::from(percent_decode(data));
206+
Some(PatchInfo { start, end, data })
207+
})
208+
.collect::<Option<Vec<_>>>()
209+
.map(|v| v.into_iter())
210+
}
211+
197212
pub fn apply(&self, input: &[u8]) -> Option<Vec<u8>> {
198-
let mut patched = Vec::new();
199-
let mut last_end = 0;
200-
for part in self.0.split(|c| *c == b'\0') {
201-
let (start, end, data) = part.split3(b',')?;
202-
let start = usize::from_bytes(start).ok()?;
203-
let data = Cow::from(percent_decode(data));
204-
patched.extend_from_slice(&input[last_end..start]);
205-
patched.extend_from_slice(&data);
206-
last_end = usize::from_bytes(end).ok()?;
207-
}
208-
patched.extend_from_slice(&input[last_end..]);
209-
Some(patched)
213+
Some(apply(self.iter()?, input))
210214
}
211215
}
212216

helper/xdiff.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,29 @@ extern "C" {
6767
) -> c_int;
6868
}
6969

70-
#[derive(Derivative, PartialEq)]
70+
#[derive(Clone, Copy, Derivative, PartialEq)]
7171
#[derivative(Debug)]
72-
pub struct PatchInfo<'a> {
72+
pub struct PatchInfo<S: AsRef<[u8]>> {
7373
pub start: usize,
7474
pub end: usize,
7575
#[derivative(Debug(format_with = "crate::util::bstr_fmt"))]
76-
pub data: &'a [u8],
76+
pub data: S,
77+
}
78+
79+
pub fn apply<S: AsRef<[u8]>>(patch: impl Iterator<Item = PatchInfo<S>>, input: &[u8]) -> Vec<u8> {
80+
let mut patched = Vec::new();
81+
let mut last_end = 0;
82+
for PatchInfo { start, end, data } in patch {
83+
patched.extend_from_slice(&input[last_end..start]);
84+
patched.extend_from_slice(data.as_ref());
85+
last_end = end;
86+
}
87+
patched.extend_from_slice(&input[last_end..]);
88+
patched
7789
}
7890

7991
struct HunkContext<'a> {
80-
patch_info: Vec<PatchInfo<'a>>,
92+
patch_info: Vec<PatchInfo<&'a [u8]>>,
8193
a_line_offsets: Vec<usize>,
8294
b_line_offsets: Vec<usize>,
8395
b: &'a [u8],
@@ -121,7 +133,7 @@ fn line_offsets(buf: &[u8]) -> Vec<usize> {
121133
.collect()
122134
}
123135

124-
pub fn textdiff<'a>(a: &[u8], b: &'a [u8]) -> Vec<PatchInfo<'a>> {
136+
pub fn textdiff<'a>(a: &[u8], b: &'a [u8]) -> Vec<PatchInfo<&'a [u8]>> {
125137
let mut ctx = HunkContext {
126138
patch_info: Vec::new(),
127139
a_line_offsets: line_offsets(a),

0 commit comments

Comments
 (0)