Skip to content

Commit 4b654de

Browse files
committed
chore: updata path documentation
1 parent 2d738fe commit 4b654de

File tree

7 files changed

+243
-74
lines changed

7 files changed

+243
-74
lines changed

shared-lib/lib-ot/src/core/document/node_tree.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,8 +216,8 @@ impl NodeTree {
216216
return Ok(());
217217
}
218218

219-
/// Append the node to the end of the children list if index greater or equal to the
220-
/// length of the children.
219+
// Append the node to the end of the children list if index greater or equal to the
220+
// length of the children.
221221
if index >= parent.children(&self.arena).count() {
222222
self.append_nodes(&parent, nodes);
223223
return Ok(());

shared-lib/lib-ot/src/core/document/operation.rs

Lines changed: 18 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,12 @@ impl NodeOperation {
6666
}
6767
}
6868

69-
pub fn mut_path<F>(&mut self, f: F)
70-
where
71-
F: FnOnce(&mut Path),
72-
{
69+
pub fn get_mut_path(&mut self) -> &mut Path {
7370
match self {
74-
NodeOperation::Insert { path, .. } => f(path),
75-
NodeOperation::UpdateAttributes { path, .. } => f(path),
76-
NodeOperation::Delete { path, .. } => f(path),
77-
NodeOperation::UpdateBody { path, .. } => f(path),
71+
NodeOperation::Insert { path, .. } => path,
72+
NodeOperation::UpdateAttributes { path, .. } => path,
73+
NodeOperation::Delete { path, .. } => path,
74+
NodeOperation::UpdateBody { path, .. } => path,
7875
}
7976
}
8077

@@ -104,15 +101,15 @@ impl NodeOperation {
104101
}
105102
}
106103

