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

View File

@ -1,21 +1,21 @@
use crate::core::document::position::Position; use crate::core::document::position::Position;
use crate::core::{NodeAttributes, NodeData, TextDelta}; use crate::core::{NodeAttributes, NodeSubTree, TextDelta};
#[derive(Clone, serde::Serialize, serde::Deserialize)] #[derive(Clone, serde::Serialize, serde::Deserialize)]
#[serde(tag = "type")]
pub enum DocumentOperation { pub enum DocumentOperation {
Insert { #[serde(rename = "insert-operation")]
path: Position, Insert { path: Position, nodes: Vec<NodeSubTree> },
nodes: Vec<NodeData>, #[serde(rename = "update-operation")]
},
Update { Update {
path: Position, path: Position,
attributes: NodeAttributes, attributes: NodeAttributes,
#[serde(rename = "oldAttributes")]
old_attributes: NodeAttributes, old_attributes: NodeAttributes,
}, },
Delete { #[serde(rename = "delete-operation")]
path: Position, Delete { path: Position, nodes: Vec<NodeSubTree> },
nodes: Vec<NodeData>, #[serde(rename = "text-edit-operation")]
},
TextEdit { TextEdit {
path: Position, path: Position,
delta: TextDelta, delta: TextDelta,
@ -101,7 +101,7 @@ impl DocumentOperation {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::core::Position; use crate::core::{Delta, DocumentOperation, NodeAttributes, NodeSubTree, Position};
#[test] #[test]
fn test_transform_path_1() { fn test_transform_path_1() {
@ -150,4 +150,45 @@ mod tests {
vec![0, 6] 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}; use crate::core::{NodeAttributes, TextDelta};
#[derive(Clone, serde::Serialize, serde::Deserialize)] #[derive(Clone)]
pub struct NodeData { pub struct NodeData {
pub node_type: String, pub node_type: String,
pub attributes: NodeAttributes, 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::document::position::Position;
use crate::core::{DocumentOperation, DocumentTree, NodeAttributes, NodeData}; use crate::core::{DocumentOperation, DocumentTree, NodeAttributes, NodeSubTree};
use std::collections::HashMap; use std::collections::HashMap;
pub struct Transaction { 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 { self.push(DocumentOperation::Insert {
path: path.clone(), path: path.clone(),
nodes: nodes.to_vec(), nodes: nodes.to_vec(),
@ -59,11 +59,17 @@ impl<'a> TransactionBuilder<'a> {
pub fn delete_nodes_at_path(&mut self, path: &Position, length: usize) { pub fn delete_nodes_at_path(&mut self, path: &Position, length: usize) {
let mut node = self.document.node_at_path(path).unwrap(); 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 { for _ in 0..length {
let data = self.document.arena.get(node).unwrap(); let node_data = self.document.arena.get(node).unwrap();
deleted_nodes.push(data.get().clone()); 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(); node = node.following_siblings(&self.document.arena).next().unwrap();
} }