feat: serialize

This commit is contained in:
Vincent Chan 2022-08-23 11:15:11 +08:00
parent ef65551340
commit bb8e0485cd
4 changed files with 120 additions and 34 deletions

View File

@ -1,5 +1,7 @@
use crate::core::document::position::Position;
use crate::core::{DocumentOperation, NodeAttributes, NodeData, OperationTransform, TextDelta, Transaction};
use crate::core::{
DocumentOperation, NodeAttributes, NodeData, NodeSubTree, OperationTransform, TextDelta, Transaction,
};
use crate::errors::{ErrorBuilder, OTError, OTErrorCode};
use indextree::{Arena, NodeId};
@ -100,40 +102,36 @@ impl DocumentTree {
}
}
fn apply_insert(&mut self, path: &Position, nodes: &Vec<NodeData>) -> Result<(), OTError> {
fn apply_insert(&mut self, path: &Position, nodes: &Vec<NodeSubTree>) -> Result<(), OTError> {
let parent_path = &path.0[0..(path.0.len() - 1)];
let last_index = path.0[path.0.len() - 1];
let parent_node = self
.node_at_path(&Position(parent_path.to_vec()))
.ok_or(ErrorBuilder::new(OTErrorCode::PathNotFound).build())?;
let mut inserted_nodes = Vec::new();
// let mut inserted_nodes = Vec::new();
//
// for node in nodes {
// inserted_nodes.push(self.arena.new_node(node.to_node_data()));
// }
for node in nodes {
inserted_nodes.push(self.arena.new_node(node.clone()));
}
self.insert_child_at_index(parent_node, last_index, &inserted_nodes)
self.insert_child_at_index(parent_node, last_index, nodes.as_ref())
}
fn insert_child_at_index(
&mut self,
parent: NodeId,
index: usize,
insert_children: &[NodeId],
insert_children: &[NodeSubTree],
) -> Result<(), OTError> {
if index == 0 && parent.children(&self.arena).next().is_none() {
for id in insert_children {
parent.append(*id, &mut self.arena);
}
self.append_subtree(&parent, insert_children);
return Ok(());
}
let children_length = parent.children(&self.arena).fold(0, |counter, _| counter + 1);
if index == children_length {
for id in insert_children {
parent.append(*id, &mut self.arena);
}
self.append_subtree(&parent, insert_children);
return Ok(());
}
@ -141,12 +139,24 @@ impl DocumentTree {
.child_at_index_of_path(parent, index)
.ok_or(ErrorBuilder::new(OTErrorCode::PathNotFound).build())?;
for id in insert_children {
node_to_insert.insert_before(*id, &mut self.arena);
}
self.insert_subtree_before(&node_to_insert, insert_children);
Ok(())
}
fn append_subtree(&mut self, parent: &NodeId, insert_children: &[NodeSubTree]) {
for child in insert_children {
let child_id = self.arena.new_node(child.to_node_data());
parent.append(child_id, &mut self.arena);
}
}
fn insert_subtree_before(&mut self, before: &NodeId, insert_children: &[NodeSubTree]) {
for id in insert_children {
let child_id = self.arena.new_node(id.to_node_data());
before.insert_before(child_id, &mut self.arena);
}
}
fn apply_update(&mut self, path: &Position, attributes: &NodeAttributes) -> Result<(), OTError> {
let update_node = self
.node_at_path(path)

View File

@ -1,21 +1,21 @@
use crate::core::document::position::Position;
use crate::core::{NodeAttributes, NodeData, TextDelta};
use crate::core::{NodeAttributes, NodeSubTree, TextDelta};
#[derive(Clone, serde::Serialize, serde::Deserialize)]
#[serde(tag = "type")]
pub enum DocumentOperation {
Insert {
path: Position,
nodes: Vec<NodeData>,
},
#[serde(rename = "insert-operation")]
Insert { path: Position, nodes: Vec<NodeSubTree> },
#[serde(rename = "update-operation")]
Update {
path: Position,
attributes: NodeAttributes,
#[serde(rename = "oldAttributes")]
old_attributes: NodeAttributes,
},
Delete {
path: Position,
nodes: Vec<NodeData>,
},
#[serde(rename = "delete-operation")]
Delete { path: Position, nodes: Vec<NodeSubTree> },
#[serde(rename = "text-edit-operation")]
TextEdit {
path: Position,
delta: TextDelta,
@ -101,7 +101,7 @@ impl DocumentOperation {
#[cfg(test)]
mod tests {
use crate::core::Position;
use crate::core::{Delta, DocumentOperation, NodeAttributes, NodeSubTree, Position};
#[test]
fn test_transform_path_1() {
@ -150,4 +150,45 @@ mod tests {
vec![0, 6]
);
}
#[test]
fn test_serialize_insert_operation() {
let insert = DocumentOperation::Insert {
path: Position(vec![0, 1]),
nodes: vec![NodeSubTree::new("text")],
};
let result = serde_json::to_string(&insert).unwrap();
assert_eq!(
result,
r#"{"type":"insert-operation","path":[0,1],"nodes":[{"node_type":"text","attributes":{}}]}"#
);
}
#[test]
fn test_serialize_update_operation() {
let insert = DocumentOperation::Update {
path: Position(vec![0, 1]),
attributes: NodeAttributes::new(),
old_attributes: NodeAttributes::new(),
};
let result = serde_json::to_string(&insert).unwrap();
assert_eq!(
result,
r#"{"type":"update-operation","path":[0,1],"attributes":{},"oldAttributes":{}}"#
);
}
#[test]
fn test_serialize_text_edit_operation() {
let insert = DocumentOperation::TextEdit {
path: Position(vec![0, 1]),
delta: Delta::new(),
inverted: Delta::new(),
};
let result = serde_json::to_string(&insert).unwrap();
assert_eq!(
result,
r#"{"type":"text-edit-operation","path":[0,1],"delta":[],"inverted":[]}"#
);
}
}

View File

@ -1,6 +1,6 @@
use crate::core::{NodeAttributes, TextDelta};
#[derive(Clone, serde::Serialize, serde::Deserialize)]
#[derive(Clone)]
pub struct NodeData {
pub node_type: String,
pub attributes: NodeAttributes,
@ -16,3 +16,32 @@ impl NodeData {
}
}
}
#[derive(Clone, serde::Serialize, serde::Deserialize)]
pub struct NodeSubTree {
pub node_type: String,
pub attributes: NodeAttributes,
#[serde(skip_serializing_if = "Option::is_none")]
pub delta: Option<TextDelta>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub children: Vec<Box<NodeSubTree>>,
}
impl NodeSubTree {
pub fn new(node_type: &str) -> NodeSubTree {
NodeSubTree {
node_type: node_type.into(),
attributes: NodeAttributes::new(),
delta: None,
children: Vec::new(),
}
}
pub fn to_node_data(&self) -> NodeData {
NodeData {
node_type: self.node_type.clone(),
attributes: self.attributes.clone(),
delta: self.delta.clone(),
}
}
}

View File

@ -1,5 +1,5 @@
use crate::core::document::position::Position;
use crate::core::{DocumentOperation, DocumentTree, NodeAttributes, NodeData};
use crate::core::{DocumentOperation, DocumentTree, NodeAttributes, NodeSubTree};
use std::collections::HashMap;
pub struct Transaction {
@ -25,7 +25,7 @@ impl<'a> TransactionBuilder<'a> {
}
}
pub fn insert_nodes_at_path(&mut self, path: &Position, nodes: &[NodeData]) {
pub fn insert_nodes_at_path(&mut self, path: &Position, nodes: &[NodeSubTree]) {
self.push(DocumentOperation::Insert {
path: path.clone(),
nodes: nodes.to_vec(),
@ -59,11 +59,17 @@ impl<'a> TransactionBuilder<'a> {
pub fn delete_nodes_at_path(&mut self, path: &Position, length: usize) {
let mut node = self.document.node_at_path(path).unwrap();
let mut deleted_nodes: Vec<NodeData> = Vec::new();
let mut deleted_nodes: Vec<NodeSubTree> = Vec::new();
for _ in 0..length {
let data = self.document.arena.get(node).unwrap();
deleted_nodes.push(data.get().clone());
let node_data = self.document.arena.get(node).unwrap();
let data = node_data.get();
deleted_nodes.push(NodeSubTree {
node_type: data.node_type.clone(),
attributes: data.attributes.clone(),
delta: data.delta.clone(),
children: vec![],
});
node = node.following_siblings(&self.document.arena).next().unwrap();
}