107-
/// Transform the `other` operation into a new operation that carries the changes made by
108-
/// the current operation.
104+
/// Make the `other` operation to be applied to the version that has been modified.
105+
/// The semantics of transform is used when editing conflicts occur, which is often determined by the version id。
106+
/// For example, if the inserted position has been acquired by others, then you need to do transform to make sure
107+
/// your position is value.
109108
///
110109
/// # Arguments
111110
///
112111
/// * `other`: The operation that is going to be transformed
113112
///
114-
/// returns: NodeOperation
115-
///
116113
/// # Examples
117114
///
118115
/// ```
@@ -130,39 +127,21 @@ impl NodeOperation {
130127
/// nodes: vec![node_2],
131128
/// };
132129
///
133-
/// assert_eq!(serde_json::to_string(&op_2).unwrap(), r#"{"op":"insert","path":[0,1],
134-
/// "nodes":[{"type":"text_2"}]}"#);
130+
/// assert_eq!(serde_json::to_string(&op_2).unwrap(), r#"{"op":"insert","path":[0,1],"nodes":[{"type":"text_2"}]}"#);
135131
///
136-
/// let new_op = op_1.transform(&op_2);
137-
/// assert_eq!(serde_json::to_string(&new_op).unwrap(), r#"{"op":"insert","path":[0,2],
138-
/// "nodes":[{"type":"text_2"}]}"#);
132+
/// op_1.transform(&mut op_2);
133+
/// assert_eq!(serde_json::to_string(&op_2).unwrap(), r#"{"op":"insert","path":[0,2],"nodes":[{"type":"text_2"}]}"#);
139134
///
140135
/// ```
141-
pub fn transform(&self, other: &NodeOperation) -> NodeOperation {
142-
let mut other = other.clone();
143-
match self {
144-
NodeOperation::Insert { path, nodes } => {
145-
let new_path = Path::transform(path, other.get_path(), nodes.len() as i64);
146-
other.mut_path(|path| *path = new_path);
147-
}
148-
NodeOperation::Delete { path: a_path, nodes } => {
149-
let new_path = Path::transform(a_path, other.get_path(), nodes.len() as i64);
150-
other.mut_path(|path| *path = new_path);
151-
}
152-
_ => {}
153-
}
154-
other
155-
}
156-
157-
pub fn mut_transform(&self, other: &mut NodeOperation) {
136+
pub fn transform(&self, other: &mut NodeOperation) {
158137
match self {
159138
NodeOperation::Insert { path, nodes } => {
160-
let new_path = Path::transform(path, other.get_path(), nodes.len() as i64);
161-
other.mut_path(|path| *path = new_path);
139+
let new_path = path.transform(other.get_path(), nodes.len());
140+
*other.get_mut_path() = new_path;
162141
}
163-
NodeOperation::Delete { path: a_path, nodes } => {
164-
let new_path = Path::transform(a_path, other.get_path(), nodes.len() as i64);
165-
other.mut_path(|path| *path = new_path);
142+
NodeOperation::Delete { path, nodes } => {
143+
let new_path = path.transform(other.get_path(), nodes.len());
144+
*other.get_mut_path() = new_path;
166145
}
167146
_ => {}
168147
}

shared-lib/lib-ot/src/core/document/path.rs

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use serde::{Deserialize, Serialize};
22

3+
/// The `Path` represents as a path to reference to the node in the `NodeTree`.
34
#[derive(Clone, Serialize, Deserialize, Eq, PartialEq, Debug)]
45
pub struct Path(pub Vec<usize>);
56

@@ -48,8 +49,56 @@ impl From<&[usize]> for Path {
4849
}
4950

5051
impl Path {
52+
///
53+
///
54+
/// The path will be changed is
55+
/// # Arguments
56+
///
57+
/// * `other`:
58+
/// * `offset`: represents the len of nodes referenced by this path
59+
///
60+
/// returns: Path
61+
///
62+
/// # Examples
63+
///
64+
/// ```
65+
///
66+
/// ```
67+
pub fn transform(&self, other: &Path, offset: usize) -> Path {
68+
if self.len() > other.len() {
69+
return other.clone();
70+
}
71+
if self.is_empty() || other.is_empty() {
72+
return other.clone();
73+
}
74+
for i in 0..(self.len() - 1) {
75+
if self.0[i] != other.0[i] {
76+
return other.clone();
77+
}
78+
}
79+
80+
// Splits the `Path` into two part. The suffix will contain the last element of the `Path`.
81+
let second_last_index = self.0.len() - 1;
82+
let mut prefix: Vec<usize> = self.0[0..second_last_index].into();
83+
let mut suffix: Vec<usize> = other.0[self.0.len()..].into();
84+
let last_value = self.0.last().unwrap().clone();
85+
86+
let other_second_last_value = other.0[second_last_index];
87+
88+
//
89+
if last_value <= other_second_last_value {
90+
prefix.push(other_second_last_value + offset);
91+
} else {
92+
prefix.push(other_second_last_value);
93+
}
94+
95+
// concat the prefix and suffix into a new path
96+
prefix.append(&mut suffix);
97+
Path(prefix)
98+
}
99+
51100
// delta is default to be 1
52-
pub fn transform(pre_insert_path: &Path, b: &Path, offset: i64) -> Path {
101+
pub fn transform3(pre_insert_path: &Path, b: &Path, offset: i64) -> Path {
53102
if pre_insert_path.len() > b.len() {
54103
return b.clone();
55104
}
@@ -83,44 +132,44 @@ mod tests {
83132
#[test]
84133
fn path_transform_test_1() {
85134
assert_eq!(
86-
{ Path::transform(&Path(vec![0, 1]), &Path(vec![0, 1]), 1) }.0,
135+
{ Path::transform3(&Path(vec![0, 1]), &Path(vec![0, 1]), 1) }.0,
87136
vec![0, 2]
88137
);
89138

90139
assert_eq!(
91-
{ Path::transform(&Path(vec![0, 1]), &Path(vec![0, 1]), 5) }.0,
140+
{ Path::transform3(&Path(vec![0, 1]), &Path(vec![0, 1]), 5) }.0,
92141
vec![0, 6]
93142
);
94143
}
95144

96145
#[test]
97146
fn path_transform_test_2() {
98147
assert_eq!(
99-
{ Path::transform(&Path(vec![0, 1]), &Path(vec![0, 2]), 1) }.0,
148+
{ Path::transform3(&Path(vec![0, 1]), &Path(vec![0, 2]), 1) }.0,
100149
vec![0, 3]
101150
);
102151
}
103152

104153
#[test]
105154
fn path_transform_test_3() {
106155
assert_eq!(
107-
{ Path::transform(&Path(vec![0, 1]), &Path(vec![0, 2, 7, 8, 9]), 1) }.0,
156+
{ Path::transform3(&Path(vec![0, 1]), &Path(vec![0, 2, 7, 8, 9]), 1) }.0,
108157
vec![0, 3, 7, 8, 9]
109158
);
110159
}
111160

112161
#[test]
113162
fn path_transform_no_changed_test() {
114163
assert_eq!(
115-
{ Path::transform(&Path(vec![0, 1, 2]), &Path(vec![0, 0, 7, 8, 9]), 1) }.0,
164+
{ Path::transform3(&Path(vec![0, 1, 2]), &Path(vec![0, 0, 7, 8, 9]), 1) }.0,
116165
vec![0, 0, 7, 8, 9]
117166
);
118167
assert_eq!(
119-
{ Path::transform(&Path(vec![0, 1, 2]), &Path(vec![0, 1]), 1) }.0,
168+
{ Path::transform3(&Path(vec![0, 1, 2]), &Path(vec![0, 1]), 1) }.0,
120169
vec![0, 1]
121170
);
122171
assert_eq!(
123-
{ Path::transform(&Path(vec![1, 1]), &Path(vec![1, 0]), 1) }.0,
172+
{ Path::transform3(&Path(vec![1, 1]), &Path(vec![1, 0]), 1) }.0,
124173
vec![1, 0]
125174
);
126175
}

shared-lib/lib-ot/src/core/document/transaction.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,14 @@ impl Transaction {
2727
self.operations.into_inner()
2828
}
2929

30+
/// Make the `other` to be applied to the version that has been modified.
31+
///
32+
/// The semantics of transform is used when editing conflicts occur, which is often determined by the version id。
33+
/// the operations of the transaction will be transformed into the conflict operations.
3034
pub fn transform(&self, other: &mut Transaction) {
3135
for other_operation in other.iter_mut() {
3236
for operation in self.operations.iter() {
33-
operation.mut_transform(other_operation);
37+
operation.transform(other_operation);
3438
}
3539
}
3640
}

shared-lib/lib-ot/tests/node/operation_test.rs

Lines changed: 59 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -81,37 +81,41 @@ fn operation_insert_op_transform_test() {
8181
nodes: vec![node_1],
8282
};
8383

84-
let insert_2 = NodeOperation::Insert {
84+
let mut insert_2 = NodeOperation::Insert {
8585
path: Path(vec![0, 1]),
8686
nodes: vec![node_2],
8787
};
8888

8989
// let mut node_tree = NodeTree::new("root");
9090
// node_tree.apply_op(insert_1.clone()).unwrap();
9191

92-
let new_op = op_1.transform(&insert_2);
93-
let json = serde_json::to_string(&new_op).unwrap();
92+
op_1.transform(&mut insert_2);
93+
let json = serde_json::to_string(&insert_2).unwrap();
9494
assert_eq!(json, r#"{"op":"insert","path":[0,2],"nodes":[{"type":"text_2"}]}"#);
9595
}
9696

9797
#[test]
98-
fn operation_insert_transform_test() {
98+
fn operation_insert_transform_one_level_path_test() {
9999
let mut test = NodeTest::new();
100100
let node_data_1 = NodeDataBuilder::new("text_1").build();
101101
let node_data_2 = NodeDataBuilder::new("text_2").build();
102102
let node_data_3 = NodeDataBuilder::new("text_3").build();
103103
let node_3: Node = node_data_3.clone().into();
104+
// 0: text_1
105+
// 1: text_2
104106
//
105-
// rev_id:1 0: text_1
106-
// rev_id:2 1: text_2
107+
// Insert a new operation with rev_id 1,but the rev_id:1 is already exist, so
108+
// it needs to be transformed.
109+
// 1:text_3 => 2:text_3
107110
//
108-
// Insert a new operation with rev_id 1.But the rev_id:1 is already exist, so
109-
// it needs to do the transform.
110-
//
111-
// --> 1:text_3
112-
// transform into:
113-
// --> 2:text_3
111+
// 0: text_1
112+
// 1: text_2
113+
// 2: text_3
114114
//
115+
// If the rev_id of the insert operation is 3. then the tree will be:
116+
// 0: text_1
117+
// 1: text_3
118+
// 2: text_2
115119
let scripts = vec![
116120
InsertNode {
117121
path: 0.into(),
@@ -137,7 +141,45 @@ fn operation_insert_transform_test() {
137141
}
138142

139143
#[test]
140-
fn operation_delete_transform_test() {
144+
fn operation_insert_transform_multiple_level_path_test() {
145+
let mut test = NodeTest::new();
146+
let node_data_1 = NodeDataBuilder::new("text_1")
147+
.add_node(NodeDataBuilder::new("text_1_1").build())
148+
.add_node(NodeDataBuilder::new("text_1_2").build())
149+
.build();
150+
151+
let node_data_2 = NodeDataBuilder::new("text_2")
152+
.add_node(NodeDataBuilder::new("text_2_1").build())
153+
.add_node(NodeDataBuilder::new("text_2_2").build())
154+
.build();
155+
156+
let node_data_3 = NodeDataBuilder::new("text_3").build();
157+
let scripts = vec![
158+
InsertNode {
159+
path: 0.into(),
160+
node_data: node_data_1.clone(),
161+
rev_id: 1,
162+
},
163+
InsertNode {
164+
path: 1.into(),
165+
node_data: node_data_2.clone(),
166+
rev_id: 2,
167+
},
168+
InsertNode {
169+
path: 1.into(),
170+
node_data: node_data_3.clone(),
171+
rev_id: 1,
172+
},
173+
AssertNode {
174+
path: 2.into(),
175+
expected: Some(node_data_3.into()),
176+
},
177+
];
178+
test.run_scripts(scripts);
179+
}
180+
181+
#[test]
182+
fn operation_delete_transform_path_test() {
141183
let mut test = NodeTest::new();
142184
let node_data_1 = NodeDataBuilder::new("text_1").build();
143185
let node_data_2 = NodeDataBuilder::new("text_2").build();
@@ -167,7 +209,6 @@ fn operation_delete_transform_test() {
167209
node_data: node_data_3.clone(),
168210
rev_id: 3,
169211
},
170-
//
171212
// 0: text_1
172213
// 1: text_3
173214
// 2: text_2
@@ -178,6 +219,10 @@ fn operation_delete_transform_test() {
178219
path: 1.into(),
179220
rev_id: 3,
180221
},
222+
// After perform the delete action, the tree will be:
223+
// 0: text_1
224+
// 1: text_3
225+
AssertNumberOfNodesAtPath { path: None, len: 2 },
181226
AssertNode {
182227
path: 1.into(),
183228
expected: Some(node_3),
@@ -186,7 +231,6 @@ fn operation_delete_transform_test() {
186231
path: 2.into(),
187232
expected: None,
188233
},
189-
AssertNumberOfNodesAtPath { path: None, len: 2 },
190234
];
191235
test.run_scripts(scripts);
192236
}

shared-lib/lib-ot/tests/node/script.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ impl NodeTest {
149149

150150
fn transform_transaction_if_need(&mut self, transaction: &mut Transaction, rev_id: usize) {
151151
if self.rev_id >= rev_id {
152-
for rev_id in rev_id..self.rev_id {
152+
for rev_id in rev_id..=self.rev_id {
153153
let old_transaction = self.rev_operations.get(&rev_id).unwrap();
154154
old_transaction.transform(transaction);
155155
}

0 commit comments

Comments
 (0)