mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
operation & delta serde
This commit is contained in:
parent
eae0c17dda
commit
592244f6b9
@ -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"
|
||||
|
@ -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>,
|
||||
}
|
||||
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
@ -2,3 +2,4 @@ pub mod attributes;
|
||||
pub mod delta;
|
||||
pub mod errors;
|
||||
pub mod operation;
|
||||
mod operation_serde;
|
||||
|
@ -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
rust-lib/flowy-ot/src/operation_serde.rs
Normal file
137
rust-lib/flowy-ot/src/operation_serde.rs
Normal file
@ -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
rust-lib/flowy-ot/tests/mod.rs
Normal file
2
rust-lib/flowy-ot/tests/mod.rs
Normal file
@ -0,0 +1,2 @@
|
||||
mod helper;
|
||||
mod serde_test;
|
@ -1,5 +1,3 @@
|
||||
mod helper;
|
||||
|
||||
use crate::helper::Rng;
|
||||
use bytecount::num_chars;
|
||||
use flowy_ot::{
|
||||
|
55
rust-lib/flowy-ot/tests/serde_test.rs
Normal file
55
rust-lib/flowy-ot/tests/serde_test.rs
Normal file
@ -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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user