merge: add a Merge::into_resolved() to avoid cloning

I don't know if this has any measurable impact. It just seems like we
should be able to take a resolved value out of a `Merge` without
clonning.
This commit is contained in:
Martin von Zweigbergk 2023-08-06 12:38:08 -07:00 committed by Martin von Zweigbergk
parent f7160cf936
commit 0570963fe3
3 changed files with 29 additions and 12 deletions

View file

@ -165,6 +165,16 @@ impl<T> Merge<T> {
}
}
/// Returns the resolved value, if this merge is resolved. Otherwise returns
/// the merge itself as an `Err`. Does not resolve trivial merges.
pub fn into_resolved(mut self) -> Result<T, Merge<T>> {
if self.removes.is_empty() {
Ok(self.adds.pop().unwrap())
} else {
Err(self)
}
}
/// Simplify the merge by joining diffs like A->B and B->C into A->C.
/// Also drops trivial diffs like A->A.
pub fn simplify(mut self) -> Self

View file

@ -227,10 +227,13 @@ fn merge_trees(merge: &Merge<Tree>) -> Result<Merge<Tree>, TreeMergeError> {
for basename in all_tree_conflict_names(merge) {
let path_merge = merge.map(|tree| tree.value(basename).cloned());
let path_merge = merge_tree_values(store, dir, path_merge)?;
if let Some(value) = path_merge.as_resolved() {
new_tree.set_or_remove(basename, value.clone());
} else {
conflicts.push((basename, path_merge));
match path_merge.into_resolved() {
Ok(value) => {
new_tree.set_or_remove(basename, value);
}
Err(path_merge) => {
conflicts.push((basename, path_merge));
}
};
}
if conflicts.is_empty() {

View file

@ -570,14 +570,18 @@ fn merge_tree_value(
);
let filename = dir.join(basename);
let merge = simplify_conflict(store, &filename, conflict)?;
if let Some(value) = merge.as_resolved() {
return Ok(value.clone());
}
if let Some(tree_value) = try_resolve_file_conflict(store, &filename, &merge)? {
Some(tree_value)
} else {
let conflict_id = store.write_conflict(&filename, &merge)?;
Some(TreeValue::Conflict(conflict_id))
match merge.into_resolved() {
Ok(value) => value,
Err(conflict) => {
if let Some(tree_value) =
try_resolve_file_conflict(store, &filename, &conflict)?
{
Some(tree_value)
} else {
let conflict_id = store.write_conflict(&filename, &conflict)?;
Some(TreeValue::Conflict(conflict_id))
}
}
}
}
})