浏览代码

add flowy-ot document

appflowy 3 年之前
父节点
当前提交
e2b8738b65

+ 177 - 0
rust-lib/flowy-ot/src/client/document.rs

@@ -0,0 +1,177 @@
+use crate::{
+    client::{History, UndoResult},
+    core::{
+        Attribute,
+        Attributes,
+        AttributesDataRule,
+        AttrsBuilder,
+        Delta,
+        Interval,
+        OpBuilder,
+        Operation,
+    },
+};
+
+pub struct Document {
+    data: Delta,
+    history: History,
+}
+
+impl Document {
+    pub fn new() -> Self {
+        Document {
+            data: Delta::new(),
+            history: History::new(),
+        }
+    }
+
+    pub fn edit(&mut self, index: usize, text: &str) {
+        if self.data.target_len < index {
+            log::error!(
+                "{} out of bounds. should 0..{}",
+                index,
+                self.data.target_len
+            );
+        }
+        let probe = Interval::new(index, index + 1);
+        let mut attributes = self.data.get_attributes(probe);
+        if attributes == Attributes::Empty {
+            attributes = Attributes::Follow;
+        }
+        let insert = OpBuilder::insert(text).attributes(attributes).build();
+        let interval = Interval::new(index, index);
+
+        self.update_with_op(insert, interval);
+    }
+
+    pub fn format(&mut self, interval: Interval, attribute: Attribute, enable: bool) {
+        let attributes = match enable {
+            true => AttrsBuilder::new().add_attribute(attribute).build(),
+            false => AttrsBuilder::new().remove_attribute(attribute).build(),
+        };
+
+        self.update_with_attribute(attributes, interval);
+    }
+
+    pub fn undo(&mut self) -> UndoResult { unimplemented!() }
+
+    pub fn redo(&mut self) -> UndoResult { unimplemented!() }
+
+    pub fn delete(&mut self, interval: Interval) {
+        let delete = OpBuilder::delete(interval.size() as u64).build();
+        self.update_with_op(delete, interval);
+    }
+
+    pub fn to_json(&self) -> String { self.data.to_json() }
+
+    pub fn data(&self) -> &Delta { &self.data }
+
+    pub fn set_data(&mut self, data: Delta) { self.data = data; }
+
+    fn update_with_op(&mut self, op: Operation, interval: Interval) {
+        let mut new_delta = Delta::default();
+        let (prefix, interval, suffix) = split_length_with_interval(self.data.target_len, interval);
+
+        // prefix
+        if prefix.is_empty() == false && prefix != interval {
+            let intervals = split_interval_with_delta(&self.data, &prefix);
+            intervals.into_iter().for_each(|i| {
+                let attributes = self.data.get_attributes(i);
+                log::debug!("prefix attribute: {:?}, interval: {:?}", attributes, i);
+                new_delta.retain(i.size() as u64, attributes);
+            });
+        }
+
+        log::debug!("add new op: {:?}", op);
+        new_delta.add(op);
+
+        // suffix
+        if suffix.is_empty() == false {
+            let intervals = split_interval_with_delta(&self.data, &suffix);
+            intervals.into_iter().for_each(|i| {
+                let attributes = self.data.get_attributes(i);
+                log::debug!("suffix attribute: {:?}, interval: {:?}", attributes, i);
+                new_delta.retain(i.size() as u64, attributes);
+            });
+        }
+
+        let new_data = self.data.compose(&new_delta).unwrap();
+        self.data = new_data;
+    }
+
+    pub fn update_with_attribute(&mut self, mut attributes: Attributes, interval: Interval) {
+        let old_attributes = self.data.get_attributes(interval);
+        log::debug!(
+            "merge attributes: {:?}, with old: {:?}",
+            attributes,
+            old_attributes
+        );
+        let new_attributes = match &mut attributes {
+            Attributes::Follow => old_attributes,
+            Attributes::Custom(attr_data) => {
+                attr_data.merge(old_attributes.data());
+                attr_data.clone().into_attributes()
+            },
+            Attributes::Empty => Attributes::Empty,
+        };
+
+        log::debug!("new attributes: {:?}", new_attributes);
+        let retain = OpBuilder::retain(interval.size() as u64)
+            .attributes(new_attributes)
+            .build();
+
+        log::debug!(
+            "Update delta with new attributes: {:?} at: {:?}",
+            retain,
+            interval
+        );
+
+        self.update_with_op(retain, interval);
+    }
+}
+
+pub fn transform(left: &Document, right: &Document) -> (Document, Document) {
+    let (a_prime, b_prime) = left.data.transform(&right.data).unwrap();
+    log::trace!("a:{:?},b:{:?}", a_prime, b_prime);
+
+    let data_left = left.data.compose(&b_prime).unwrap();
+    let data_right = right.data.compose(&a_prime).unwrap();
+    (
+        Document {
+            data: data_left,
+            history: left.history.clone(),
+        },
+        Document {
+            data: data_right,
+            history: right.history.clone(),
+        },
+    )
+}
+
+fn split_length_with_interval(length: usize, interval: Interval) -> (Interval, Interval, Interval) {
+    let original_interval = Interval::new(0, length);
+    let prefix = original_interval.prefix(interval);
+    let suffix = original_interval.suffix(interval);
+    (prefix, interval, suffix)
+}
+
+fn split_interval_with_delta(delta: &Delta, interval: &Interval) -> Vec<Interval> {
+    let mut start = 0;
+    let mut new_intervals = vec![];
+    delta.ops.iter().for_each(|op| match op {
+        Operation::Delete(_) => {},
+        Operation::Retain(_) => {},
+        Operation::Insert(insert) => {
+            let len = insert.num_chars() as usize;
+            let end = start + len;
+            let insert_interval = Interval::new(start, end);
+            let new_interval = interval.intersect(insert_interval);
+
+            if !new_interval.is_empty() {
+                new_intervals.push(new_interval)
+            }
+            start += len;
+        },
+    });
+    new_intervals
+}

