use super::cursor::DiffCursor;
use super::error::{Diff, Error};
use super::store::Store;
use super::tree::Tree;
pub trait StreamingDiffer<S: Store> {
fn stream_diff<'a>(
&'a self,
store: &'a S,
base: &Tree,
other: &Tree,
) -> Result<Box<dyn Iterator<Item = Result<Diff, Error>> + 'a>, Error>;
}
#[derive(Debug, Default, Clone, Copy)]
pub struct DefaultStreamingDiffer;
impl DefaultStreamingDiffer {
pub fn new() -> Self {
Self
}
}
impl<S: Store> StreamingDiffer<S> for DefaultStreamingDiffer {
fn stream_diff<'a>(
&'a self,
store: &'a S,
base: &Tree,
other: &Tree,
) -> Result<Box<dyn Iterator<Item = Result<Diff, Error>> + 'a>, Error> {
if base.root == other.root {
return Ok(Box::new(std::iter::empty()));
}
let diff_cursor = DiffCursor::new(store, base, other)?;
Ok(Box::new(diff_cursor.map(Ok)))
}
}
#[cfg(test)]
mod tests {
use super::super::config::Config;
use super::super::store::MemStore;
use super::super::Prolly;
use super::*;
use std::sync::Arc;
#[test]
fn test_streaming_diff_identical_trees() {
let store = Arc::new(MemStore::new());
let prolly = Prolly::new(store.clone(), Config::default());
let tree = prolly
.put(&prolly.create(), b"a".to_vec(), b"1".to_vec())
.unwrap();
let differ = DefaultStreamingDiffer::new();
let diffs: Vec<_> = differ
.stream_diff(store.as_ref(), &tree, &tree)
.unwrap()
.collect();
assert!(diffs.is_empty());
}
#[test]
fn test_streaming_diff_empty_base() {
let store = Arc::new(MemStore::new());
let prolly = Prolly::new(store.clone(), Config::default());
let base = prolly.create();
let other = prolly.put(&base, b"a".to_vec(), b"1".to_vec()).unwrap();
let differ = DefaultStreamingDiffer::new();
let diffs: Vec<_> = differ
.stream_diff(store.as_ref(), &base, &other)
.unwrap()
.filter_map(|r| r.ok())
.collect();
assert_eq!(diffs.len(), 1);
assert!(matches!(
&diffs[0],
Diff::Added { key, val } if key == b"a" && val == b"1"
));
}
#[test]
fn test_streaming_diff_empty_other() {
let store = Arc::new(MemStore::new());
let prolly = Prolly::new(store.clone(), Config::default());
let base = prolly
.put(&prolly.create(), b"a".to_vec(), b"1".to_vec())
.unwrap();
let other = prolly.create();
let differ = DefaultStreamingDiffer::new();
let diffs: Vec<_> = differ
.stream_diff(store.as_ref(), &base, &other)
.unwrap()
.filter_map(|r| r.ok())
.collect();
assert_eq!(diffs.len(), 1);
assert!(matches!(
&diffs[0],
Diff::Removed { key, val } if key == b"a" && val == b"1"
));
}
#[test]
fn test_streaming_diff_changed_value() {
let store = Arc::new(MemStore::new());
let prolly = Prolly::new(store.clone(), Config::default());
let base = prolly
.put(&prolly.create(), b"a".to_vec(), b"1".to_vec())
.unwrap();
let other = prolly.put(&base, b"a".to_vec(), b"2".to_vec()).unwrap();
let differ = DefaultStreamingDiffer::new();
let diffs: Vec<_> = differ
.stream_diff(store.as_ref(), &base, &other)
.unwrap()
.filter_map(|r| r.ok())
.collect();
assert_eq!(diffs.len(), 1);
assert!(matches!(
&diffs[0],
Diff::Changed { key, old, new } if key == b"a" && old == b"1" && new == b"2"
));
}
#[test]
fn test_streaming_diff_lexicographic_order() {
let store = Arc::new(MemStore::new());
let prolly = Prolly::new(store.clone(), Config::default());
let base = prolly.create();
let mut other = base.clone();
other = prolly.put(&other, b"c".to_vec(), b"3".to_vec()).unwrap();
other = prolly.put(&other, b"a".to_vec(), b"1".to_vec()).unwrap();
other = prolly.put(&other, b"b".to_vec(), b"2".to_vec()).unwrap();
let differ = DefaultStreamingDiffer::new();
let diffs: Vec<_> = differ
.stream_diff(store.as_ref(), &base, &other)
.unwrap()
.filter_map(|r| r.ok())
.collect();
assert_eq!(diffs.len(), 3);
let keys: Vec<_> = diffs
.iter()
.map(|d| match d {
Diff::Added { key, .. } => key.clone(),
Diff::Removed { key, .. } => key.clone(),
Diff::Changed { key, .. } => key.clone(),
})
.collect();
assert_eq!(keys, vec![b"a".to_vec(), b"b".to_vec(), b"c".to_vec()]);
}
#[test]
fn test_streaming_diff_both_empty() {
let store = Arc::new(MemStore::new());
let prolly = Prolly::new(store.clone(), Config::default());
let base = prolly.create();
let other = prolly.create();
let differ = DefaultStreamingDiffer::new();
let diffs: Vec<_> = differ
.stream_diff(store.as_ref(), &base, &other)
.unwrap()
.collect();
assert!(diffs.is_empty());
}
}