chore: update node documentation

This commit is contained in:
nathan 2022-09-10 23:31:58 +08:00
parent 9142f5d870
commit 3c84e8df51
4 changed files with 71 additions and 38 deletions

View File

@ -27,6 +27,7 @@ impl Node {
} }
} }
/// Builder for [`Node`]
pub struct NodeBuilder { pub struct NodeBuilder {
node: Node, 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 { pub fn add_node(mut self, node: Node) -> Self {
self.node.children.push(node); self.node.children.push(node);
self 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 { pub fn insert_attribute(mut self, key: AttributeKey, value: AttributeValue) -> Self {
self.node.attributes.insert(key, value); self.node.attributes.insert(key, value);
self 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.node.body = body;
self self
} }
/// Returns the builder's node
pub fn build(self) -> Node { pub fn build(self) -> Node {
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)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum NodeBody { pub enum NodeBody {
Empty, Empty,
@ -79,6 +95,7 @@ impl NodeBody {
} }
impl OperationTransform for NodeBody { impl OperationTransform for NodeBody {
/// Only the same enum variant can perform the compose operation.
fn compose(&self, other: &Self) -> Result<Self, OTError> fn compose(&self, other: &Self) -> Result<Self, OTError>
where where
Self: Sized, 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> fn transform(&self, other: &Self) -> Result<(Self, Self), OTError>
where where
Self: Sized, 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 { fn invert(&self, other: &Self) -> Self {
match (self, other) { match (self, other) {
(Delta(l), Delta(r)) => Delta(l.invert(r)), (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)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub enum NodeBodyChangeset { pub enum NodeBodyChangeset {
Delta { delta: TextDelta, inverted: TextDelta }, 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)] #[derive(Clone, Eq, PartialEq, Debug)]
pub struct NodeData { pub struct NodeData {
pub node_type: String, pub node_type: String,

View File

@ -3,6 +3,7 @@ use crate::core::{Node, NodeAttributes, NodeBodyChangeset, NodeData, NodeOperati
use crate::errors::{ErrorBuilder, OTError, OTErrorCode}; use crate::errors::{ErrorBuilder, OTError, OTErrorCode};
use indextree::{Arena, Children, FollowingSiblings, NodeId}; use indextree::{Arena, Children, FollowingSiblings, NodeId};
///
pub struct NodeTree { pub struct NodeTree {
arena: Arena<NodeData>, arena: Arena<NodeData>,
root: NodeId, root: NodeId,
@ -145,12 +146,15 @@ impl NodeTree {
pub fn apply_op(&mut self, op: &NodeOperation) -> Result<(), OTError> { pub fn apply_op(&mut self, op: &NodeOperation) -> Result<(), OTError> {
match op { match op {
NodeOperation::Insert { path, nodes } => self.insert_nodes(path, nodes), 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::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> { fn insert_nodes(&mut self, path: &Path, nodes: &[Node]) -> Result<(), OTError> {
debug_assert!(!path.is_empty()); debug_assert!(!path.is_empty());
if path.is_empty() { if path.is_empty() {
@ -166,6 +170,21 @@ impl NodeTree {
self.insert_nodes_at_index(parent_node, last_index, nodes) 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> { 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() { if index == 0 && parent.children(&self.arena).next().is_none() {
self.append_nodes(&parent, insert_children); self.append_nodes(&parent, insert_children);
@ -181,30 +200,20 @@ impl NodeTree {
.child_from_node_at_index(parent, index) .child_from_node_at_index(parent, index)
.ok_or_else(|| ErrorBuilder::new(OTErrorCode::PathNotFound).build())?; .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(()) Ok(())
} }
// recursive append the subtrees to the node fn append_nodes(&mut self, parent: &NodeId, nodes: &[Node]) {
fn append_nodes(&mut self, parent: &NodeId, insert_children: &[Node]) { for node in nodes {
for child in insert_children { let new_node_id = self.arena.new_node(node.into());
let child_id = self.arena.new_node(child.into()); parent.append(new_node_id, &mut self.arena);
parent.append(child_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]) { fn update_attributes(&mut self, path: &Path, attributes: &NodeAttributes) -> Result<(), OTError> {
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> {
self.mut_node_at_path(path, |node_data| { self.mut_node_at_path(path, |node_data| {
let new_attributes = NodeAttributes::compose(&node_data.attributes, attributes)?; let new_attributes = NodeAttributes::compose(&node_data.attributes, attributes)?;
node_data.attributes = new_attributes; node_data.attributes = new_attributes;

View File

@ -9,29 +9,29 @@ pub enum NodeOperation {
Insert { path: Path, nodes: Vec<Node> }, Insert { path: Path, nodes: Vec<Node> },
#[serde(rename = "update")] #[serde(rename = "update")]
Update { UpdateAttributes {
path: Path, path: Path,
attributes: NodeAttributes, attributes: NodeAttributes,
#[serde(rename = "oldAttributes")] #[serde(rename = "oldAttributes")]
old_attributes: NodeAttributes, old_attributes: NodeAttributes,
}, },
#[serde(rename = "delete")]
Delete { path: Path, nodes: Vec<Node> },
#[serde(rename = "edit-body")] #[serde(rename = "edit-body")]
#[serde(serialize_with = "serialize_edit_body")] #[serde(serialize_with = "serialize_edit_body")]
// #[serde(deserialize_with = "operation_serde::deserialize_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<Node> },
} }
impl NodeOperation { impl NodeOperation {
pub fn path(&self) -> &Path { pub fn path(&self) -> &Path {
match self { match self {
NodeOperation::Insert { path, .. } => path, NodeOperation::Insert { path, .. } => path,
NodeOperation::Update { path, .. } => path, NodeOperation::UpdateAttributes { path, .. } => path,
NodeOperation::Delete { path, .. } => path, NodeOperation::Delete { path, .. } => path,
NodeOperation::EditBody { path, .. } => path, NodeOperation::UpdateBody { path, .. } => path,
} }
} }
pub fn invert(&self) -> NodeOperation { pub fn invert(&self) -> NodeOperation {
@ -40,11 +40,11 @@ impl NodeOperation {
path: path.clone(), path: path.clone(),
nodes: nodes.clone(), nodes: nodes.clone(),
}, },
NodeOperation::Update { NodeOperation::UpdateAttributes {
path, path,
attributes, attributes,
old_attributes, old_attributes,
} => NodeOperation::Update { } => NodeOperation::UpdateAttributes {
path: path.clone(), path: path.clone(),
attributes: old_attributes.clone(), attributes: old_attributes.clone(),
old_attributes: attributes.clone(), old_attributes: attributes.clone(),
@ -53,7 +53,7 @@ impl NodeOperation {
path: path.clone(), path: path.clone(),
nodes: nodes.clone(), nodes: nodes.clone(),
}, },
NodeOperation::EditBody { path, changeset: body } => NodeOperation::EditBody { NodeOperation::UpdateBody { path, changeset: body } => NodeOperation::UpdateBody {
path: path.clone(), path: path.clone(),
changeset: body.inverted(), changeset: body.inverted(),
}, },
@ -65,11 +65,11 @@ impl NodeOperation {
path, path,
nodes: nodes.clone(), nodes: nodes.clone(),
}, },
NodeOperation::Update { NodeOperation::UpdateAttributes {
attributes, attributes,
old_attributes, old_attributes,
.. ..
} => NodeOperation::Update { } => NodeOperation::UpdateAttributes {
path, path,
attributes: attributes.clone(), attributes: attributes.clone(),
old_attributes: old_attributes.clone(), old_attributes: old_attributes.clone(),
@ -78,9 +78,9 @@ impl NodeOperation {
path, path,
nodes: nodes.clone(), nodes: nodes.clone(),
}, },
NodeOperation::EditBody { path, changeset: body } => NodeOperation::EditBody { NodeOperation::UpdateBody { path, changeset } => NodeOperation::UpdateBody {
path: path.clone(), path: path.clone(),
changeset: body.clone(), changeset: changeset.clone(),
}, },
} }
} }
@ -127,7 +127,7 @@ mod tests {
#[test] #[test]
fn test_serialize_update_operation() { fn test_serialize_update_operation() {
let insert = NodeOperation::Update { let insert = NodeOperation::UpdateAttributes {
path: Path(vec![0, 1]), path: Path(vec![0, 1]),
attributes: NodeAttributes::new(), attributes: NodeAttributes::new(),
old_attributes: NodeAttributes::new(), old_attributes: NodeAttributes::new(),
@ -145,7 +145,7 @@ mod tests {
delta: TextDelta::new(), delta: TextDelta::new(),
inverted: TextDelta::new(), inverted: TextDelta::new(),
}; };
let insert = NodeOperation::EditBody { let insert = NodeOperation::UpdateBody {
path: Path(vec![0, 1]), path: Path(vec![0, 1]),
changeset, changeset,
}; };

View File

@ -92,7 +92,7 @@ impl<'a> TransactionBuilder<'a> {
} }
} }
self.push(NodeOperation::Update { self.push(NodeOperation::UpdateAttributes {
path: path.clone(), path: path.clone(),
attributes, attributes,
old_attributes, old_attributes,