+ 50 - 0
rust-lib/flowy-ot/src/client/history.rs

@@ -0,0 +1,50 @@
+use crate::core::{Delta, Interval, OpBuilder, Operation};
+
+const MAX_UNDOS: usize = 20;
+
+#[derive(Debug, Clone)]
+pub struct Revision {
+    rev_id: u64,
+    delta: Delta,
+}
+
+#[derive(Debug, Clone)]
+pub struct UndoResult {
+    success: bool,
+    len: u64,
+}
+
+#[derive(Debug, Clone)]
+pub struct History {
+    cur_undo: usize,
+    undos: Vec<Revision>,
+    redos: Vec<Revision>,
+}
+
+impl History {
+    pub fn new() -> Self {
+        History {
+            cur_undo: 1,
+            undos: Vec::new(),
+            redos: Vec::new(),
+        }
+    }
+
+    pub fn can_undo(&self) -> bool { !self.undos.is_empty() }
+
+    pub fn can_redo(&self) -> bool { !self.redos.is_empty() }
+
+    pub fn record(&mut self, _change: Delta) {}
+
+    pub fn undo(&mut self) -> Option<Revision> {
+        if !self.can_undo() {
+            return None;
+        }
+
+        let revision = self.undos.pop().unwrap();
+
+        Some(revision)
+    }
+
+    pub fn redo(&mut self) -> Option<Revision> { None }
+}

+ 254 - 0
rust-lib/flowy-ot/src/core/attributes/attributes.rs

