Skip to content

Commit

Permalink
Add xdiff patch application code and share it with GitChangesetPatch
Browse files Browse the repository at this point in the history
  • Loading branch information
glandium committed May 10, 2020
1 parent a1b5ba6 commit 7446d02
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 17 deletions.
28 changes: 16 additions & 12 deletions helper/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use crate::libgit::{BlobId, CommitId, RawBlob, RawCommit};
use crate::oid::{HgObjectId, ObjectId};
use crate::oid_type;
use crate::util::{FromBytes, SliceExt};
use crate::xdiff::{apply, PatchInfo};

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

impl<'a> GitChangesetPatch<'a> {
pub fn iter(&self) -> Option<impl Iterator<Item = PatchInfo<Cow<'a, [u8]>>>> {
self.0
.split(|c| *c == b'\0')
.map(|part| {
let (start, end, data) = part.split3(b',')?;
let start = usize::from_bytes(start).ok()?;
let end = usize::from_bytes(end).ok()?;
let data = Cow::from(percent_decode(data));
Some(PatchInfo { start, end, data })
})
.collect::<Option<Vec<_>>>()
.map(|v| v.into_iter())
}

pub fn apply(&self, input: &[u8]) -> Option<Vec<u8>> {
let mut patched = Vec::new();
let mut last_end = 0;
for part in self.0.split(|c| *c == b'\0') {
let (start, end, data) = part.split3(b',')?;
let start = usize::from_bytes(start).ok()?;
let data = Cow::from(percent_decode(data));
patched.extend_from_slice(&input[last_end..start]);
patched.extend_from_slice(&data);
last_end = usize::from_bytes(end).ok()?;
}
patched.extend_from_slice(&input[last_end..]);
Some(patched)
Some(apply(self.iter()?, input))
}
}

Expand Down
22 changes: 17 additions & 5 deletions helper/xdiff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,17 +67,29 @@ extern "C" {
) -> c_int;
}

#[derive(Derivative, PartialEq)]
#[derive(Clone, Copy, Derivative, PartialEq)]
#[derivative(Debug)]
pub struct PatchInfo<'a> {
pub struct PatchInfo<S: AsRef<[u8]>> {
pub start: usize,
pub end: usize,
#[derivative(Debug(format_with = "crate::util::bstr_fmt"))]
pub data: &'a [u8],
pub data: S,
}

pub fn apply<S: AsRef<[u8]>>(patch: impl Iterator<Item = PatchInfo<S>>, input: &[u8]) -> Vec<u8> {
let mut patched = Vec::new();
let mut last_end = 0;
for PatchInfo { start, end, data } in patch {
patched.extend_from_slice(&input[last_end..start]);
patched.extend_from_slice(data.as_ref());
last_end = end;
}
patched.extend_from_slice(&input[last_end..]);
patched
}

struct HunkContext<'a> {
patch_info: Vec<PatchInfo<'a>>,
patch_info: Vec<PatchInfo<&'a [u8]>>,
a_line_offsets: Vec<usize>,
b_line_offsets: Vec<usize>,
b: &'a [u8],
Expand Down Expand Up @@ -121,7 +133,7 @@ fn line_offsets(buf: &[u8]) -> Vec<usize> {
.collect()
}

pub fn textdiff<'a>(a: &[u8], b: &'a [u8]) -> Vec<PatchInfo<'a>> {
pub fn textdiff<'a>(a: &[u8], b: &'a [u8]) -> Vec<PatchInfo<&'a [u8]>> {
let mut ctx = HunkContext {
patch_info: Vec::new(),
a_line_offsets: line_offsets(a),
Expand Down

0 comments on commit 7446d02

Please sign in to comment.