summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortummychow <tummychow@users.noreply.github.com>2018-02-25 23:32:46 -0800
committertummychow <tummychow@users.noreply.github.com>2018-02-25 23:32:46 -0800
commit2170218bbb752819afa489ff5d4f715edf6a8edb (patch)
tree265c8632b1e909a66607c187d943a6062932e020
parent9d6aea560654ec7ef7903b20100feb445a451db7 (diff)
implement commuting against an entire patch
-rw-r--r--src/commute.rs64
1 files changed, 64 insertions, 0 deletions
diff --git a/src/commute.rs b/src/commute.rs
index 85a996e..3741225 100644
--- a/src/commute.rs
+++ b/src/commute.rs
@@ -103,6 +103,25 @@ pub fn commute(first: &owned::Hunk, second: &owned::Hunk) -> Option<(owned::Hunk
})
}
+pub fn commute_diff_before<'a, I>(after: &owned::Hunk, before: I) -> Option<owned::Hunk>
+where
+ I: iter::IntoIterator<Item = &'a owned::Hunk>,
+ <I as iter::IntoIterator>::IntoIter: iter::DoubleEndedIterator,
+{
+ before
+ .into_iter()
+ // the patch's hunks must be iterated in reverse application
+ // order (last applied to first applied), which also happens
+ // to be reverse line order (bottom to top), which also
+ // happens to be reverse of the order they're stored
+ .rev()
+ .fold(Some(after.clone()), |after, next| {
+ after
+ .and_then(|after| commute(next, &after))
+ .map(|(commuted_after, _)| commuted_after)
+ })
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -173,4 +192,49 @@ mod tests {
assert_eq!(new1.added.lines.len(), 2);
assert_eq!(new2.added.lines.len(), 4);
}
+
+ #[test]
+ fn test_commute_patch() {
+ let patch = vec![
+ owned::Hunk {
+ added: owned::Block {
+ start: 1,
+ lines: Rc::new(vec![b"bar\n".to_vec()]),
+ trailing_newline: true,
+ },
+ removed: owned::Block {
+ start: 0,
+ lines: Rc::new(vec![]),
+ trailing_newline: true,
+ },
+ },
+ owned::Hunk {
+ added: owned::Block {
+ start: 3,
+ lines: Rc::new(vec![b"bar\n".to_vec()]),
+ trailing_newline: true,
+ },
+ removed: owned::Block {
+ start: 1,
+ lines: Rc::new(vec![]),
+ trailing_newline: true,
+ },
+ },
+ ];
+ let hunk = owned::Hunk {
+ added: owned::Block {
+ start: 5,
+ lines: Rc::new(vec![b"bar\n".to_vec()]),
+ trailing_newline: true,
+ },
+ removed: owned::Block {
+ start: 4,
+ lines: Rc::new(vec![]),
+ trailing_newline: true,
+ },
+ };
+
+ let commuted = commute_diff_before(&hunk, &patch).unwrap();
+ assert_eq!(commuted.added.start, 3);
+ }
}