From 3c84e8df519643db521b3342a52b9ff3f4a3df40 Mon Sep 17 00:00:00 2001 From: nathan Date: Sat, 10 Sep 2022 23:31:58 +0800 Subject: [PATCH] chore: update node documentation --- shared-lib/lib-ot/src/core/document/node.rs | 26 +++++++++- .../lib-ot/src/core/document/node_tree.rs | 49 +++++++++++-------- .../lib-ot/src/core/document/operation.rs | 32 ++++++------ .../lib-ot/src/core/document/transaction.rs | 2 +- 4 files changed, 71 insertions(+), 38 deletions(-) diff --git a/shared-lib/lib-ot/src/core/document/node.rs b/shared-lib/lib-ot/src/core/document/node.rs index eff18e2164..c8f9ebf0c9 100644 --- a/shared-lib/lib-ot/src/core/document/node.rs +++ b/shared-lib/lib-ot/src/core/document/node.rs @@ -27,6 +27,7 @@ impl Node { } } +/// Builder for [`Node`] pub struct NodeBuilder { node: Node, } @@ -38,25 +39,40 @@ impl NodeBuilder { } } + /// Appends a new node to the end of the builder's node children. pub fn add_node(mut self, node: Node) -> Self { self.node.children.push(node); self } + /// Inserts attributes to the builder's node. + /// + /// The attributes will be replace if they shared the same key pub fn insert_attribute(mut self, key: AttributeKey, value: AttributeValue) -> Self { self.node.attributes.insert(key, value); self } - pub fn set_body(mut self, body: NodeBody) -> Self { + /// Inserts a body to the builder's node + pub fn insert_body(mut self, body: NodeBody) -> Self { self.node.body = body; self } + + /// Returns the builder's node pub fn build(self) -> Node { self.node } } +/// NodeBody represents as the node's data. +/// +/// For the moment, the NodeBody can be Empty or Delta. We can extend +/// the NodeBody by adding a new enum type. +/// +/// The NodeBody implements the [`OperationTransform`] trait which means it can perform +/// compose, transform and invert. +/// #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum NodeBody { Empty, @@ -79,6 +95,7 @@ impl NodeBody { } impl OperationTransform for NodeBody { + /// Only the same enum variant can perform the compose operation. fn compose(&self, other: &Self) -> Result where Self: Sized, @@ -93,6 +110,7 @@ impl OperationTransform for NodeBody { } } + /// Only the same enum variant can perform the transform operation. fn transform(&self, other: &Self) -> Result<(Self, Self), OTError> where Self: Sized, @@ -107,6 +125,7 @@ impl OperationTransform for NodeBody { } } + /// Only the same enum variant can perform the invert operation. fn invert(&self, other: &Self) -> Self { match (self, other) { (Delta(l), Delta(r)) => Delta(l.invert(r)), @@ -119,6 +138,9 @@ impl OperationTransform for NodeBody { } } +/// Represents the changeset of the [`NodeBody`] +/// +/// Each NodeBody except the Empty should have its corresponding changeset variant. #[derive(Debug, Clone, Serialize, Deserialize)] pub enum NodeBodyChangeset { Delta { delta: TextDelta, inverted: TextDelta }, @@ -135,6 +157,8 @@ impl NodeBodyChangeset { } } +/// [`NodeData`] represents as a leaf data in the [`NodeTree`]. +/// #[derive(Clone, Eq, PartialEq, Debug)] pub struct NodeData { pub node_type: String, diff --git a/shared-lib/lib-ot/src/core/document/node_tree.rs b/shared-lib/lib-ot/src/core/document/node_tree.rs index 04765de358..dd3c3c31ad 100644 --- a/shared-lib/lib-ot/src/core/document/node_tree.rs +++ b/shared-lib/lib-ot/src/core/document/node_tree.rs @@ -3,6 +3,7 @@ use crate::core::{Node, NodeAttributes, NodeBodyChangeset, NodeData, NodeOperati use crate::errors::{ErrorBuilder, OTError, OTErrorCode}; use indextree::{Arena, Children, FollowingSiblings, NodeId}; +/// pub struct NodeTree { arena: Arena, root: NodeId, @@ -145,12 +146,15 @@ impl NodeTree { pub fn apply_op(&mut self, op: &NodeOperation) -> Result<(), OTError> { match op { NodeOperation::Insert { path, nodes } => self.insert_nodes(path, nodes), - NodeOperation::Update { path, attributes, .. } => self.update_node(path, attributes), + NodeOperation::UpdateAttributes { path, attributes, .. } => self.update_attributes(path, attributes), + NodeOperation::UpdateBody { path, changeset } => self.update_body(path, changeset), NodeOperation::Delete { path, nodes } => self.delete_node(path, nodes), - NodeOperation::EditBody { path, changeset: body } => self.update_body(path, body), } } - + /// Inserts nodes at given path + /// + /// returns error if the path is empty + /// fn insert_nodes(&mut self, path: &Path, nodes: &[Node]) -> Result<(), OTError> { debug_assert!(!path.is_empty()); if path.is_empty() { @@ -166,6 +170,21 @@ impl NodeTree { self.insert_nodes_at_index(parent_node, last_index, nodes) } + /// Inserts nodes before the node with node_id + /// + fn insert_nodes_before(&mut self, node_id: &NodeId, nodes: &[Node]) { + for node in nodes { + let new_node_id = self.arena.new_node(node.into()); + if node_id.is_removed(&self.arena) { + tracing::warn!("Node:{:?} is remove before insert", node_id); + return; + } + + node_id.insert_before(new_node_id, &mut self.arena); + self.append_nodes(&new_node_id, &node.children); + } + } + fn insert_nodes_at_index(&mut self, parent: NodeId, index: usize, insert_children: &[Node]) -> Result<(), OTError> { if index == 0 && parent.children(&self.arena).next().is_none() { self.append_nodes(&parent, insert_children); @@ -181,30 +200,20 @@ impl NodeTree { .child_from_node_at_index(parent, index) .ok_or_else(|| ErrorBuilder::new(OTErrorCode::PathNotFound).build())?; - self.insert_subtree_before(&node_to_insert, insert_children); + self.insert_nodes_before(&node_to_insert, insert_children); Ok(()) } - // recursive append the subtrees to the node - fn append_nodes(&mut self, parent: &NodeId, insert_children: &[Node]) { - for child in insert_children { - let child_id = self.arena.new_node(child.into()); - parent.append(child_id, &mut self.arena); + fn append_nodes(&mut self, parent: &NodeId, nodes: &[Node]) { + for node in nodes { + let new_node_id = self.arena.new_node(node.into()); + parent.append(new_node_id, &mut self.arena); - self.append_nodes(&child_id, &child.children); + self.append_nodes(&new_node_id, &node.children); } } - fn insert_subtree_before(&mut self, before: &NodeId, insert_children: &[Node]) { - for child in insert_children { - let child_id = self.arena.new_node(child.into()); - before.insert_before(child_id, &mut self.arena); - - self.append_nodes(&child_id, &child.children); - } - } - - fn update_node(&mut self, path: &Path, attributes: &NodeAttributes) -> Result<(), OTError> { + fn update_attributes(&mut self, path: &Path, attributes: &NodeAttributes) -> Result<(), OTError> { self.mut_node_at_path(path, |node_data| { let new_attributes = NodeAttributes::compose(&node_data.attributes, attributes)?; node_data.attributes = new_attributes; diff --git a/shared-lib/lib-ot/src/core/document/operation.rs b/shared-lib/lib-ot/src/core/document/operation.rs index a805f06d20..fd6536b401 100644 --- a/shared-lib/lib-ot/src/core/document/operation.rs +++ b/shared-lib/lib-ot/src/core/document/operation.rs @@ -9,29 +9,29 @@ pub enum NodeOperation { Insert { path: Path, nodes: Vec }, #[serde(rename = "update")] - Update { + UpdateAttributes { path: Path, attributes: NodeAttributes, #[serde(rename = "oldAttributes")] old_attributes: NodeAttributes, }, - #[serde(rename = "delete")] - Delete { path: Path, nodes: Vec }, - #[serde(rename = "edit-body")] #[serde(serialize_with = "serialize_edit_body")] // #[serde(deserialize_with = "operation_serde::deserialize_edit_body")] - EditBody { path: Path, changeset: NodeBodyChangeset }, + UpdateBody { path: Path, changeset: NodeBodyChangeset }, + + #[serde(rename = "delete")] + Delete { path: Path, nodes: Vec }, } impl NodeOperation { pub fn path(&self) -> &Path { match self { NodeOperation::Insert { path, .. } => path, - NodeOperation::Update { path, .. } => path, + NodeOperation::UpdateAttributes { path, .. } => path, NodeOperation::Delete { path, .. } => path, - NodeOperation::EditBody { path, .. } => path, + NodeOperation::UpdateBody { path, .. } => path, } } pub fn invert(&self) -> NodeOperation { @@ -40,11 +40,11 @@ impl NodeOperation { path: path.clone(), nodes: nodes.clone(), }, - NodeOperation::Update { + NodeOperation::UpdateAttributes { path, attributes, old_attributes, - } => NodeOperation::Update { + } => NodeOperation::UpdateAttributes { path: path.clone(), attributes: old_attributes.clone(), old_attributes: attributes.clone(), @@ -53,7 +53,7 @@ impl NodeOperation { path: path.clone(), nodes: nodes.clone(), }, - NodeOperation::EditBody { path, changeset: body } => NodeOperation::EditBody { + NodeOperation::UpdateBody { path, changeset: body } => NodeOperation::UpdateBody { path: path.clone(), changeset: body.inverted(), }, @@ -65,11 +65,11 @@ impl NodeOperation { path, nodes: nodes.clone(), }, - NodeOperation::Update { + NodeOperation::UpdateAttributes { attributes, old_attributes, .. - } => NodeOperation::Update { + } => NodeOperation::UpdateAttributes { path, attributes: attributes.clone(), old_attributes: old_attributes.clone(), @@ -78,9 +78,9 @@ impl NodeOperation { path, nodes: nodes.clone(), }, - NodeOperation::EditBody { path, changeset: body } => NodeOperation::EditBody { + NodeOperation::UpdateBody { path, changeset } => NodeOperation::UpdateBody { path: path.clone(), - changeset: body.clone(), + changeset: changeset.clone(), }, } } @@ -127,7 +127,7 @@ mod tests { #[test] fn test_serialize_update_operation() { - let insert = NodeOperation::Update { + let insert = NodeOperation::UpdateAttributes { path: Path(vec![0, 1]), attributes: NodeAttributes::new(), old_attributes: NodeAttributes::new(), @@ -145,7 +145,7 @@ mod tests { delta: TextDelta::new(), inverted: TextDelta::new(), }; - let insert = NodeOperation::EditBody { + let insert = NodeOperation::UpdateBody { path: Path(vec![0, 1]), changeset, }; diff --git a/shared-lib/lib-ot/src/core/document/transaction.rs b/shared-lib/lib-ot/src/core/document/transaction.rs index 40a12bc40c..b7f71cc267 100644 --- a/shared-lib/lib-ot/src/core/document/transaction.rs +++ b/shared-lib/lib-ot/src/core/document/transaction.rs @@ -92,7 +92,7 @@ impl<'a> TransactionBuilder<'a> { } } - self.push(NodeOperation::Update { + self.push(NodeOperation::UpdateAttributes { path: path.clone(), attributes, old_attributes,