|
@@ -1,11 +1,145 @@
|
|
-use crate::core::{NodeAttributes, TextDelta};
|
|
|
|
|
|
+use crate::core::NodeBody::Delta;
|
|
|
|
+use crate::core::{AttributeKey, AttributeValue, NodeAttributes, OperationTransform, TextDelta};
|
|
|
|
+use crate::errors::OTError;
|
|
use serde::{Deserialize, Serialize};
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
|
|
|
+#[derive(Default, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
|
|
|
+pub struct Node {
|
|
|
|
+ #[serde(rename = "type")]
|
|
|
|
+ pub node_type: String,
|
|
|
|
+
|
|
|
|
+ #[serde(skip_serializing_if = "NodeAttributes::is_empty")]
|
|
|
|
+ pub attributes: NodeAttributes,
|
|
|
|
+
|
|
|
|
+ #[serde(skip_serializing_if = "NodeBody::is_empty")]
|
|
|
|
+ pub body: NodeBody,
|
|
|
|
+
|
|
|
|
+ #[serde(skip_serializing_if = "Vec::is_empty")]
|
|
|
|
+ pub children: Vec<Node>,
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl Node {
|
|
|
|
+ pub fn new<T: ToString>(node_type: T) -> Node {
|
|
|
|
+ Node {
|
|
|
|
+ node_type: node_type.to_string(),
|
|
|
|
+ ..Default::default()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+pub struct NodeBuilder {
|
|
|
|
+ node: Node,
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl NodeBuilder {
|
|
|
|
+ pub fn new<T: ToString>(node_type: T) -> Self {
|
|
|
|
+ Self {
|
|
|
|
+ node: Node::new(node_type.to_string()),
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn add_node(mut self, node: Node) -> Self {
|
|
|
|
+ self.node.children.push(node);
|
|
|
|
+ self
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ 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 {
|
|
|
|
+ self.node.body = body;
|
|
|
|
+ self
|
|
|
|
+ }
|
|
|
|
+ pub fn build(self) -> Node {
|
|
|
|
+ self.node
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
|
|
+pub enum NodeBody {
|
|
|
|
+ Empty,
|
|
|
|
+ Delta(TextDelta),
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl std::default::Default for NodeBody {
|
|
|
|
+ fn default() -> Self {
|
|
|
|
+ NodeBody::Empty
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl NodeBody {
|
|
|
|
+ fn is_empty(&self) -> bool {
|
|
|
|
+ match self {
|
|
|
|
+ NodeBody::Empty => true,
|
|
|
|
+ _ => false,
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl OperationTransform for NodeBody {
|
|
|
|
+ fn compose(&self, other: &Self) -> Result<Self, OTError>
|
|
|
|
+ where
|
|
|
|
+ Self: Sized,
|
|
|
|
+ {
|
|
|
|
+ match (self, other) {
|
|
|
|
+ (Delta(a), Delta(b)) => a.compose(b).map(|delta| Delta(delta)),
|
|
|
|
+ (NodeBody::Empty, NodeBody::Empty) => Ok(NodeBody::Empty),
|
|
|
|
+ (l, r) => {
|
|
|
|
+ let msg = format!("{:?} can not compose {:?}", l, r);
|
|
|
|
+ Err(OTError::internal().context(msg))
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn transform(&self, other: &Self) -> Result<(Self, Self), OTError>
|
|
|
|
+ where
|
|
|
|
+ Self: Sized,
|
|
|
|
+ {
|
|
|
|
+ match (self, other) {
|
|
|
|
+ (Delta(l), Delta(r)) => l.transform(r).map(|(ta, tb)| (Delta(ta), Delta(tb))),
|
|
|
|
+ (NodeBody::Empty, NodeBody::Empty) => Ok((NodeBody::Empty, NodeBody::Empty)),
|
|
|
|
+ (l, r) => {
|
|
|
|
+ let msg = format!("{:?} can not compose {:?}", l, r);
|
|
|
|
+ Err(OTError::internal().context(msg))
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fn invert(&self, other: &Self) -> Self {
|
|
|
|
+ match (self, other) {
|
|
|
|
+ (Delta(l), Delta(r)) => Delta(l.invert(r)),
|
|
|
|
+ (NodeBody::Empty, NodeBody::Empty) => NodeBody::Empty,
|
|
|
|
+ (l, r) => {
|
|
|
|
+ tracing::error!("{:?} can not compose {:?}", l, r);
|
|
|
|
+ l.clone()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
+pub enum NodeBodyChangeset {
|
|
|
|
+ Delta { delta: TextDelta, inverted: TextDelta },
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl NodeBodyChangeset {
|
|
|
|
+ pub fn inverted(&self) -> NodeBodyChangeset {
|
|
|
|
+ match self {
|
|
|
|
+ NodeBodyChangeset::Delta { delta, inverted } => NodeBodyChangeset::Delta {
|
|
|
|
+ delta: inverted.clone(),
|
|
|
|
+ inverted: delta.clone(),
|
|
|
|
+ },
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
#[derive(Clone, Eq, PartialEq, Debug)]
|
|
#[derive(Clone, Eq, PartialEq, Debug)]
|
|
pub struct NodeData {
|
|
pub struct NodeData {
|
|
pub node_type: String,
|
|
pub node_type: String,
|
|
|
|
+ pub body: NodeBody,
|
|
pub attributes: NodeAttributes,
|
|
pub attributes: NodeAttributes,
|
|
- pub delta: Option<TextDelta>,
|
|
|
|
}
|
|
}
|
|
|
|
|
|
impl NodeData {
|
|
impl NodeData {
|
|
@@ -13,7 +147,16 @@ impl NodeData {
|
|
NodeData {
|
|
NodeData {
|
|
node_type: node_type.into(),
|
|
node_type: node_type.into(),
|
|
attributes: NodeAttributes::new(),
|
|
attributes: NodeAttributes::new(),
|
|
- delta: None,
|
|
|
|
|
|
+ body: NodeBody::Empty,
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pub fn apply_body_changeset(&mut self, changeset: &NodeBodyChangeset) {
|
|
|
|
+ match changeset {
|
|
|
|
+ NodeBodyChangeset::Delta { delta, inverted: _ } => match self.body.compose(&Delta(delta.clone())) {
|
|
|
|
+ Ok(new_body) => self.body = new_body,
|
|
|
|
+ Err(e) => tracing::error!("{:?}", e),
|
|
|
|
+ },
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -21,9 +164,9 @@ impl NodeData {
|
|
impl std::convert::From<Node> for NodeData {
|
|
impl std::convert::From<Node> for NodeData {
|
|
fn from(node: Node) -> Self {
|
|
fn from(node: Node) -> Self {
|
|
Self {
|
|
Self {
|
|
- node_type: node.note_type,
|
|
|
|
|
|
+ node_type: node.node_type,
|
|
attributes: node.attributes,
|
|
attributes: node.attributes,
|
|
- delta: node.delta,
|
|
|
|
|
|
+ body: node.body,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -31,34 +174,9 @@ impl std::convert::From<Node> for NodeData {
|
|
impl std::convert::From<&Node> for NodeData {
|
|
impl std::convert::From<&Node> for NodeData {
|
|
fn from(node: &Node) -> Self {
|
|
fn from(node: &Node) -> Self {
|
|
Self {
|
|
Self {
|
|
- node_type: node.note_type.clone(),
|
|
|
|
|
|
+ node_type: node.node_type.clone(),
|
|
attributes: node.attributes.clone(),
|
|
attributes: node.attributes.clone(),
|
|
- delta: node.delta.clone(),
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-#[derive(Clone, Serialize, Deserialize, Eq, PartialEq)]
|
|
|
|
-pub struct Node {
|
|
|
|
- #[serde(rename = "type")]
|
|
|
|
- pub note_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<Node>,
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-impl Node {
|
|
|
|
- pub fn new(node_type: &str) -> Node {
|
|
|
|
- Node {
|
|
|
|
- note_type: node_type.into(),
|
|
|
|
- attributes: NodeAttributes::new(),
|
|
|
|
- delta: None,
|
|
|
|
- children: Vec::new(),
|
|
|
|
|
|
+ body: node.body.clone(),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|