@@ -0,0 +1,254 @@
+use crate::core::{should_remove, Operation};
+use std::{collections::HashMap, fmt};
+
+#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize)]
+#[serde(untagged)]
+pub enum Attributes {
+    #[serde(skip)]
+    Follow,
+    Custom(AttributesData),
+    #[serde(skip)]
+    Empty,
+}
+
+impl Attributes {
+    pub fn data(&self) -> Option<AttributesData> {
+        match self {
+            Attributes::Follow => None,
+            Attributes::Custom(data) => Some(data.clone()),
+            Attributes::Empty => None,
+        }
+    }
+
+    pub fn is_empty(&self) -> bool {
+        match self {
+            Attributes::Follow => true,
+            Attributes::Custom(data) => data.is_empty(),
+            Attributes::Empty => true,
+        }
+    }
+}
+
+impl std::default::Default for Attributes {
+    fn default() -> Self { Attributes::Empty }
+}
+
+impl fmt::Display for Attributes {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Attributes::Follow => {
+                f.write_str("")?;
+            },
+            Attributes::Custom(data) => {
+                f.write_fmt(format_args!("{:?}", data.inner))?;
+            },
+            Attributes::Empty => {
+                f.write_str("")?;
+            },
+        }
+        Ok(())
+    }
+}
+
+#[derive(Debug, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)]
+pub struct AttributesData {
+    #[serde(skip_serializing_if = "HashMap::is_empty")]
+    #[serde(flatten)]
+    inner: HashMap<String, String>,
+}
+
+impl AttributesData {
+    pub fn new() -> Self {
+        AttributesData {
+            inner: HashMap::new(),
+        }
+    }
+    pub fn is_empty(&self) -> bool {
+        self.inner.values().filter(|v| !should_remove(v)).count() == 0
+    }
+
+    fn remove_empty(&mut self) { self.inner.retain(|_, v| !should_remove(v)); }
+
+    pub fn extend(&mut self, other: AttributesData) { self.inner.extend(other.inner); }
+
+    pub fn merge(&mut self, other: Option<AttributesData>) {
+        if other.is_none() {
+            return;
+        }
+
+        let mut new_attributes = other.unwrap().inner;
+        self.inner.iter().for_each(|(k, v)| {
+            if should_remove(v) {
+                new_attributes.remove(k);
+            } else {
+                new_attributes.insert(k.clone(), v.clone());
+            }
+        });
+        self.inner = new_attributes;
+    }
+}
+
+pub trait AttributesDataRule {
+    fn apply_rule(&mut self);
+
+    fn into_attributes(self) -> Attributes;
+}
+impl AttributesDataRule for AttributesData {
+    fn apply_rule(&mut self) { self.remove_empty(); }
+
+    fn into_attributes(mut self) -> Attributes {
+        self.apply_rule();
+
+        if self.is_empty() {
+            Attributes::Empty
+        } else {
+            Attributes::Custom(self)
+        }
+    }
+}
+
+pub trait AttributesRule {
+    fn apply_rule(self) -> Attributes;
+}
+
+impl AttributesRule for Attributes {
+    fn apply_rule(self) -> Attributes {
+        match self {
+            Attributes::Follow => self,
+            Attributes::Custom(data) => data.into_attributes(),
+            Attributes::Empty => self,
+        }
+    }
+}
+
+impl std::convert::From<HashMap<String, String>> for AttributesData {
+    fn from(attributes: HashMap<String, String>) -> Self { AttributesData { inner: attributes } }
+}
+
+impl std::ops::Deref for AttributesData {
+    type Target = HashMap<String, String>;
+
+    fn deref(&self) -> &Self::Target { &self.inner }
+}
+
+impl std::ops::DerefMut for AttributesData {
+    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner }
+}
+
+pub(crate) fn attributes_from(operation: &Option<Operation>) -> Option<Attributes> {
+    match operation {
+        None => None,
+        Some(operation) => Some(operation.get_attributes()),
+    }
+}
+
+pub fn compose_operation(left: &Option<Operation>, right: &Option<Operation>) -> Attributes {
+    if left.is_none() && right.is_none() {
+        return Attributes::Empty;
+    }
+    let attr_l = attributes_from(left);
+    let attr_r = attributes_from(right);
+
+    if attr_l.is_none() {
+        return attr_r.unwrap();
+    }
+
+    if attr_r.is_none() {
+        return attr_l.unwrap();
+    }
+
+    compose_attributes(attr_l.unwrap(), attr_r.unwrap())
+}
+
+pub fn transform_operation(left: &Option<Operation>, right: &Option<Operation>) -> Attributes {
+    let attr_l = attributes_from(left);
+    let attr_r = attributes_from(right);
+
+    if attr_l.is_none() {
+        if attr_r.is_none() {
+            return Attributes::Empty;
+        }
+
+        return match attr_r.as_ref().unwrap() {
+            Attributes::Follow => Attributes::Follow,
+            Attributes::Custom(_) => attr_r.unwrap(),
+            Attributes::Empty => Attributes::Empty,
+        };
+    }
+
+    transform_attributes(attr_l.unwrap(), attr_r.unwrap())
+}
+
+pub fn invert_attributes(attr: Attributes, base: Attributes) -> Attributes {
+    let attr = attr.data();
+    let base = base.data();
+
+    if attr.is_none() && base.is_none() {
+        return Attributes::Empty;
+    }
+
+    let attr = attr.unwrap_or(AttributesData::new());
+    let base = base.unwrap_or(AttributesData::new());
+
+    let base_inverted = base
+        .iter()
+        .fold(AttributesData::new(), |mut attributes, (k, v)| {
+            if base.get(k) != attr.get(k) && attr.contains_key(k) {
+                attributes.insert(k.clone(), v.clone());
+            }
+            attributes
+        });
+
+    let inverted = attr.iter().fold(base_inverted, |mut attributes, (k, _)| {
+        if base.get(k) != attr.get(k) && !base.contains_key(k) {
+            attributes.remove(k);
+        }
+        attributes
+    });
+
+    return Attributes::Custom(inverted);
+}
+
+pub fn merge_attributes(attributes: Attributes, other: Attributes) -> Attributes {
+    match (&attributes, &other) {
+        (Attributes::Custom(data), Attributes::Custom(o_data)) => {
+            let mut data = data.clone();
+            data.extend(o_data.clone());
+            Attributes::Custom(data)
+        },
+        (Attributes::Custom(data), _) => Attributes::Custom(data.clone()),
+        _ => other,
+    }
+}
+
+fn compose_attributes(left: Attributes, right: Attributes) -> Attributes {
+    log::trace!("compose_attributes: a: {:?}, b: {:?}", left, right);
+
+    let attr = match (&left, &right) {
+        (_, Attributes::Empty) => Attributes::Empty,
+        (_, Attributes::Custom(_)) => merge_attributes(left, right),
+        (Attributes::Custom(_), _) => merge_attributes(left, right),
+        _ => Attributes::Follow,
+    };
+
+    log::trace!("composed_attributes: a: {:?}", attr);
+    attr.apply_rule()
+}
+
+fn transform_attributes(left: Attributes, right: Attributes) -> Attributes {
+    match (left, right) {
+        (Attributes::Custom(data_l), Attributes::Custom(data_r)) => {
+            let result = data_r
+                .iter()
+                .fold(AttributesData::new(), |mut new_attr_data, (k, v)| {
+                    if !data_l.contains_key(k) {
+                        new_attr_data.insert(k.clone(), v.clone());
+                    }
+                    new_attr_data
+                });
+
+            Attributes::Custom(result)
+        },
+        _ => Attributes::Empty,
+    }
+}

+ 52 - 0
rust-lib/flowy-ot/src/core/attributes/builder.rs

@@ -0,0 +1,52 @@
+use crate::core::{Attributes, AttributesData};
+use derive_more::Display;
+const REMOVE_FLAG: &'static str = "";
+pub(crate) fn should_remove(s: &str) -> bool { s == REMOVE_FLAG }
+
+#[derive(Clone, Display)]
+pub enum Attribute {
+    #[display(fmt = "bold")]
+    Bold,
+    #[display(fmt = "italic")]
+    Italic,
+}
+
+pub struct AttrsBuilder {
+    inner: AttributesData,
+}
+
+impl AttrsBuilder {
+    pub fn new() -> Self {
+        Self {
+            inner: AttributesData::default(),
+        }
+    }
+
+    pub fn add_attribute(mut self, attribute: Attribute) -> Self {
+        self.inner
+            .insert(format!("{}", attribute), "true".to_owned());
+        self
+    }
+
+    pub fn remove_attribute(mut self, attribute: Attribute) -> Self {
+        self.inner
+            .insert(format!("{}", attribute), REMOVE_FLAG.to_owned());
+        self
+    }
+
+    pub fn bold(self, bold: bool) -> Self {
+        match bold {
+            true => self.add_attribute(Attribute::Bold),
+            false => self.remove_attribute(Attribute::Bold),
+        }
+    }
+
+    pub fn italic(self, italic: bool) -> Self {
+        match italic {
+            true => self.add_attribute(Attribute::Italic),
+            false => self.remove_attribute(Attribute::Italic),
+        }
+    }
+
+    pub fn build(self) -> Attributes { Attributes::Custom(self.inner) }
+}

+ 5 - 0
rust-lib/flowy-ot/src/core/attributes/mod.rs

@@ -0,0 +1,5 @@
+mod attributes;
+mod builder;
+
+pub use attributes::*;
+pub use builder::*;

+ 36 - 0
rust-lib/flowy-ot/src/core/operation/builder.rs

@@ -0,0 +1,36 @@
+use crate::core::{Attributes, Operation};
+
+pub struct OpBuilder {
+    ty: Operation,
+    attrs: Attributes,
+}
+
+impl OpBuilder {
+    pub fn new(ty: Operation) -> OpBuilder {
+        OpBuilder {
+            ty,
+            attrs: Attributes::Empty,
+        }
+    }
+
+    pub fn retain(n: u64) -> OpBuilder { OpBuilder::new(Operation::Retain(n.into())) }
+
+    pub fn delete(n: u64) -> OpBuilder { OpBuilder::new(Operation::Delete(n)) }
+
+    pub fn insert(s: &str) -> OpBuilder { OpBuilder::new(Operation::Insert(s.into())) }
+
+    pub fn attributes(mut self, attrs: Attributes) -> OpBuilder {
+        self.attrs = attrs;
+        self
+    }
+
+    pub fn build(self) -> Operation {
+        let mut operation = self.ty;
+        match &mut operation {
+            Operation::Delete(_) => {},
+            Operation::Retain(retain) => retain.attributes = self.attrs,
+            Operation::Insert(insert) => insert.attributes = self.attrs,
+        }
+        operation
+    }
+}

+ 7 - 0
rust-lib/flowy-ot/src/core/operation/mod.rs

@@ -0,0 +1,7 @@
+mod builder;
+mod operation;
+mod operation_serde;
+
+pub use builder::*;
+pub use operation::*;
+pub use operation_serde::*;

+ 197 - 0
rust-lib/flowy-ot/src/core/operation/operation.rs

@@ -0,0 +1,197 @@
+use crate::core::{Attributes, OpBuilder};
+use bytecount::num_chars;
+use std::{
+    fmt,
+    ops::{Deref, DerefMut},
+    str::Chars,
+};
+
+#[derive(Debug, Clone, PartialEq)]
+pub enum Operation {
+    Delete(u64),
+    Retain(Retain),
+    Insert(Insert),
+}
+
+impl Operation {
+    pub fn is_delete(&self) -> bool {
+        match self {
+            Operation::Delete(_) => true,
+            _ => false,
+        }
+    }
+
+    pub fn is_noop(&self) -> bool {
+        match self {
+            Operation::Retain(_) => true,
+            _ => false,
+        }
+    }
+
+    pub fn get_attributes(&self) -> Attributes {
+        match self {
+            Operation::Delete(_) => Attributes::Empty,
+            Operation::Retain(retain) => retain.attributes.clone(),
+            Operation::Insert(insert) => insert.attributes.clone(),
+        }
+    }
+
+    pub fn set_attributes(&mut self, attributes: Attributes) {
+        match self {
+            Operation::Delete(_) => {
+                log::error!("Delete should not contains attributes");
+            },
+            Operation::Retain(retain) => {
+                retain.attributes = attributes;
+            },
+            Operation::Insert(insert) => {
+                insert.attributes = attributes;
+            },
+        }
+    }
+
+    pub fn has_attribute(&self) -> bool {
+        match self.get_attributes() {
+            Attributes::Follow => true,
+            Attributes::Custom(_) => false,
+            Attributes::Empty => true,
+        }
+    }
+
+    pub fn length(&self) -> u64 {
+        match self {
+            Operation::Delete(n) => *n,
+            Operation::Retain(r) => r.n,
+            Operation::Insert(i) => i.num_chars(),
+        }
+    }
+
+    pub fn is_empty(&self) -> bool { self.length() == 0 }
+}
+
+impl fmt::Display for Operation {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Operation::Delete(n) => {
+                f.write_fmt(format_args!("delete: {}", n))?;
+            },
+            Operation::Retain(r) => {
+                f.write_fmt(format_args!(
+                    "retain: {}, attributes: {}",
+                    r.n, r.attributes
+                ))?;
+            },
+            Operation::Insert(i) => {
+                f.write_fmt(format_args!(
+                    "insert: {}, attributes: {}",
+                    i.s, i.attributes
+                ))?;
+            },
+        }
+        Ok(())
+    }
+}
+
+#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
+pub struct Retain {
+    #[serde(rename(serialize = "retain", deserialize = "retain"))]
+    pub n: u64,
+    #[serde(skip_serializing_if = "is_empty")]
+    pub attributes: Attributes,
+}
+
+impl Retain {
+    pub fn merge_or_new_op(&mut self, n: u64, attributes: Attributes) -> Option<Operation> {
+        log::debug!(
+            "merge_retain_or_new_op: {:?}, {:?}",
+            self.attributes,
+            attributes
+        );
+
+        match &attributes {
+            Attributes::Follow => {
+                log::debug!("Follow attribute: {:?}", self.attributes);
+                self.n += n;
+                None
+            },
+            Attributes::Custom(_) | Attributes::Empty => {
+                if self.attributes == attributes {
+                    log::debug!("Attribute equal");
+                    self.n += n;
+                    None
+                } else {
+                    log::debug!("New retain op");
+                    Some(OpBuilder::retain(n).attributes(attributes).build())
+                }
+            },
+        }
+    }
+}
+
+impl std::convert::From<u64> for Retain {
+    fn from(n: u64) -> Self {
+        Retain {
+            n,
+            attributes: Attributes::default(),
+        }
+    }
+}
+
+impl Deref for Retain {
+    type Target = u64;
+
+    fn deref(&self) -> &Self::Target { &self.n }
+}
+
+impl DerefMut for Retain {
+    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.n }
+}
+
+#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
+pub struct Insert {
+    #[serde(rename(serialize = "insert", deserialize = "insert"))]
+    pub s: String,
+
+    #[serde(skip_serializing_if = "is_empty")]
+    pub attributes: Attributes,
+}
+
+impl Insert {
+    pub fn as_bytes(&self) -> &[u8] { self.s.as_bytes() }
+
+    pub fn chars(&self) -> Chars<'_> { self.s.chars() }
+
+    pub fn num_chars(&self) -> u64 { num_chars(self.s.as_bytes()) as _ }
+
+    pub fn merge_or_new_op(&mut self, s: &str, attributes: Attributes) -> Option<Operation> {
+        match &attributes {
+            Attributes::Follow => {
+                self.s += s;
+                return None;
+            },
+            Attributes::Custom(_) | Attributes::Empty => {
+                if self.attributes == attributes {
+                    self.s += s;
+                    None
+                } else {
+                    Some(OpBuilder::insert(s).attributes(attributes).build())
+                }
+            },
+        }
+    }
+}
+
+impl std::convert::From<String> for Insert {
+    fn from(s: String) -> Self {
+        Insert {
+            s,
+            attributes: Attributes::default(),
+        }
+    }
+}
+
+impl std::convert::From<&str> for Insert {
+    fn from(s: &str) -> Self { Insert::from(s.to_owned()) }
+}
+
+fn is_empty(attributes: &Attributes) -> bool { attributes.is_empty() }

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

