Add deterministic ordering
This commit is contained in:
parent
d7ae0a781d
commit
667b324a88
3 changed files with 47 additions and 13 deletions
|
|
@ -25,7 +25,7 @@ use crate::{
|
|||
#[derive(Debug, Clone, PartialEq, Default)]
|
||||
pub struct EditedText<'a, T>
|
||||
where
|
||||
T: PartialEq + Clone,
|
||||
T: PartialEq + Clone + std::fmt::Debug,
|
||||
{
|
||||
text: &'a str,
|
||||
operations: Vec<OrderedOperation<T>>,
|
||||
|
|
@ -46,7 +46,7 @@ impl<'a> EditedText<'a, String> {
|
|||
|
||||
impl<'a, T> EditedText<'a, T>
|
||||
where
|
||||
T: PartialEq + Clone,
|
||||
T: PartialEq + Clone + std::fmt::Debug,
|
||||
{
|
||||
/// Create an `EditedText` from the given original (old) and updated (new)
|
||||
/// strings. The returned `EditedText` represents the changes from the
|
||||
|
|
@ -207,9 +207,12 @@ where
|
|||
|(operation, _)| {
|
||||
(
|
||||
operation.order,
|
||||
// Operations on left and right must come in the same order so that
|
||||
// Operations on the left and right must come in the same order so that
|
||||
// inserts can be merged with other inserts and deletes with deletes.
|
||||
usize::from(matches!(operation.operation, Operation::Delete { .. })),
|
||||
// Make sure that the ordering is deterministic regardless which text
|
||||
// is left or right.
|
||||
operation.operation.get_hash(),
|
||||
)
|
||||
},
|
||||
)
|
||||
|
|
@ -282,7 +285,7 @@ mod tests {
|
|||
let original = "hello world! ...";
|
||||
let left = "Hello world! I'm Andras.";
|
||||
let right = "Hello world! How are you?";
|
||||
let expected = "Hello world! I'm Andras.How are you?";
|
||||
let expected = "Hello world! How are you?I'm Andras.";
|
||||
|
||||
let operations_1 = EditedText::from_strings(original, left);
|
||||
let operations_2 = EditedText::from_strings(original, right);
|
||||
|
|
|
|||
|
|
@ -2,18 +2,18 @@ use core::{
|
|||
fmt::{Debug, Display},
|
||||
ops::Range,
|
||||
};
|
||||
use std::cmp::min;
|
||||
use std::hash::{DefaultHasher, Hash, Hasher};
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::merge_context::MergeContext;
|
||||
use crate::{
|
||||
Token,
|
||||
utils::{
|
||||
find_longest_prefix_contained_within::find_longest_prefix_contained_within,
|
||||
string_builder::StringBuilder,
|
||||
},
|
||||
Token,
|
||||
};
|
||||
|
||||
/// Represents a change that can be applied to a text document.
|
||||
|
|
@ -39,6 +39,28 @@ where
|
|||
},
|
||||
}
|
||||
|
||||
impl<T> Hash for Operation<T>
|
||||
where
|
||||
T: PartialEq + Clone + std::fmt::Debug,
|
||||
{
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
match self {
|
||||
Operation::Insert { index, text } => {
|
||||
index.hash(state);
|
||||
text.iter().for_each(|token| token.original().hash(state));
|
||||
}
|
||||
Operation::Delete {
|
||||
index,
|
||||
deleted_character_count,
|
||||
..
|
||||
} => {
|
||||
index.hash(state);
|
||||
deleted_character_count.hash(state);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Operation<T>
|
||||
where
|
||||
T: PartialEq + Clone + std::fmt::Debug,
|
||||
|
|
@ -300,6 +322,13 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the hash of the operation based on the indexes and original text.
|
||||
pub fn get_hash(&self) -> u64 {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
self.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Display for Operation<T>
|
||||
|
|
@ -362,9 +391,11 @@ mod tests {
|
|||
#[test]
|
||||
#[should_panic]
|
||||
fn test_shifting_error() {
|
||||
insta::assert_debug_snapshot!(Operation::create_insert(1, vec!["hi".into()])
|
||||
insta::assert_debug_snapshot!(
|
||||
Operation::create_insert(1, vec!["hi".into()])
|
||||
.unwrap()
|
||||
.with_shifted_index(-2));
|
||||
.with_shifted_index(-2)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue