Start implementing merge, for #23
This commit is contained in:
parent
d241da35fb
commit
df39e658cd
2 changed files with 207 additions and 0 deletions
|
@ -29,6 +29,7 @@ use std::net::{IpAddr, SocketAddr};
|
||||||
|
|
||||||
mod assets;
|
mod assets;
|
||||||
mod db;
|
mod db;
|
||||||
|
mod merge;
|
||||||
mod mimes;
|
mod mimes;
|
||||||
mod models;
|
mod models;
|
||||||
mod rendering;
|
mod rendering;
|
||||||
|
|
206
src/merge.rs
Normal file
206
src/merge.rs
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
|
use diff;
|
||||||
|
use diff::Result::*;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
struct Chunk(Range<usize>, Range<usize>);
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
enum ChunkKind {
|
||||||
|
Stable,
|
||||||
|
Unstable,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
struct ChunkItem {
|
||||||
|
kind: ChunkKind,
|
||||||
|
chunk: Chunk,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChunkItem {
|
||||||
|
fn stable(chunk: Chunk) -> ChunkItem {
|
||||||
|
ChunkItem {
|
||||||
|
kind: ChunkKind::Stable,
|
||||||
|
chunk: chunk,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unstable(chunk: Chunk) -> ChunkItem {
|
||||||
|
ChunkItem {
|
||||||
|
kind: ChunkKind::Unstable,
|
||||||
|
chunk: chunk,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MergeIterator<Item> {
|
||||||
|
left: Vec<diff::Result<Item>>,
|
||||||
|
right: Vec<diff::Result<Item>>,
|
||||||
|
|
||||||
|
a: usize,
|
||||||
|
o: usize,
|
||||||
|
b: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Item> MergeIterator<Item> {
|
||||||
|
fn new(left: Vec<diff::Result<Item>>, right: Vec<diff::Result<Item>>) -> MergeIterator<Item> {
|
||||||
|
MergeIterator {
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
a: 0,
|
||||||
|
o: 0,
|
||||||
|
b: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Item> Iterator for MergeIterator<Item>
|
||||||
|
where
|
||||||
|
Item: ::std::fmt::Debug + PartialEq
|
||||||
|
{
|
||||||
|
type Item = ChunkItem;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let mut i = 0;
|
||||||
|
while let (Some(&Both(..)), Some(&Both(..))) = (self.left.get(self.a+i), self.right.get(self.b+i)) {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
if i > 0 {
|
||||||
|
let chunk = ChunkItem::stable(Chunk(self.a..self.a+i, self.b..self.b+i));
|
||||||
|
self.a += i;
|
||||||
|
self.o += i;
|
||||||
|
self.b += i;
|
||||||
|
return Some(chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut a = self.a;
|
||||||
|
let mut o = self.o;
|
||||||
|
let mut b = self.b;
|
||||||
|
loop {
|
||||||
|
match (self.left.get(a), self.right.get(b)) {
|
||||||
|
(Some(&Right(_)), _) => {
|
||||||
|
a += 1;
|
||||||
|
},
|
||||||
|
(_, Some(&Right(_))) => {
|
||||||
|
b += 1;
|
||||||
|
},
|
||||||
|
(Some(&Left(_)), Some(_)) => {
|
||||||
|
a += 1;
|
||||||
|
o += 1;
|
||||||
|
b += 1;
|
||||||
|
},
|
||||||
|
(Some(_), Some(&Left(_))) => {
|
||||||
|
a += 1;
|
||||||
|
o += 1;
|
||||||
|
b += 1;
|
||||||
|
},
|
||||||
|
(Some(&Both(..)), Some(&Both(..))) => {
|
||||||
|
let chunk = ChunkItem::unstable(Chunk(self.a..a, self.b..b));
|
||||||
|
self.a = a;
|
||||||
|
self.o = o;
|
||||||
|
self.b = b;
|
||||||
|
return Some(chunk);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if self.a < self.left.len() || self.b < self.right.len() {
|
||||||
|
let chunk = ChunkItem::unstable(Chunk(self.a..self.left.len(), self.b..self.right.len()));
|
||||||
|
self.a = self.left.len();
|
||||||
|
self.b = self.right.len();
|
||||||
|
return Some(chunk);
|
||||||
|
}
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use diff;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn simple_case() {
|
||||||
|
let o = "aaabbbccc";
|
||||||
|
let a = "aaaxxxbbbccc";
|
||||||
|
let b = "aaabbbyyyccc";
|
||||||
|
|
||||||
|
let oa = diff::chars(o, a);
|
||||||
|
let ob = diff::chars(o, b);
|
||||||
|
|
||||||
|
let merge = MergeIterator::new(oa, ob).collect::<Vec<_>>();
|
||||||
|
assert_eq!(vec![
|
||||||
|
ChunkItem::stable(Chunk(0..3, 0..3)),
|
||||||
|
ChunkItem::unstable(Chunk(3..6, 3..3)),
|
||||||
|
ChunkItem::stable(Chunk(6..9, 3..6)),
|
||||||
|
ChunkItem::unstable(Chunk(9..9, 6..9)),
|
||||||
|
ChunkItem::stable(Chunk(9..12, 9..12)),
|
||||||
|
], merge);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn real_conflict() {
|
||||||
|
let o = "aaabbbccc";
|
||||||
|
let a = "aaaxxxccc";
|
||||||
|
let b = "aaayyyccc";
|
||||||
|
|
||||||
|
let oa = diff::chars(o, a);
|
||||||
|
let ob = diff::chars(o, b);
|
||||||
|
|
||||||
|
let merge = MergeIterator::new(oa, ob).collect::<Vec<_>>();
|
||||||
|
assert_eq!(vec![
|
||||||
|
ChunkItem::stable(Chunk(0..3, 0..3)),
|
||||||
|
ChunkItem::unstable(Chunk(3..9, 3..9)),
|
||||||
|
ChunkItem::stable(Chunk(9..12, 9..12)),
|
||||||
|
], merge);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn additional_at_end() {
|
||||||
|
let o = "aaabbbccc";
|
||||||
|
let a = "aaabbbccc";
|
||||||
|
let b = "aaabbbcccddd";
|
||||||
|
|
||||||
|
let oa = diff::chars(o, a);
|
||||||
|
let ob = diff::chars(o, b);
|
||||||
|
|
||||||
|
let merge = MergeIterator::new(oa, ob).collect::<Vec<_>>();
|
||||||
|
assert_eq!(vec![
|
||||||
|
ChunkItem::stable(Chunk(0..9, 0..9)),
|
||||||
|
ChunkItem::unstable(Chunk(9..9, 9..12)),
|
||||||
|
], merge);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn additional_at_end_2() {
|
||||||
|
let o = "aaabbb";
|
||||||
|
let a = "aaabbbccc";
|
||||||
|
let b = "aaabbbcccddd";
|
||||||
|
|
||||||
|
let oa = diff::chars(o, a);
|
||||||
|
let ob = diff::chars(o, b);
|
||||||
|
|
||||||
|
let merge = MergeIterator::new(oa, ob).collect::<Vec<_>>();
|
||||||
|
assert_eq!(vec![
|
||||||
|
ChunkItem::stable(Chunk(0..6, 0..6)),
|
||||||
|
ChunkItem::unstable(Chunk(6..9, 6..12)),
|
||||||
|
], merge);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn completely_unrelated() {
|
||||||
|
let o = "aaa";
|
||||||
|
let a = "bbb";
|
||||||
|
let b = "ccc";
|
||||||
|
|
||||||
|
let oa = diff::chars(o, a);
|
||||||
|
let ob = diff::chars(o, b);
|
||||||
|
|
||||||
|
let merge = MergeIterator::new(oa, ob).collect::<Vec<_>>();
|
||||||
|
assert_eq!(vec![
|
||||||
|
ChunkItem::unstable(Chunk(0..6, 0..6)),
|
||||||
|
], merge);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue