operation & delta serde

This commit is contained in:
appflowy 2021-08-01 14:39:30 +08:00
parent eae0c17dda
commit 592244f6b9
9 changed files with 257 additions and 25 deletions

View File

@ -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"

View File

@ -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>,
}

View File

@ -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(),
}
}

View File

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

View File

@ -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,
}
}
}

View 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)
}
}

View File

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

View File

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

View 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);
}