@@ -0,0 +1,137 @@
+use crate::core::{Attributes, Delta, Operation};
+use serde::{
+    de,
+    de::{MapAccess, SeqAccess, Visitor},
+    ser::{SerializeMap, SerializeSeq},
+    Deserialize,
+    Deserializer,
+    Serialize,
+    Serializer,
+};
+use std::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.unwrap_or(Attributes::Empty));
+                        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)
+    }
+}

+ 29 - 149
rust-lib/flowy-ot/tests/helper/mod.rs

@@ -1,5 +1,8 @@
 use derive_more::Display;
-use flowy_ot::core::*;
+use flowy_ot::{
+    client::{transform, Document},
+    core::*,
+};
 use rand::{prelude::*, Rng as WrappedRng};
 use std::sync::Once;
 
@@ -29,15 +32,12 @@ pub enum TestOp {
     #[display(fmt = "Undo")]
     Undo(usize, usize),
 
-    #[display(fmt = "AssertStr")]
-    AssertStr(usize, &'static str),
-
     #[display(fmt = "AssertOpsJson")]
     AssertOpsJson(usize, &'static str),
 }
 
 pub struct OpTester {
-    deltas: Vec<Delta>,
+    documents: Vec<Document>,
 }
 
 impl OpTester {
@@ -48,52 +48,47 @@ impl OpTester {
             env_logger::init();
         });
 
-        let mut deltas = Vec::with_capacity(2);
+        let mut documents = Vec::with_capacity(2);
         for _ in 0..2 {
-            let delta = Delta::default();
-            deltas.push(delta);
+            documents.push(Document::new());
         }
-        Self { deltas }
+        Self { documents }
     }
 
     pub fn run_op(&mut self, op: &TestOp) {
         log::debug!("***************** 😈{} *******************", &op);
         match op {
             TestOp::Insert(delta_i, s, index) => {
-                self.update_delta_with_insert(*delta_i, s, *index);
+                let document = &mut self.documents[*delta_i];
+                document.edit(*index, s);
             },
             TestOp::Delete(delta_i, interval) => {
-                //
-                self.update_delta_with_delete(*delta_i, interval);
+                let document = &mut self.documents[*delta_i];
+                document.delete(*interval);
             },
-            TestOp::InsertBold(delta_i, s, _interval) => {
-                let attrs = AttrsBuilder::new().bold(true).build();
-                let delta = &mut self.deltas[*delta_i];
-                delta.insert(s, attrs);
+            TestOp::InsertBold(delta_i, s, interval) => {
+                let document = &mut self.documents[*delta_i];
+                document.edit(interval.start, s);
+                document.format(*interval, Attribute::Bold, true);
             },
             TestOp::Bold(delta_i, interval, enable) => {
-                let attrs = AttrsBuilder::new().bold(*enable).build();
-                self.update_delta_with_attribute(*delta_i, attrs, interval);
+                let document = &mut self.documents[*delta_i];
+                document.format(*interval, Attribute::Bold, *enable);
             },
             TestOp::Italic(delta_i, interval, enable) => {
-                let attrs = AttrsBuilder::new().italic(*enable).build();
-                self.update_delta_with_attribute(*delta_i, attrs, interval);
+                let document = &mut self.documents[*delta_i];
+                document.format(*interval, Attribute::Italic, *enable);
             },
             TestOp::Transform(delta_a_i, delta_b_i) => {
-                let delta_a = &self.deltas[*delta_a_i];
-                let delta_b = &self.deltas[*delta_b_i];
-
-                let (a_prime, b_prime) = delta_a.transform(delta_b).unwrap();
-                log::trace!("a:{:?},b:{:?}", a_prime, b_prime);
-                let new_delta_a = delta_a.compose(&b_prime).unwrap();
-                let new_delta_b = delta_b.compose(&a_prime).unwrap();
+                let (document_a, document_b) =
+                    transform(&self.documents[*delta_a_i], &self.documents[*delta_b_i]);
 
-                self.deltas[*delta_a_i] = new_delta_a;
-                self.deltas[*delta_b_i] = new_delta_b;
+                self.documents[*delta_a_i] = document_a;
+                self.documents[*delta_b_i] = document_b;
             },
             TestOp::Undo(delta_a_i, delta_b_i) => {
-                let delta_a = &self.deltas[*delta_a_i];
-                let delta_b = &self.deltas[*delta_b_i];
+                let delta_a = &self.documents[*delta_a_i].data();
+                let delta_b = &self.documents[*delta_b_i].data();
                 log::debug!("Invert: ");
                 log::debug!("a: {}", delta_a.to_json());
                 log::debug!("b: {}", delta_b.to_json());
@@ -109,18 +104,13 @@ impl OpTester {
 
                 log::debug!("inverted delta a: {}", new_delta_after_undo.to_string());
 
-                assert_eq!(delta_a, &new_delta_after_undo);
+                assert_eq!(delta_a, &&new_delta_after_undo);
 
-                self.deltas[*delta_a_i] = new_delta_after_undo;
-            },
-            TestOp::AssertStr(delta_i, expected) => {
-                let s = self.deltas[*delta_i].apply("").unwrap();
-                assert_eq!(&s, expected);
+                self.documents[*delta_a_i].set_data(new_delta_after_undo);
             },
 
             TestOp::AssertOpsJson(delta_i, expected) => {
-                log::debug!("AssertOpsJson: {:?}", self.deltas[*delta_i]);
-                let delta_i_json = serde_json::to_string(&self.deltas[*delta_i]).unwrap();
+                let delta_i_json = self.documents[*delta_i].to_json();
 
                 let expected_delta: Delta = serde_json::from_str(expected).unwrap();
                 let target_delta: Delta = serde_json::from_str(&delta_i_json).unwrap();
@@ -139,116 +129,6 @@ impl OpTester {
             self.run_op(op);
         }
     }
-
-    pub fn get_delta(&mut self, index: usize) -> &mut Delta { &mut self.deltas[index] }
-
-    pub fn update_delta_with_insert(&mut self, delta_index: usize, s: &str, index: usize) {
-        let old_delta = &mut self.deltas[delta_index];
-        let target_interval = Interval::new(0, old_delta.target_len);
-        if old_delta.target_len < index {
-            log::error!("{} out of bounds {}", index, target_interval);
-        }
-
-        let mut attributes = old_delta.get_attributes(Interval::new(index, index + 1));
-        if attributes == Attributes::Empty {
-            attributes = Attributes::Follow;
-        }
-        let insert = OpBuilder::insert(s).attributes(attributes).build();
-        let new_delta = new_delta_with_op(old_delta, insert, Interval::new(index, index));
-        self.deltas[delta_index] = new_delta;
-    }
-
-    pub fn update_delta_with_attribute(
-        &mut self,
-        delta_index: usize,
-        mut attributes: Attributes,
-        interval: &Interval,
-    ) {
-        let old_delta = &self.deltas[delta_index];
-        let old_attributes = old_delta.get_attributes(*interval);
-        log::debug!(
-            "merge attributes: {:?}, with old: {:?}",
-            attributes,
-            old_attributes
-        );
-        let new_attributes = match &mut attributes {
-            Attributes::Follow => old_attributes,
-            Attributes::Custom(attr_data) => {
-                attr_data.merge(old_attributes.data());
-                attr_data.clone().into_attributes()
-            },
-            Attributes::Empty => Attributes::Empty,
-        };
-
-        log::debug!("new attributes: {:?}", new_attributes);
-        let retain = OpBuilder::retain(interval.size() as u64)
-            .attributes(new_attributes)
-            .build();
-
-        log::debug!(
-            "Update delta with new attributes: {:?} at: {:?}",
-            retain,
-            interval
-        );
-
-        let new_delta = new_delta_with_op(old_delta, retain, *interval);
-        self.deltas[delta_index] = new_delta;
-    }
-
-    pub fn update_delta_with_delete(&mut self, delta_index: usize, interval: &Interval) {
-        let old_delta = &self.deltas[delta_index];
-        let delete = OpBuilder::delete(interval.size() as u64).build();
-        let new_delta = new_delta_with_op(old_delta, delete, *interval);
-        self.deltas[delta_index] = new_delta;
-    }
-}
-
-fn new_delta_with_op(delta: &Delta, op: Operation, interval: Interval) -> Delta {
-    let mut new_delta = Delta::default();
-    let (prefix, interval, suffix) = target_length_split_with_interval(delta.target_len, interval);
-
-    // prefix
-    if prefix.is_empty() == false && prefix != interval {
-        let intervals = split_interval_with_delta(delta, &prefix);
-        intervals.into_iter().for_each(|p_interval| {
-            let attributes = delta.get_attributes(p_interval);
-            log::debug!(
-                "prefix attribute: {:?}, interval: {:?}",
-                attributes,
-                p_interval
-            );
-            new_delta.retain(p_interval.size() as u64, attributes);
-        });
-    }
-
-    log::debug!("add new op: {:?}", op);
-    new_delta.add(op);
-
-    // suffix
-    if suffix.is_empty() == false {
-        let intervals = split_interval_with_delta(delta, &suffix);
-        intervals.into_iter().for_each(|s_interval| {
-            let attributes = delta.get_attributes(s_interval);
-            log::debug!(
-                "suffix attribute: {:?}, interval: {:?}",
-                attributes,
-                s_interval
-            );
-            new_delta.retain(s_interval.size() as u64, attributes);
-        });
-    }
-
-    delta.compose(&new_delta).unwrap()
-}
-
-pub fn target_length_split_with_interval(
-    length: usize,
-    interval: Interval,
-) -> (Interval, Interval, Interval) {
-    let original_interval = Interval::new(0, length);
-    let prefix = original_interval.prefix(interval);
-    let suffix = original_interval.suffix(interval);
-    (prefix, interval, suffix)
 }
 
 pub fn debug_print_delta(delta: &Delta) {

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

@@ -191,8 +191,6 @@ fn transform2() {
         Insert(0, "123", 0),
         Insert(1, "456", 0),
         Transform(0, 1),
-        AssertStr(0, "123456"),
-        AssertStr(1, "123456"),
         AssertOpsJson(0, r#"[{"insert":"123456"}]"#),
         AssertOpsJson(1, r#"[{"insert":"123456"}]"#),
     ];