Procházet zdrojové kódy

operation & delta serde

appflowy před 3 roky
rodič
revize
592244f6b9

+ 2 - 0
rust-lib/flowy-ot/Cargo.toml

@@ -7,6 +7,8 @@ edition = "2018"
 
 [dependencies]
 bytecount = "0.6.0"
+serde = { version = "1.0", features = ["derive"] }
+serde_json = {version = "1.0"}
 
 [dev-dependencies]
 criterion = "0.3"

+ 3 - 1
rust-lib/flowy-ot/src/attributes.rs

@@ -1,7 +1,9 @@
 use std::collections::{hash_map::RandomState, HashMap};
 
-#[derive(Debug, Clone, Default, PartialEq)]
+#[derive(Debug, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)]
 pub struct Attributes {
+    #[serde(skip_serializing_if = "HashMap::is_empty")]
+    #[serde(flatten)]
     inner: HashMap<String, String>,
 }
 

+ 8 - 8
rust-lib/flowy-ot/src/delta.rs

@@ -53,11 +53,11 @@ impl Delta {
         }
     }
 
-    fn add(&mut self, op: Operation) {
+    pub fn add(&mut self, op: Operation) {
         match op {
             Operation::Delete(i) => self.delete(i),
-            Operation::Insert(i) => self.insert(&i.s, i.attrs),
-            Operation::Retain(r) => self.retain(r.n, r.attrs),
+            Operation::Insert(i) => self.insert(&i.s, i.attributes),
+            Operation::Retain(r) => self.retain(r.n, r.attributes),
         }
     }
 
@@ -96,7 +96,7 @@ impl Delta {
             _ => Operation::Insert(s.into()),
         };
         self.ops
-            .push(OpBuilder::new(new_last).with_attrs(attrs).build());
+            .push(OpBuilder::new(new_last).attributes(attrs).build());
     }
 
     pub fn retain(&mut self, n: u64, attrs: Option<Attributes>) {
@@ -108,10 +108,10 @@ impl Delta {
 
         if let Some(Operation::Retain(i_last)) = self.ops.last_mut() {
             i_last.n += n;
-            i_last.attrs = attrs;
+            i_last.attributes = attrs;
         } else {
             self.ops
-                .push(OpBuilder::retain(n).with_attrs(attrs).build());
+                .push(OpBuilder::retain(n).attributes(attrs).build());
         }
     }
 
@@ -415,7 +415,7 @@ impl Delta {
                 Operation::Delete(delete) => {
                     inverted.insert(
                         &chars.take(*delete as usize).collect::<String>(),
-                        op.attrs(),
+                        op.attributes(),
                     );
                 },
             }
@@ -452,6 +452,6 @@ impl Delta {
 pub fn get_attrs(operation: &Option<Operation>) -> Option<Attributes> {
     match operation {
         None => None,
-        Some(operation) => operation.attrs(),
+        Some(operation) => operation.attributes(),
     }
 }

+ 1 - 0
rust-lib/flowy-ot/src/lib.rs

@@ -2,3 +2,4 @@ pub mod attributes;
 pub mod delta;
 pub mod errors;
 pub mod operation;
+mod operation_serde;

+ 49 - 14
rust-lib/flowy-ot/src/operation.rs

@@ -29,15 +29,35 @@ impl Operation {
         }
     }
 
-    pub fn attrs(&self) -> Option<Attributes> {
+    pub fn attributes(&self) -> Option<Attributes> {
         match self {
             Operation::Delete(_) => None,
-            Operation::Retain(retain) => retain.attrs.clone(),
-            Operation::Insert(insert) => insert.attrs.clone(),
+            Operation::Retain(retain) => retain.attributes.clone(),
+            Operation::Insert(insert) => insert.attributes.clone(),
         }
     }
 
-    pub fn is_plain(&self) -> bool { self.attrs().is_none() }
+    pub fn set_attributes(&mut self, attributes: Option<Attributes>) {
+        match self {
+            Operation::Delete(_) => {},
+            Operation::Retain(retain) => {
+                retain.attributes = attributes;
+            },
+            Operation::Insert(insert) => {
+                insert.attributes = attributes;
+            },
+        }
+    }
+
+    pub fn is_plain(&self) -> bool { self.attributes().is_none() }
+
+    pub fn length(&self) -> u64 {
+        match self {
+            Operation::Delete(n) => *n,
+            Operation::Retain(r) => r.n,
+            Operation::Insert(i) => i.num_chars(),
+        }
+    }
 }
 
 pub struct OpBuilder {
@@ -54,7 +74,7 @@ impl OpBuilder {
 
     pub fn insert(s: String) -> OpBuilder { OpBuilder::new(Operation::Insert(s.into())) }
 
-    pub fn with_attrs(mut self, attrs: Option<Attributes>) -> OpBuilder {
+    pub fn attributes(mut self, attrs: Option<Attributes>) -> OpBuilder {
         self.attrs = attrs;
         self
     }
@@ -63,21 +83,28 @@ impl OpBuilder {
         let mut operation = self.ty;
         match &mut operation {
             Operation::Delete(_) => {},
-            Operation::Retain(retain) => retain.attrs = self.attrs,
-            Operation::Insert(insert) => insert.attrs = self.attrs,
+            Operation::Retain(retain) => retain.attributes = self.attrs,
+            Operation::Insert(insert) => insert.attributes = self.attrs,
         }
         operation
     }
 }
 
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
 pub struct Retain {
+    #[serde(rename(serialize = "retain", deserialize = "retain"))]
     pub n: u64,
-    pub(crate) attrs: Option<Attributes>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub(crate) attributes: Option<Attributes>,
 }
 
 impl std::convert::From<u64> for Retain {
-    fn from(n: u64) -> Self { Retain { n, attrs: None } }
+    fn from(n: u64) -> Self {
+        Retain {
+            n,
+            attributes: None,
+        }
+    }
 }
 
 impl Deref for Retain {
@@ -90,10 +117,13 @@ impl DerefMut for Retain {
     fn deref_mut(&mut self) -> &mut Self::Target { &mut self.n }
 }
 
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
 pub struct Insert {
+    #[serde(rename(serialize = "insert", deserialize = "insert"))]
     pub s: String,
-    pub attrs: Option<Attributes>,
+
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub attributes: Option<Attributes>,
 }
 
 impl Insert {
@@ -105,14 +135,19 @@ impl Insert {
 }
 
 impl std::convert::From<String> for Insert {
-    fn from(s: String) -> Self { Insert { s, attrs: None } }
+    fn from(s: String) -> Self {
+        Insert {
+            s,
+            attributes: None,
+        }
+    }
 }
 
 impl std::convert::From<&str> for Insert {
     fn from(s: &str) -> Self {
         Insert {
             s: s.to_owned(),
-            attrs: None,
+            attributes: None,
         }
     }
 }

+ 137 - 0
rust-lib/flowy-ot/src/operation_serde.rs

@@ -0,0 +1,137 @@
+use crate::{attributes::Attributes, delta::Delta, operation::Operation};
+use serde::{
+    de,
+    de::{MapAccess, SeqAccess, Visitor},
+    ser::{SerializeMap, SerializeSeq},
+    Deserialize,
+    Deserializer,
+    Serialize,
+    Serializer,
+};
+use std::{collections::HashMap, fmt};
+
+impl Serialize for Operation {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: Serializer,
+    {
+        match self {
+            Operation::Retain(retain) => retain.serialize(serializer),
+            Operation::Delete(i) => {
+                let mut map = serializer.serialize_map(Some(1))?;
+                map.serialize_entry("delete", i)?;
+                map.end()
+            },
+            Operation::Insert(insert) => insert.serialize(serializer),
+        }
+    }
+}
+
+impl<'de> Deserialize<'de> for Operation {
+    fn deserialize<D>(deserializer: D) -> Result<Operation, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        struct OperationVisitor;
+
+        impl<'de> Visitor<'de> for OperationVisitor {
+            type Value = Operation;
+
+            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+                formatter.write_str("an integer between -2^64 and 2^63 or a string")
+            }
+
+            fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
+            where
+                V: MapAccess<'de>,
+            {
+                let mut operation = None;
+                let mut attributes = None;
+                while let Some(key) = map.next_key()? {
+                    match key {
+                        "delete" => {
+                            if operation.is_some() {
+                                return Err(de::Error::duplicate_field("operation"));
+                            }
+                            operation = Some(Operation::Delete(map.next_value()?));
+                        },
+                        "retain" => {
+                            if operation.is_some() {
+                                return Err(de::Error::duplicate_field("operation"));
+                            }
+                            let i: u64 = map.next_value()?;
+                            operation = Some(Operation::Retain(i.into()));
+                        },
+                        "insert" => {
+                            if operation.is_some() {
+                                return Err(de::Error::duplicate_field("operation"));
+                            }
+                            let i: String = map.next_value()?;
+                            operation = Some(Operation::Insert(i.into()));
+                        },
+                        "attributes" => {
+                            if attributes.is_some() {
+                                return Err(de::Error::duplicate_field("attributes"));
+                            }
+                            let map: Attributes = map.next_value()?;
+                            attributes = Some(map);
+                        },
+                        _ => panic!(),
+                    }
+                }
+                match operation {
+                    None => Err(de::Error::missing_field("operation")),
+                    Some(mut operation) => {
+                        operation.set_attributes(attributes);
+                        Ok(operation)
+                    },
+                }
+            }
+        }
+
+        deserializer.deserialize_any(OperationVisitor)
+    }
+}
+
+impl Serialize for Delta {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: Serializer,
+    {
+        let mut seq = serializer.serialize_seq(Some(self.ops.len()))?;
+        for op in self.ops.iter() {
+            seq.serialize_element(op)?;
+        }
+        seq.end()
+    }
+}
+
+impl<'de> Deserialize<'de> for Delta {
+    fn deserialize<D>(deserializer: D) -> Result<Delta, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        struct OperationSeqVisitor;
+
+        impl<'de> Visitor<'de> for OperationSeqVisitor {
+            type Value = Delta;
+
+            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+                formatter.write_str("a sequence")
+            }
+
+            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
+            where
+                A: SeqAccess<'de>,
+            {
+                let mut o = Delta::default();
+                while let Some(op) = seq.next_element()? {
+                    o.add(op);
+                }
+                Ok(o)
+            }
+        }
+
+        deserializer.deserialize_seq(OperationSeqVisitor)
+    }
+}

+ 2 - 0
rust-lib/flowy-ot/tests/mod.rs

@@ -0,0 +1,2 @@
+mod helper;
+mod serde_test;

+ 0 - 2
rust-lib/flowy-ot/tests/op_test.rs

@@ -1,5 +1,3 @@
-mod helper;
-
 use crate::helper::Rng;
 use bytecount::num_chars;
 use flowy_ot::{

+ 55 - 0
rust-lib/flowy-ot/tests/serde_test.rs

@@ -0,0 +1,55 @@
+use flowy_ot::{
+    attributes::{Attributes, AttributesBuilder},
+    delta::Delta,
+    operation::{OpBuilder, Operation, Retain},
+};
+
+#[test]
+fn operation_insert_serialize_test() {
+    let attributes = AttributesBuilder::new().bold().italic().build();
+    let operation = OpBuilder::insert("123".to_owned())
+        .attributes(Some(attributes))
+        .build();
+    let json = serde_json::to_string(&operation).unwrap();
+    eprintln!("{}", json);
+
+    let insert_op: Operation = serde_json::from_str(&json).unwrap();
+    assert_eq!(insert_op, operation);
+}
+
+#[test]
+fn operation_retain_serialize_test() {
+    let operation = Operation::Retain(12.into());
+    let json = serde_json::to_string(&operation).unwrap();
+    eprintln!("{}", json);
+    let insert_op: Operation = serde_json::from_str(&json).unwrap();
+    assert_eq!(insert_op, operation);
+}
+
+#[test]
+fn operation_delete_serialize_test() {
+    let operation = Operation::Delete(2);
+    let json = serde_json::to_string(&operation).unwrap();
+    let insert_op: Operation = serde_json::from_str(&json).unwrap();
+    assert_eq!(insert_op, operation);
+}
+
+#[test]
+fn delta_serialize_test() {
+    let mut delta = Delta::default();
+
+    let attributes = AttributesBuilder::new().bold().italic().build();
+    let retain = OpBuilder::insert("123".to_owned())
+        .attributes(Some(attributes))
+        .build();
+
+    delta.add(retain);
+    delta.add(Operation::Retain(5.into()));
+    delta.add(Operation::Delete(3));
+
+    let json = serde_json::to_string(&delta).unwrap();
+    eprintln!("{}", json);
+
+    let delta_from_json: Delta = serde_json::from_str(&json).unwrap();
+    assert_eq!(delta_from_json, delta);
+}