generic lib-ot

This commit is contained in:
appflowy 2021-12-07 10:39:01 +08:00
parent 8457682092
commit 2f413a8e67
44 changed files with 1023 additions and 586 deletions

View File

@ -13,7 +13,7 @@ use flowy_document_infra::{
entities::ws::{WsDataType, WsDocumentData},
protobuf::{Doc, RevId, RevType, Revision, RevisionRange, UpdateDocParams},
};
use lib_ot::core::{Delta, OperationTransformable};
use lib_ot::core::{OperationTransformable, RichTextDelta};
use parking_lot::RwLock;
use protobuf::Message;
use sqlx::PgPool;
@ -35,7 +35,7 @@ pub struct ServerDocEditor {
impl ServerDocEditor {
pub fn new(doc: Doc) -> Result<Self, ServerError> {
let delta = Delta::from_bytes(&doc.data).map_err(internal_error)?;
let delta = RichTextDelta::from_bytes(&doc.data).map_err(internal_error)?;
let document = Arc::new(RwLock::new(Document::from_delta(delta)));
let users = DashMap::new();
Ok(Self {
@ -123,7 +123,7 @@ impl ServerDocEditor {
pub fn document_json(&self) -> String { self.document.read().to_json() }
async fn compose_revision(&self, revision: &Revision, pg_pool: Data<PgPool>) -> Result<(), ServerError> {
let delta = Delta::from_bytes(&revision.delta_data).map_err(internal_error)?;
let delta = RichTextDelta::from_bytes(&revision.delta_data).map_err(internal_error)?;
let _ = self.compose_delta(delta)?;
let _ = self.rev_id.fetch_update(SeqCst, SeqCst, |_e| Some(revision.rev_id));
let _ = self.save_revision(&revision, pg_pool).await?;
@ -132,7 +132,7 @@ impl ServerDocEditor {
#[tracing::instrument(level = "debug", skip(self, revision))]
fn transform_revision(&self, revision: &Revision) -> Result<Revision, ServerError> {
let cli_delta = Delta::from_bytes(&revision.delta_data).map_err(internal_error)?;
let cli_delta = RichTextDelta::from_bytes(&revision.delta_data).map_err(internal_error)?;
let (cli_prime, server_prime) = self
.document
.read()
@ -145,7 +145,7 @@ impl ServerDocEditor {
Ok(cli_revision)
}
fn mk_revision(&self, base_rev_id: i64, delta: Delta) -> Revision {
fn mk_revision(&self, base_rev_id: i64, delta: RichTextDelta) -> Revision {
let delta_data = delta.to_bytes().to_vec();
let md5 = md5(&delta_data);
Revision {
@ -167,7 +167,7 @@ impl ServerDocEditor {
result,
)
)]
fn compose_delta(&self, delta: Delta) -> Result<(), ServerError> {
fn compose_delta(&self, delta: RichTextDelta) -> Result<(), ServerError> {
if delta.is_empty() {
log::warn!("Composed delta is empty");
}

View File

@ -16,7 +16,6 @@ use flowy_user_infra::{
use sqlx::{PgPool, Postgres};
use super::AUTHORIZED_USERS;
use crate::services::user::user_default::create_default_workspace;
pub async fn sign_in(pool: &PgPool, params: SignInParams) -> Result<SignInResponse, ServerError> {
let email = UserEmail::parse(params.email).map_err(|e| ServerError::params_invalid().context(e))?;

View File

@ -1,6 +1,6 @@
use crate::document::helper::{DocScript, DocumentTest};
use flowy_document_infra::core::{Document, FlowyDoc};
use lib_ot::core::{Attribute, Interval};
use lib_ot::core::{Interval, RichTextAttribute};
#[rustfmt::skip]
// ┌─────────┐ ┌─────────┐
@ -51,11 +51,11 @@ async fn delta_sync_while_editing_with_attribute() {
DocScript::ClientConnectWs,
DocScript::ClientOpenDoc,
DocScript::ClientInsertText(0, "abc"),
DocScript::ClientFormatText(Interval::new(0, 3), Attribute::Bold(true)),
DocScript::ClientFormatText(Interval::new(0, 3), RichTextAttribute::Bold(true)),
DocScript::AssertClient(r#"[{"insert":"abc","attributes":{"bold":true}},{"insert":"\n"}]"#),
DocScript::AssertServer(r#"[{"insert":"abc","attributes":{"bold":true}},{"insert":"\n"}]"#, 2),
DocScript::ClientInsertText(3, "efg"),
DocScript::ClientFormatText(Interval::new(3, 5), Attribute::Italic(true)),
DocScript::ClientFormatText(Interval::new(3, 5), RichTextAttribute::Italic(true)),
DocScript::AssertClient(r#"[{"insert":"abc","attributes":{"bold":true}},{"insert":"ef","attributes":{"bold":true,"italic":true}},{"insert":"g","attributes":{"bold":true}},{"insert":"\n"}]"#),
DocScript::AssertServer(r#"[{"insert":"abc","attributes":{"bold":true}},{"insert":"ef","attributes":{"bold":true,"italic":true}},{"insert":"g","attributes":{"bold":true}},{"insert":"\n"}]"#, 4),
])

View File

@ -1,7 +1,7 @@
#![allow(clippy::all)]
#![cfg_attr(rustfmt, rustfmt::skip)]
use actix_web::web::Data;
use backend::service::doc::{crud::update_doc, manager::DocManager};
use backend::services::doc::{crud::update_doc, manager::DocManager};
use flowy_document::services::doc::ClientDocEditor as ClientEditDocContext;
use flowy_test::{workspace::ViewTest, FlowyTest};
use flowy_user::services::user::UserSession;
@ -12,7 +12,7 @@ use tokio::time::{sleep, Duration};
// use crate::helper::*;
use crate::util::helper::{spawn_server, TestServer};
use flowy_document_infra::{entities::doc::DocIdentifier, protobuf::UpdateDocParams};
use lib_ot::core::{Attribute, Delta, Interval};
use lib_ot::core::{RichTextAttribute, RichTextDelta, Interval};
use parking_lot::RwLock;
pub struct DocumentTest {
@ -23,7 +23,7 @@ pub struct DocumentTest {
pub enum DocScript {
ClientConnectWs,
ClientInsertText(usize, &'static str),
ClientFormatText(Interval, Attribute),
ClientFormatText(Interval, RichTextAttribute),
ClientOpenDoc,
AssertClient(&'static str),
AssertServer(&'static str, i64),
@ -150,8 +150,8 @@ async fn run_scripts(context: Arc<RwLock<ScriptContext>>, scripts: Vec<DocScript
}
fn assert_eq(expect: &str, receive: &str) {
let expected_delta: Delta = serde_json::from_str(expect).unwrap();
let target_delta: Delta = serde_json::from_str(receive).unwrap();
let expected_delta: RichTextDelta = serde_json::from_str(expect).unwrap();
let target_delta: RichTextDelta = serde_json::from_str(receive).unwrap();
if expected_delta != target_delta {
log::error!("✅ expect: {}", expect,);

View File

@ -17,7 +17,7 @@ use flowy_document_infra::{
errors::DocumentResult,
};
use lib_infra::retry::{ExponentialBackoff, Retry};
use lib_ot::core::{Attribute, Delta, Interval};
use lib_ot::core::{Interval, RichTextAttribute, RichTextDelta};
use lib_ws::WsConnectState;
use std::{convert::TryFrom, sync::Arc};
use tokio::sync::{mpsc, mpsc::UnboundedSender, oneshot};
@ -60,7 +60,7 @@ impl ClientDocEditor {
}
pub async fn insert<T: ToString>(&self, index: usize, data: T) -> Result<(), DocError> {
let (ret, rx) = oneshot::channel::<DocumentResult<Delta>>();
let (ret, rx) = oneshot::channel::<DocumentResult<RichTextDelta>>();
let msg = EditCommand::Insert {
index,
data: data.to_string(),
@ -73,7 +73,7 @@ impl ClientDocEditor {
}
pub async fn delete(&self, interval: Interval) -> Result<(), DocError> {
let (ret, rx) = oneshot::channel::<DocumentResult<Delta>>();
let (ret, rx) = oneshot::channel::<DocumentResult<RichTextDelta>>();
let msg = EditCommand::Delete { interval, ret };
let _ = self.edit_tx.send(msg);
let delta = rx.await.map_err(internal_error)??;
@ -81,8 +81,8 @@ impl ClientDocEditor {
Ok(())
}
pub async fn format(&self, interval: Interval, attribute: Attribute) -> Result<(), DocError> {
let (ret, rx) = oneshot::channel::<DocumentResult<Delta>>();
pub async fn format(&self, interval: Interval, attribute: RichTextAttribute) -> Result<(), DocError> {
let (ret, rx) = oneshot::channel::<DocumentResult<RichTextDelta>>();
let msg = EditCommand::Format {
interval,
attribute,
@ -95,7 +95,7 @@ impl ClientDocEditor {
}
pub async fn replace<T: ToString>(&mut self, interval: Interval, data: T) -> Result<(), DocError> {
let (ret, rx) = oneshot::channel::<DocumentResult<Delta>>();
let (ret, rx) = oneshot::channel::<DocumentResult<RichTextDelta>>();
let msg = EditCommand::Replace {
interval,
data: data.to_string(),
@ -149,7 +149,7 @@ impl ClientDocEditor {
})
}
async fn save_local_delta(&self, delta: Delta) -> Result<RevId, DocError> {
async fn save_local_delta(&self, delta: RichTextDelta) -> Result<RevId, DocError> {
let delta_data = delta.to_bytes();
let (base_rev_id, rev_id) = self.rev_manager.next_rev_id();
let delta_data = delta_data.to_vec();
@ -160,7 +160,7 @@ impl ClientDocEditor {
#[tracing::instrument(level = "debug", skip(self, data), err)]
pub(crate) async fn composing_local_delta(&self, data: Bytes) -> Result<(), DocError> {
let delta = Delta::from_bytes(&data)?;
let delta = RichTextDelta::from_bytes(&data)?;
let (ret, rx) = oneshot::channel::<DocumentResult<()>>();
let msg = EditCommand::ComposeDelta {
delta: delta.clone(),
@ -314,7 +314,7 @@ fn spawn_rev_receiver(mut receiver: mpsc::UnboundedReceiver<Revision>, ws: Arc<d
});
}
fn spawn_edit_queue(doc_id: &str, delta: Delta, _pool: Arc<ConnectionPool>) -> UnboundedSender<EditCommand> {
fn spawn_edit_queue(doc_id: &str, delta: RichTextDelta, _pool: Arc<ConnectionPool>) -> UnboundedSender<EditCommand> {
let (sender, receiver) = mpsc::unbounded_channel::<EditCommand>();
let actor = EditCommandQueue::new(doc_id, delta, receiver);
tokio::spawn(actor.run());

View File

@ -6,7 +6,7 @@ use flowy_document_infra::{
errors::DocumentError,
};
use futures::stream::StreamExt;
use lib_ot::core::{Attribute, Delta, Interval, OperationTransformable};
use lib_ot::core::{Interval, OperationTransformable, RichTextAttribute, RichTextDelta};
use std::{convert::TryFrom, sync::Arc};
use tokio::sync::{mpsc, oneshot, RwLock};
@ -17,7 +17,7 @@ pub(crate) struct EditCommandQueue {
}
impl EditCommandQueue {
pub(crate) fn new(doc_id: &str, delta: Delta, receiver: mpsc::UnboundedReceiver<EditCommand>) -> Self {
pub(crate) fn new(doc_id: &str, delta: RichTextDelta, receiver: mpsc::UnboundedReceiver<EditCommand>) -> Self {
let document = Arc::new(RwLock::new(Document::from_delta(delta)));
Self {
doc_id: doc_id.to_owned(),
@ -54,7 +54,7 @@ impl EditCommandQueue {
},
EditCommand::RemoteRevision { bytes, ret } => {
let revision = Revision::try_from(bytes)?;
let delta = Delta::from_bytes(&revision.delta_data)?;
let delta = RichTextDelta::from_bytes(&revision.delta_data)?;
let rev_id: RevId = revision.rev_id.into();
let (server_prime, client_prime) = self.document.read().await.delta().transform(&delta)?;
let transform_delta = TransformDeltas {
@ -107,7 +107,7 @@ impl EditCommandQueue {
}
#[tracing::instrument(level = "debug", skip(self, delta), fields(compose_result), err)]
async fn composed_delta(&self, delta: Delta) -> Result<(), DocumentError> {
async fn composed_delta(&self, delta: RichTextDelta) -> Result<(), DocumentError> {
// tracing::debug!("{:?} thread handle_message", thread::current(),);
let mut document = self.document.write().await;
tracing::Span::current().record(
@ -125,7 +125,7 @@ impl EditCommandQueue {
pub(crate) type Ret<T> = oneshot::Sender<Result<T, DocumentError>>;
pub(crate) enum EditCommand {
ComposeDelta {
delta: Delta,
delta: RichTextDelta,
ret: Ret<()>,
},
RemoteRevision {
@ -135,22 +135,22 @@ pub(crate) enum EditCommand {
Insert {
index: usize,
data: String,
ret: Ret<Delta>,
ret: Ret<RichTextDelta>,
},
Delete {
interval: Interval,
ret: Ret<Delta>,
ret: Ret<RichTextDelta>,
},
Format {
interval: Interval,
attribute: Attribute,
ret: Ret<Delta>,
attribute: RichTextAttribute,
ret: Ret<RichTextDelta>,
},
Replace {
interval: Interval,
data: String,
ret: Ret<Delta>,
ret: Ret<RichTextDelta>,
},
CanUndo {
ret: oneshot::Sender<bool>,
@ -170,7 +170,7 @@ pub(crate) enum EditCommand {
}
pub(crate) struct TransformDeltas {
pub client_prime: Delta,
pub server_prime: Delta,
pub client_prime: RichTextDelta,
pub server_prime: RichTextDelta,
pub server_rev_id: RevId,
}

View File

@ -8,7 +8,7 @@ use flowy_document_infra::{
util::RevIdCounter,
};
use lib_infra::future::ResultFuture;
use lib_ot::core::{Delta, OperationTransformable};
use lib_ot::core::{OperationTransformable, RichTextDelta};
use std::sync::Arc;
use tokio::sync::mpsc;
@ -38,7 +38,7 @@ impl RevisionManager {
}
}
pub async fn load_document(&mut self) -> DocResult<Delta> {
pub async fn load_document(&mut self) -> DocResult<RichTextDelta> {
let doc = self.rev_store.fetch_document().await?;
self.update_rev_id_counter_value(doc.rev_id);
Ok(doc.delta()?)
@ -67,9 +67,9 @@ impl RevisionManager {
pub async fn mk_revisions(&self, range: RevisionRange) -> Result<Revision, DocError> {
debug_assert!(range.doc_id == self.doc_id);
let revisions = self.rev_store.revs_in_range(range.clone()).await?;
let mut new_delta = Delta::new();
let mut new_delta = RichTextDelta::new();
for revision in revisions {
match Delta::from_bytes(revision.delta_data) {
match RichTextDelta::from_bytes(revision.delta_data) {
Ok(delta) => {
new_delta = new_delta.compose(&delta)?;
},

View File

@ -9,7 +9,7 @@ use flowy_database::{ConnectionPool, SqliteConnection};
use flowy_document_infra::entities::doc::{revision_from_doc, Doc, RevId, RevType, Revision, RevisionRange};
use futures::stream::StreamExt;
use lib_infra::future::ResultFuture;
use lib_ot::core::{Delta, Operation, OperationTransformable};
use lib_ot::core::{Operation, OperationTransformable, RichTextDelta};
use std::{collections::VecDeque, sync::Arc, time::Duration};
use tokio::{
sync::{broadcast, mpsc, RwLock},
@ -188,9 +188,9 @@ async fn fetch_from_local(doc_id: &str, persistence: Arc<Persistence>) -> DocRes
let base_rev_id: RevId = revisions.last().unwrap().base_rev_id.into();
let rev_id: RevId = revisions.last().unwrap().rev_id.into();
let mut delta = Delta::new();
let mut delta = RichTextDelta::new();
for (_, revision) in revisions.into_iter().enumerate() {
match Delta::from_bytes(revision.delta_data) {
match RichTextDelta::from_bytes(revision.delta_data) {
Ok(local_delta) => {
delta = delta.compose(&local_delta)?;
},
@ -225,7 +225,7 @@ async fn fetch_from_local(doc_id: &str, persistence: Arc<Persistence>) -> DocRes
}
#[cfg(debug_assertions)]
fn validate_delta(doc_id: &str, persistence: Arc<Persistence>, conn: &SqliteConnection, delta: &Delta) {
fn validate_delta(doc_id: &str, persistence: Arc<Persistence>, conn: &SqliteConnection, delta: &RichTextDelta) {
if delta.ops.last().is_none() {
return;
}
@ -236,7 +236,7 @@ fn validate_delta(doc_id: &str, persistence: Arc<Persistence>, conn: &SqliteConn
let result = || {
let revisions = persistence.rev_sql.read_rev_tables(&doc_id, conn)?;
for revision in revisions {
let delta = Delta::from_bytes(revision.delta_data)?;
let delta = RichTextDelta::from_bytes(revision.delta_data)?;
log::error!("Invalid revision: {}:{}", revision.rev_id, delta.to_json());
}
Ok::<(), DocError>(())

View File

@ -1,7 +1,7 @@
#![cfg_attr(rustfmt, rustfmt::skip)]
use crate::editor::{TestBuilder, TestOp::*};
use flowy_document_infra::core::{FlowyDoc, PlainDoc};
use lib_ot::core::{Delta, Interval, OperationTransformable, NEW_LINE, WHITESPACE, FlowyStr};
use lib_ot::core::{Interval, OperationTransformable, NEW_LINE, WHITESPACE, FlowyStr, RichTextDelta};
use unicode_segmentation::UnicodeSegmentation;
#[test]
@ -760,12 +760,12 @@ fn attributes_preserve_list_format_on_merge() {
#[test]
fn delta_compose() {
let mut delta = Delta::from_json(r#"[{"insert":"\n"}]"#).unwrap();
let mut delta = RichTextDelta::from_json(r#"[{"insert":"\n"}]"#).unwrap();
let deltas = vec![
Delta::from_json(r#"[{"retain":1,"attributes":{"list":"unchecked"}}]"#).unwrap(),
Delta::from_json(r#"[{"insert":"a"}]"#).unwrap(),
Delta::from_json(r#"[{"retain":1},{"insert":"\n","attributes":{"list":"unchecked"}}]"#).unwrap(),
Delta::from_json(r#"[{"retain":2},{"retain":1,"attributes":{"list":""}}]"#).unwrap(),
RichTextDelta::from_json(r#"[{"retain":1,"attributes":{"list":"unchecked"}}]"#).unwrap(),
RichTextDelta::from_json(r#"[{"insert":"a"}]"#).unwrap(),
RichTextDelta::from_json(r#"[{"retain":1},{"insert":"\n","attributes":{"list":"unchecked"}}]"#).unwrap(),
RichTextDelta::from_json(r#"[{"retain":2},{"retain":1,"attributes":{"list":""}}]"#).unwrap(),
];
for d in deltas {

View File

@ -80,8 +80,8 @@ pub enum TestOp {
pub struct TestBuilder {
documents: Vec<Document>,
deltas: Vec<Option<Delta>>,
primes: Vec<Option<Delta>>,
deltas: Vec<Option<RichTextDelta>>,
primes: Vec<Option<RichTextDelta>>,
}
impl TestBuilder {
@ -125,11 +125,11 @@ impl TestBuilder {
TestOp::InsertBold(delta_i, s, iv) => {
let document = &mut self.documents[*delta_i];
document.insert(iv.start, s).unwrap();
document.format(*iv, Attribute::Bold(true)).unwrap();
document.format(*iv, RichTextAttribute::Bold(true)).unwrap();
},
TestOp::Bold(delta_i, iv, enable) => {
let document = &mut self.documents[*delta_i];
let attribute = Attribute::Bold(*enable);
let attribute = RichTextAttribute::Bold(*enable);
let delta = document.format(*iv, attribute).unwrap();
tracing::trace!("Bold delta: {}", delta.to_json());
self.deltas.insert(*delta_i, Some(delta));
@ -137,8 +137,8 @@ impl TestBuilder {
TestOp::Italic(delta_i, iv, enable) => {
let document = &mut self.documents[*delta_i];
let attribute = match *enable {
true => Attribute::Italic(true),
false => Attribute::Italic(false),
true => RichTextAttribute::Italic(true),
false => RichTextAttribute::Italic(false),
};
let delta = document.format(*iv, attribute).unwrap();
tracing::trace!("Italic delta: {}", delta.to_json());
@ -146,21 +146,21 @@ impl TestBuilder {
},
TestOp::Header(delta_i, iv, level) => {
let document = &mut self.documents[*delta_i];
let attribute = Attribute::Header(*level);
let attribute = RichTextAttribute::Header(*level);
let delta = document.format(*iv, attribute).unwrap();
tracing::trace!("Header delta: {}", delta.to_json());
self.deltas.insert(*delta_i, Some(delta));
},
TestOp::Link(delta_i, iv, link) => {
let document = &mut self.documents[*delta_i];
let attribute = Attribute::Link(link.to_owned());
let attribute = RichTextAttribute::Link(link.to_owned());
let delta = document.format(*iv, attribute).unwrap();
tracing::trace!("Link delta: {}", delta.to_json());
self.deltas.insert(*delta_i, Some(delta));
},
TestOp::Bullet(delta_i, iv, enable) => {
let document = &mut self.documents[*delta_i];
let attribute = Attribute::Bullet(*enable);
let attribute = RichTextAttribute::Bullet(*enable);
let delta = document.format(*iv, attribute).unwrap();
tracing::debug!("Bullet delta: {}", delta.to_json());
@ -225,8 +225,8 @@ impl TestBuilder {
TestOp::AssertDocJson(delta_i, expected) => {
let delta_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_json).unwrap();
let expected_delta: RichTextDelta = serde_json::from_str(expected).unwrap();
let target_delta: RichTextDelta = serde_json::from_str(&delta_json).unwrap();
if expected_delta != target_delta {
log::error!("✅ expect: {}", expected,);
@ -237,8 +237,8 @@ impl TestBuilder {
TestOp::AssertPrimeJson(doc_i, expected) => {
let prime_json = self.primes[*doc_i].as_ref().unwrap().to_json();
let expected_prime: Delta = serde_json::from_str(expected).unwrap();
let target_prime: Delta = serde_json::from_str(&prime_json).unwrap();
let expected_prime: RichTextDelta = serde_json::from_str(expected).unwrap();
let target_prime: RichTextDelta = serde_json::from_str(&prime_json).unwrap();
if expected_prime != target_prime {
log::error!("✅ expect prime: {}", expected,);
@ -292,8 +292,8 @@ impl Rng {
.collect()
}
pub fn gen_delta(&mut self, s: &str) -> Delta {
let mut delta = Delta::default();
pub fn gen_delta(&mut self, s: &str) -> RichTextDelta {
let mut delta = RichTextDelta::default();
loop {
let left = s.chars().count() - delta.base_len;
if left == 0 {
@ -306,18 +306,18 @@ impl Rng {
};
match self.0.gen_range(0.0, 1.0) {
f if f < 0.2 => {
delta.insert(&self.gen_string(i), Attributes::default());
delta.insert(&self.gen_string(i), RichTextAttributes::default());
},
f if f < 0.4 => {
delta.delete(i);
},
_ => {
delta.retain(i, Attributes::default());
delta.retain(i, RichTextAttributes::default());
},
}
}
if self.0.gen_range(0.0, 1.0) < 0.3 {
delta.insert(&("1".to_owned() + &self.gen_string(10)), Attributes::default());
delta.insert(&("1".to_owned() + &self.gen_string(10)), RichTextAttributes::default());
}
delta
}

View File

@ -35,7 +35,7 @@ fn attributes_insert_text_at_middle() {
#[test]
fn delta_get_ops_in_interval_1() {
let mut delta = Delta::default();
let mut delta = RichTextDelta::default();
let insert_a = OpBuilder::insert("123").build();
let insert_b = OpBuilder::insert("4").build();
@ -48,7 +48,7 @@ fn delta_get_ops_in_interval_1() {
#[test]
fn delta_get_ops_in_interval_2() {
let mut delta = Delta::default();
let mut delta = RichTextDelta::default();
let insert_a = OpBuilder::insert("123").build();
let insert_b = OpBuilder::insert("4").build();
let insert_c = OpBuilder::insert("5").build();
@ -92,7 +92,7 @@ fn delta_get_ops_in_interval_2() {
#[test]
fn delta_get_ops_in_interval_3() {
let mut delta = Delta::default();
let mut delta = RichTextDelta::default();
let insert_a = OpBuilder::insert("123456").build();
delta.add(insert_a.clone());
assert_eq!(
@ -103,7 +103,7 @@ fn delta_get_ops_in_interval_3() {
#[test]
fn delta_get_ops_in_interval_4() {
let mut delta = Delta::default();
let mut delta = RichTextDelta::default();
let insert_a = OpBuilder::insert("12").build();
let insert_b = OpBuilder::insert("34").build();
let insert_c = OpBuilder::insert("56").build();
@ -133,7 +133,7 @@ fn delta_get_ops_in_interval_4() {
#[test]
fn delta_get_ops_in_interval_5() {
let mut delta = Delta::default();
let mut delta = RichTextDelta::default();
let insert_a = OpBuilder::insert("123456").build();
let insert_b = OpBuilder::insert("789").build();
delta.ops.push(insert_a.clone());
@ -151,7 +151,7 @@ fn delta_get_ops_in_interval_5() {
#[test]
fn delta_get_ops_in_interval_6() {
let mut delta = Delta::default();
let mut delta = RichTextDelta::default();
let insert_a = OpBuilder::insert("12345678").build();
delta.add(insert_a.clone());
assert_eq!(
@ -162,7 +162,7 @@ fn delta_get_ops_in_interval_6() {
#[test]
fn delta_get_ops_in_interval_7() {
let mut delta = Delta::default();
let mut delta = RichTextDelta::default();
let insert_a = OpBuilder::insert("12345").build();
let retain_a = OpBuilder::retain(3).build();
@ -182,7 +182,7 @@ fn delta_get_ops_in_interval_7() {
#[test]
fn delta_seek_1() {
let mut delta = Delta::default();
let mut delta = RichTextDelta::default();
let insert_a = OpBuilder::insert("12345").build();
let retain_a = OpBuilder::retain(3).build();
delta.add(insert_a.clone());
@ -194,7 +194,7 @@ fn delta_seek_1() {
#[test]
fn delta_seek_2() {
let mut delta = Delta::default();
let mut delta = RichTextDelta::default();
delta.add(OpBuilder::insert("12345").build());
let mut iter = DeltaIter::new(&delta);
@ -203,7 +203,7 @@ fn delta_seek_2() {
#[test]
fn delta_seek_3() {
let mut delta = Delta::default();
let mut delta = RichTextDelta::default();
delta.add(OpBuilder::insert("12345").build());
let mut iter = DeltaIter::new(&delta);
@ -218,7 +218,7 @@ fn delta_seek_3() {
#[test]
fn delta_seek_4() {
let mut delta = Delta::default();
let mut delta = RichTextDelta::default();
delta.add(OpBuilder::insert("12345").build());
let mut iter = DeltaIter::new(&delta);
@ -228,10 +228,10 @@ fn delta_seek_4() {
#[test]
fn delta_seek_5() {
let mut delta = Delta::default();
let mut delta = RichTextDelta::default();
let attributes = AttributeBuilder::new()
.add_attr(Attribute::Bold(true))
.add_attr(Attribute::Italic(true))
.add_attr(RichTextAttribute::Bold(true))
.add_attr(RichTextAttribute::Italic(true))
.build();
delta.add(OpBuilder::insert("1234").attributes(attributes.clone()).build());
@ -248,7 +248,7 @@ fn delta_seek_5() {
#[test]
fn delta_next_op_len_test() {
let mut delta = Delta::default();
let mut delta = RichTextDelta::default();
delta.add(OpBuilder::insert("12345").build());
let mut iter = DeltaIter::new(&delta);
@ -261,7 +261,7 @@ fn delta_next_op_len_test() {
#[test]
fn delta_next_op_len_test2() {
let mut delta = Delta::default();
let mut delta = RichTextDelta::default();
delta.add(OpBuilder::insert("12345").build());
let mut iter = DeltaIter::new(&delta);
@ -272,7 +272,7 @@ fn delta_next_op_len_test2() {
#[test]
fn delta_next_op_with_len_zero() {
let mut delta = Delta::default();
let mut delta = RichTextDelta::default();
delta.add(OpBuilder::insert("12345").build());
let mut iter = DeltaIter::new(&delta);
assert_eq!(iter.next_op_with_len(0), None,);
@ -281,7 +281,7 @@ fn delta_next_op_with_len_zero() {
#[test]
fn delta_next_op_with_len_cross_op_return_last() {
let mut delta = Delta::default();
let mut delta = RichTextDelta::default();
delta.add(OpBuilder::insert("12345").build());
delta.add(OpBuilder::retain(1).build());
delta.add(OpBuilder::insert("678").build());
@ -294,16 +294,16 @@ fn delta_next_op_with_len_cross_op_return_last() {
#[test]
fn lengths() {
let mut delta = Delta::default();
let mut delta = RichTextDelta::default();
assert_eq!(delta.base_len, 0);
assert_eq!(delta.target_len, 0);
delta.retain(5, Attributes::default());
delta.retain(5, RichTextAttributes::default());
assert_eq!(delta.base_len, 5);
assert_eq!(delta.target_len, 5);
delta.insert("abc", Attributes::default());
delta.insert("abc", RichTextAttributes::default());
assert_eq!(delta.base_len, 5);
assert_eq!(delta.target_len, 8);
delta.retain(2, Attributes::default());
delta.retain(2, RichTextAttributes::default());
assert_eq!(delta.base_len, 7);
assert_eq!(delta.target_len, 10);
delta.delete(2);
@ -312,11 +312,11 @@ fn lengths() {
}
#[test]
fn sequence() {
let mut delta = Delta::default();
delta.retain(5, Attributes::default());
delta.retain(0, Attributes::default());
delta.insert("appflowy", Attributes::default());
delta.insert("", Attributes::default());
let mut delta = RichTextDelta::default();
delta.retain(5, RichTextAttributes::default());
delta.retain(0, RichTextAttributes::default());
delta.insert("appflowy", RichTextAttributes::default());
delta.insert("", RichTextAttributes::default());
delta.delete(3);
delta.delete(0);
assert_eq!(delta.ops.len(), 3);
@ -335,12 +335,12 @@ fn apply_1000() {
#[test]
fn apply() {
let s = "hello world,".to_owned();
let mut delta_a = Delta::default();
delta_a.insert(&s, Attributes::default());
let mut delta_a = RichTextDelta::default();
delta_a.insert(&s, RichTextAttributes::default());
let mut delta_b = Delta::default();
delta_b.retain(s.len(), Attributes::default());
delta_b.insert("appflowy", Attributes::default());
let mut delta_b = RichTextDelta::default();
delta_b.retain(s.len(), RichTextAttributes::default());
delta_b.insert("appflowy", RichTextAttributes::default());
let after_a = delta_a.apply("").unwrap();
let after_b = delta_b.apply(&after_a).unwrap();
@ -349,16 +349,16 @@ fn apply() {
#[test]
fn base_len_test() {
let mut delta_a = Delta::default();
delta_a.insert("a", Attributes::default());
delta_a.insert("b", Attributes::default());
delta_a.insert("c", Attributes::default());
let mut delta_a = RichTextDelta::default();
delta_a.insert("a", RichTextAttributes::default());
delta_a.insert("b", RichTextAttributes::default());
delta_a.insert("c", RichTextAttributes::default());
let s = "hello world,".to_owned();
delta_a.delete(s.len());
let after_a = delta_a.apply(&s).unwrap();
delta_a.insert("d", Attributes::default());
delta_a.insert("d", RichTextAttributes::default());
assert_eq!("abc", &after_a);
}
@ -377,43 +377,43 @@ fn invert() {
#[test]
fn empty_ops() {
let mut delta = Delta::default();
delta.retain(0, Attributes::default());
delta.insert("", Attributes::default());
let mut delta = RichTextDelta::default();
delta.retain(0, RichTextAttributes::default());
delta.insert("", RichTextAttributes::default());
delta.delete(0);
assert_eq!(delta.ops.len(), 0);
}
#[test]
fn eq() {
let mut delta_a = Delta::default();
let mut delta_a = RichTextDelta::default();
delta_a.delete(1);
delta_a.insert("lo", Attributes::default());
delta_a.retain(2, Attributes::default());
delta_a.retain(3, Attributes::default());
let mut delta_b = Delta::default();
delta_a.insert("lo", RichTextAttributes::default());
delta_a.retain(2, RichTextAttributes::default());
delta_a.retain(3, RichTextAttributes::default());
let mut delta_b = RichTextDelta::default();
delta_b.delete(1);
delta_b.insert("l", Attributes::default());
delta_b.insert("o", Attributes::default());
delta_b.retain(5, Attributes::default());
delta_b.insert("l", RichTextAttributes::default());
delta_b.insert("o", RichTextAttributes::default());
delta_b.retain(5, RichTextAttributes::default());
assert_eq!(delta_a, delta_b);
delta_a.delete(1);
delta_b.retain(1, Attributes::default());
delta_b.retain(1, RichTextAttributes::default());
assert_ne!(delta_a, delta_b);
}
#[test]
fn ops_merging() {
let mut delta = Delta::default();
let mut delta = RichTextDelta::default();
assert_eq!(delta.ops.len(), 0);
delta.retain(2, Attributes::default());
delta.retain(2, RichTextAttributes::default());
assert_eq!(delta.ops.len(), 1);
assert_eq!(delta.ops.last(), Some(&OpBuilder::retain(2).build()));
delta.retain(3, Attributes::default());
delta.retain(3, RichTextAttributes::default());
assert_eq!(delta.ops.len(), 1);
assert_eq!(delta.ops.last(), Some(&OpBuilder::retain(5).build()));
delta.insert("abc", Attributes::default());
delta.insert("abc", RichTextAttributes::default());
assert_eq!(delta.ops.len(), 2);
assert_eq!(delta.ops.last(), Some(&OpBuilder::insert("abc").build()));
delta.insert("xyz", Attributes::default());
delta.insert("xyz", RichTextAttributes::default());
assert_eq!(delta.ops.len(), 2);
assert_eq!(delta.ops.last(), Some(&OpBuilder::insert("abcxyz").build()));
delta.delete(1);
@ -425,13 +425,13 @@ fn ops_merging() {
}
#[test]
fn is_noop() {
let mut delta = Delta::default();
let mut delta = RichTextDelta::default();
assert!(delta.is_noop());
delta.retain(5, Attributes::default());
delta.retain(5, RichTextAttributes::default());
assert!(delta.is_noop());
delta.retain(3, Attributes::default());
delta.retain(3, RichTextAttributes::default());
assert!(delta.is_noop());
delta.insert("lorem", Attributes::default());
delta.insert("lorem", RichTextAttributes::default());
assert!(!delta.is_noop());
}
#[test]
@ -473,15 +473,18 @@ fn transform_random_delta() {
#[test]
fn transform_with_two_delta_test() {
let mut a = Delta::default();
let mut a = RichTextDelta::default();
let mut a_s = String::new();
a.insert("123", AttributeBuilder::new().add_attr(Attribute::Bold(true)).build());
a.insert(
"123",
AttributeBuilder::new().add_attr(RichTextAttribute::Bold(true)).build(),
);
a_s = a.apply(&a_s).unwrap();
assert_eq!(&a_s, "123");
let mut b = Delta::default();
let mut b = RichTextDelta::default();
let mut b_s = String::new();
b.insert("456", Attributes::default());
b.insert("456", RichTextAttributes::default());
b_s = b.apply(&b_s).unwrap();
assert_eq!(&b_s, "456");
@ -569,10 +572,10 @@ fn transform_two_conflict_non_seq_delta() {
#[test]
fn delta_invert_no_attribute_delta() {
let mut delta = Delta::default();
let mut delta = RichTextDelta::default();
delta.add(OpBuilder::insert("123").build());
let mut change = Delta::default();
let mut change = RichTextDelta::default();
change.add(OpBuilder::retain(3).build());
change.add(OpBuilder::insert("456").build());
let undo = change.invert(&delta);

View File

@ -4,14 +4,14 @@ use lib_ot::core::*;
#[test]
fn operation_insert_serialize_test() {
let attributes = AttributeBuilder::new()
.add_attr(Attribute::Bold(true))
.add_attr(Attribute::Italic(true))
.add_attr(RichTextAttribute::Bold(true))
.add_attr(RichTextAttribute::Italic(true))
.build();
let operation = OpBuilder::insert("123").attributes(attributes).build();
let json = serde_json::to_string(&operation).unwrap();
eprintln!("{}", json);
let insert_op: Operation = serde_json::from_str(&json).unwrap();
let insert_op: RichTextOperation = serde_json::from_str(&json).unwrap();
assert_eq!(insert_op, operation);
}
@ -20,23 +20,23 @@ 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();
let insert_op: RichTextOperation = serde_json::from_str(&json).unwrap();
assert_eq!(insert_op, operation);
}
#[test]
fn operation_delete_serialize_test() {
let operation = Operation::Delete(2);
let operation = RichTextOperation::Delete(2);
let json = serde_json::to_string(&operation).unwrap();
let insert_op: Operation = serde_json::from_str(&json).unwrap();
let insert_op: RichTextOperation = serde_json::from_str(&json).unwrap();
assert_eq!(insert_op, operation);
}
#[test]
fn attributes_serialize_test() {
let attributes = AttributeBuilder::new()
.add_attr(Attribute::Bold(true))
.add_attr(Attribute::Italic(true))
.add_attr(RichTextAttribute::Bold(true))
.add_attr(RichTextAttribute::Italic(true))
.build();
let retain = OpBuilder::insert("123").attributes(attributes).build();
@ -49,8 +49,8 @@ fn delta_serialize_multi_attribute_test() {
let mut delta = Delta::default();
let attributes = AttributeBuilder::new()
.add_attr(Attribute::Bold(true))
.add_attr(Attribute::Italic(true))
.add_attr(RichTextAttribute::Bold(true))
.add_attr(RichTextAttribute::Italic(true))
.build();
let retain = OpBuilder::insert("123").attributes(attributes).build();
@ -73,7 +73,7 @@ fn delta_deserialize_test() {
{"retain":2,"attributes":{"italic":"true","bold":"true"}},
{"retain":2,"attributes":{"italic":true,"bold":true}}
]"#;
let delta = Delta::from_json(json).unwrap();
let delta = RichTextDelta::from_json(json).unwrap();
eprintln!("{}", delta);
}
@ -82,10 +82,10 @@ fn delta_deserialize_null_test() {
let json = r#"[
{"retain":7,"attributes":{"bold":null}}
]"#;
let delta1 = Delta::from_json(json).unwrap();
let delta1 = RichTextDelta::from_json(json).unwrap();
let mut attribute = Attribute::Bold(true);
attribute.value = AttributeValue(None);
let mut attribute = RichTextAttribute::Bold(true);
attribute.value = RichTextAttributeValue(None);
let delta2 = DeltaBuilder::new().retain_with_attributes(7, attribute.into()).build();
assert_eq!(delta2.to_json(), r#"[{"retain":7,"attributes":{"bold":""}}]"#);
@ -94,8 +94,8 @@ fn delta_deserialize_null_test() {
#[test]
fn delta_serde_null_test() {
let mut attribute = Attribute::Bold(true);
attribute.value = AttributeValue(None);
let mut attribute = RichTextAttribute::Bold(true);
attribute.value = RichTextAttributeValue(None);
assert_eq!(attribute.to_json(), r#"{"bold":""}"#);
}

View File

@ -10,21 +10,21 @@ use lib_ot::core::*;
use tokio::sync::mpsc;
pub trait CustomDocument {
fn init_delta() -> Delta;
fn init_delta() -> RichTextDelta;
}
pub struct PlainDoc();
impl CustomDocument for PlainDoc {
fn init_delta() -> Delta { Delta::new() }
fn init_delta() -> RichTextDelta { RichTextDelta::new() }
}
pub struct FlowyDoc();
impl CustomDocument for FlowyDoc {
fn init_delta() -> Delta { doc_initial_delta() }
fn init_delta() -> RichTextDelta { doc_initial_delta() }
}
pub struct Document {
delta: Delta,
delta: RichTextDelta,
history: History,
view: View,
last_edit_time: usize,
@ -34,7 +34,7 @@ pub struct Document {
impl Document {
pub fn new<C: CustomDocument>() -> Self { Self::from_delta(C::init_delta()) }
pub fn from_delta(delta: Delta) -> Self {
pub fn from_delta(delta: RichTextDelta) -> Self {
Document {
delta,
history: History::new(),
@ -45,7 +45,7 @@ impl Document {
}
pub fn from_json(json: &str) -> Result<Self, DocumentError> {
let delta = Delta::from_json(json)?;
let delta = RichTextDelta::from_json(json)?;
Ok(Self::from_delta(delta))
}
@ -55,11 +55,11 @@ impl Document {
pub fn to_plain_string(&self) -> String { self.delta.apply("").unwrap() }
pub fn delta(&self) -> &Delta { &self.delta }
pub fn delta(&self) -> &RichTextDelta { &self.delta }
pub fn set_notify(&mut self, notify: mpsc::UnboundedSender<()>) { self.notify = Some(notify); }
pub fn set_delta(&mut self, data: Delta) {
pub fn set_delta(&mut self, data: RichTextDelta) {
self.delta = data;
match &self.notify {
@ -70,7 +70,7 @@ impl Document {
}
}
pub fn compose_delta(&mut self, mut delta: Delta) -> Result<(), DocumentError> {
pub fn compose_delta(&mut self, mut delta: RichTextDelta) -> Result<(), DocumentError> {
trim(&mut delta);
tracing::trace!("{} compose {}", &self.delta.to_json(), delta.to_json());
let mut composed_delta = self.delta.compose(&delta)?;
@ -100,7 +100,7 @@ impl Document {
Ok(())
}
pub fn insert<T: ToString>(&mut self, index: usize, data: T) -> Result<Delta, DocumentError> {
pub fn insert<T: ToString>(&mut self, index: usize, data: T) -> Result<RichTextDelta, DocumentError> {
let interval = Interval::new(index, index);
let _ = validate_interval(&self.delta, &interval)?;
@ -111,7 +111,7 @@ impl Document {
Ok(delta)
}
pub fn delete(&mut self, interval: Interval) -> Result<Delta, DocumentError> {
pub fn delete(&mut self, interval: Interval) -> Result<RichTextDelta, DocumentError> {
let _ = validate_interval(&self.delta, &interval)?;
debug_assert_eq!(interval.is_empty(), false);
let delete = self.view.delete(&self.delta, interval)?;
@ -122,7 +122,7 @@ impl Document {
Ok(delete)
}
pub fn format(&mut self, interval: Interval, attribute: Attribute) -> Result<Delta, DocumentError> {
pub fn format(&mut self, interval: Interval, attribute: RichTextAttribute) -> Result<RichTextDelta, DocumentError> {
let _ = validate_interval(&self.delta, &interval)?;
tracing::trace!("format with {} at {}", attribute, interval);
let format_delta = self.view.format(&self.delta, attribute, interval).unwrap();
@ -132,9 +132,9 @@ impl Document {
Ok(format_delta)
}
pub fn replace<T: ToString>(&mut self, interval: Interval, data: T) -> Result<Delta, DocumentError> {
pub fn replace<T: ToString>(&mut self, interval: Interval, data: T) -> Result<RichTextDelta, DocumentError> {
let _ = validate_interval(&self.delta, &interval)?;
let mut delta = Delta::default();
let mut delta = RichTextDelta::default();
let text = data.to_string();
if !text.is_empty() {
delta = self.view.insert(&self.delta, &text, interval)?;
@ -184,7 +184,7 @@ impl Document {
}
impl Document {
fn invert(&self, delta: &Delta) -> Result<(Delta, Delta), DocumentError> {
fn invert(&self, delta: &RichTextDelta) -> Result<(RichTextDelta, RichTextDelta), DocumentError> {
// c = a.compose(b)
// d = b.invert(a)
// a = c.compose(d)
@ -195,7 +195,7 @@ impl Document {
}
}
fn validate_interval(delta: &Delta, interval: &Interval) -> Result<(), DocumentError> {
fn validate_interval(delta: &RichTextDelta, interval: &Interval) -> Result<(), DocumentError> {
if delta.target_len < interval.end {
log::error!("{:?} out of bounds. should 0..{}", interval, delta.target_len);
return Err(DocumentError::out_of_bound());
@ -204,7 +204,7 @@ fn validate_interval(delta: &Delta, interval: &Interval) -> Result<(), DocumentE
}
/// Removes trailing retain operation with empty attributes, if present.
pub fn trim(delta: &mut Delta) {
pub fn trim(delta: &mut RichTextDelta) {
if let Some(last) = delta.ops.last() {
if last.is_retain() && last.is_plain() {
delta.ops.pop();

View File

@ -1,11 +1,11 @@
use crate::core::extensions::DeleteExt;
use lib_ot::core::{Delta, DeltaBuilder, Interval};
use lib_ot::core::{DeltaBuilder, Interval, RichTextDelta};
pub struct DefaultDelete {}
impl DeleteExt for DefaultDelete {
fn ext_name(&self) -> &str { "DefaultDelete" }
fn apply(&self, _delta: &Delta, interval: Interval) -> Option<Delta> {
fn apply(&self, _delta: &RichTextDelta, interval: Interval) -> Option<RichTextDelta> {
Some(
DeltaBuilder::new()
.retain(interval.start)

View File

@ -1,11 +1,20 @@
use crate::{core::extensions::DeleteExt, util::is_newline};
use lib_ot::core::{plain_attributes, CharMetric, Delta, DeltaBuilder, DeltaIter, Interval, NEW_LINE};
use lib_ot::core::{
plain_attributes,
Attributes,
CharMetric,
DeltaBuilder,
DeltaIter,
Interval,
RichTextDelta,
NEW_LINE,
};
pub struct PreserveLineFormatOnMerge {}
impl DeleteExt for PreserveLineFormatOnMerge {
fn ext_name(&self) -> &str { "PreserveLineFormatOnMerge" }
fn apply(&self, delta: &Delta, interval: Interval) -> Option<Delta> {
fn apply(&self, delta: &RichTextDelta, interval: Interval) -> Option<RichTextDelta> {
if interval.is_empty() {
return None;
}
@ -40,7 +49,7 @@ impl DeleteExt for PreserveLineFormatOnMerge {
attributes.mark_all_as_removed_except(None);
if newline_op.has_attribute() {
attributes.extend(newline_op.get_attributes());
attributes.extend_other(newline_op.get_attributes());
}
new_delta.retain(line_break, plain_attributes());

View File

@ -1,8 +1,12 @@
use crate::util::find_newline;
use lib_ot::core::{plain_attributes, Attribute, AttributeScope, Delta, Operation};
use lib_ot::core::{plain_attributes, AttributeScope, RichTextAttribute, RichTextDelta, RichTextOperation};
pub(crate) fn line_break(op: &Operation, attribute: &Attribute, scope: AttributeScope) -> Delta {
let mut new_delta = Delta::new();
pub(crate) fn line_break(
op: &RichTextOperation,
attribute: &RichTextAttribute,
scope: AttributeScope,
) -> RichTextDelta {
let mut new_delta = RichTextDelta::new();
let mut start = 0;
let end = op.len();
let mut s = op.get_data();

View File

@ -2,13 +2,21 @@ use crate::{
core::extensions::{format::helper::line_break, FormatExt},
util::find_newline,
};
use lib_ot::core::{plain_attributes, Attribute, AttributeScope, Delta, DeltaBuilder, DeltaIter, Interval};
use lib_ot::core::{
plain_attributes,
AttributeScope,
DeltaBuilder,
DeltaIter,
Interval,
RichTextAttribute,
RichTextDelta,
};
pub struct ResolveBlockFormat {}
impl FormatExt for ResolveBlockFormat {
fn ext_name(&self) -> &str { std::any::type_name::<ResolveBlockFormat>() }
fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option<Delta> {
fn apply(&self, delta: &RichTextDelta, interval: Interval, attribute: &RichTextAttribute) -> Option<RichTextDelta> {
if attribute.scope != AttributeScope::Block {
return None;
}

View File

@ -2,13 +2,13 @@ use crate::{
core::extensions::{format::helper::line_break, FormatExt},
util::find_newline,
};
use lib_ot::core::{Attribute, AttributeScope, Delta, DeltaBuilder, DeltaIter, Interval};
use lib_ot::core::{AttributeScope, DeltaBuilder, DeltaIter, Interval, RichTextAttribute, RichTextDelta};
pub struct ResolveInlineFormat {}
impl FormatExt for ResolveInlineFormat {
fn ext_name(&self) -> &str { std::any::type_name::<ResolveInlineFormat>() }
fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option<Delta> {
fn apply(&self, delta: &RichTextDelta, interval: Interval, attribute: &RichTextAttribute) -> Option<RichTextDelta> {
if attribute.scope != AttributeScope::Inline {
return None;
}

View File

@ -1,12 +1,19 @@
use crate::{core::extensions::InsertExt, util::is_newline};
use lib_ot::core::{attributes_except_header, is_empty_line_at_index, AttributeKey, Delta, DeltaBuilder, DeltaIter};
use lib_ot::core::{
attributes_except_header,
is_empty_line_at_index,
DeltaBuilder,
DeltaIter,
RichTextAttributeKey,
RichTextDelta,
};
pub struct AutoExitBlock {}
impl InsertExt for AutoExitBlock {
fn ext_name(&self) -> &str { std::any::type_name::<AutoExitBlock>() }
fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
fn apply(&self, delta: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option<RichTextDelta> {
// Auto exit block will be triggered by enter two new lines
if !is_newline(text) {
return None;
@ -39,7 +46,7 @@ impl InsertExt for AutoExitBlock {
},
}
attributes.mark_all_as_removed_except(Some(AttributeKey::Header));
attributes.mark_all_as_removed_except(Some(RichTextAttributeKey::Header));
Some(
DeltaBuilder::new()

View File

@ -1,5 +1,13 @@
use crate::{core::extensions::InsertExt, util::is_whitespace};
use lib_ot::core::{count_utf16_code_units, plain_attributes, Attribute, Attributes, Delta, DeltaBuilder, DeltaIter};
use lib_ot::core::{
count_utf16_code_units,
plain_attributes,
DeltaBuilder,
DeltaIter,
RichTextAttribute,
RichTextAttributes,
RichTextDelta,
};
use std::cmp::min;
use url::Url;
@ -7,7 +15,7 @@ pub struct AutoFormatExt {}
impl InsertExt for AutoFormatExt {
fn ext_name(&self) -> &str { std::any::type_name::<AutoFormatExt>() }
fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
fn apply(&self, delta: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option<RichTextDelta> {
// enter whitespace to trigger auto format
if !is_whitespace(text) {
return None;
@ -55,9 +63,9 @@ pub enum AutoFormatter {
}
impl AutoFormatter {
pub fn to_attributes(&self) -> Attributes {
pub fn to_attributes(&self) -> RichTextAttributes {
match self {
AutoFormatter::Url(url) => Attribute::Link(url.as_str()).into(),
AutoFormatter::Url(url) => RichTextAttribute::Link(url.as_str()).into(),
}
}

View File

@ -1,13 +1,21 @@
use crate::core::extensions::InsertExt;
use lib_ot::core::{AttributeKey, Attributes, Delta, DeltaBuilder, DeltaIter, NEW_LINE};
use lib_ot::core::{
Attributes,
DeltaBuilder,
DeltaIter,
RichTextAttributeKey,
RichTextAttributes,
RichTextDelta,
NEW_LINE,
};
pub struct DefaultInsertAttribute {}
impl InsertExt for DefaultInsertAttribute {
fn ext_name(&self) -> &str { std::any::type_name::<DefaultInsertAttribute>() }
fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
fn apply(&self, delta: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option<RichTextDelta> {
let iter = DeltaIter::new(delta);
let mut attributes = Attributes::new();
let mut attributes = RichTextAttributes::new();
// Enable each line split by "\n" remains the block attributes. for example:
// insert "\n" to "123456" at index 3
@ -18,8 +26,8 @@ impl InsertExt for DefaultInsertAttribute {
match iter.last() {
None => {},
Some(op) => {
if op.get_attributes().contains_key(&AttributeKey::Header) {
attributes.extend(op.get_attributes());
if op.get_attributes().contains_key(&RichTextAttributeKey::Header) {
attributes.extend_other(op.get_attributes());
}
},
}

View File

@ -2,7 +2,7 @@ use crate::core::extensions::InsertExt;
pub use auto_exit_block::*;
pub use auto_format::*;
pub use default_insert::*;
use lib_ot::core::Delta;
use lib_ot::core::RichTextDelta;
pub use preserve_block_format::*;
pub use preserve_inline_format::*;
pub use reset_format_on_new_line::*;
@ -18,12 +18,16 @@ pub struct InsertEmbedsExt {}
impl InsertExt for InsertEmbedsExt {
fn ext_name(&self) -> &str { "InsertEmbedsExt" }
fn apply(&self, _delta: &Delta, _replace_len: usize, _text: &str, _index: usize) -> Option<Delta> { None }
fn apply(&self, _delta: &RichTextDelta, _replace_len: usize, _text: &str, _index: usize) -> Option<RichTextDelta> {
None
}
}
pub struct ForceNewlineForInsertsAroundEmbedExt {}
impl InsertExt for ForceNewlineForInsertsAroundEmbedExt {
fn ext_name(&self) -> &str { "ForceNewlineForInsertsAroundEmbedExt" }
fn apply(&self, _delta: &Delta, _replace_len: usize, _text: &str, _index: usize) -> Option<Delta> { None }
fn apply(&self, _delta: &RichTextDelta, _replace_len: usize, _text: &str, _index: usize) -> Option<RichTextDelta> {
None
}
}

View File

@ -2,12 +2,12 @@ use crate::{core::extensions::InsertExt, util::is_newline};
use lib_ot::core::{
attributes_except_header,
plain_attributes,
Attribute,
AttributeKey,
Attributes,
Delta,
DeltaBuilder,
DeltaIter,
RichTextAttribute,
RichTextAttributeKey,
RichTextAttributes,
RichTextDelta,
NEW_LINE,
};
@ -15,7 +15,7 @@ pub struct PreserveBlockFormatOnInsert {}
impl InsertExt for PreserveBlockFormatOnInsert {
fn ext_name(&self) -> &str { std::any::type_name::<PreserveBlockFormatOnInsert>() }
fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
fn apply(&self, delta: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option<RichTextDelta> {
if !is_newline(text) {
return None;
}
@ -30,9 +30,9 @@ impl InsertExt for PreserveBlockFormatOnInsert {
return None;
}
let mut reset_attribute = Attributes::new();
if newline_attributes.contains_key(&AttributeKey::Header) {
reset_attribute.add(Attribute::Header(1));
let mut reset_attribute = RichTextAttributes::new();
if newline_attributes.contains_key(&RichTextAttributeKey::Header) {
reset_attribute.add(RichTextAttribute::Header(1));
}
let lines: Vec<_> = text.split(NEW_LINE).collect();

View File

@ -2,13 +2,21 @@ use crate::{
core::extensions::InsertExt,
util::{contain_newline, is_newline},
};
use lib_ot::core::{plain_attributes, AttributeKey, Delta, DeltaBuilder, DeltaIter, OpNewline, NEW_LINE};
use lib_ot::core::{
plain_attributes,
DeltaBuilder,
DeltaIter,
OpNewline,
RichTextAttributeKey,
RichTextDelta,
NEW_LINE,
};
pub struct PreserveInlineFormat {}
impl InsertExt for PreserveInlineFormat {
fn ext_name(&self) -> &str { std::any::type_name::<PreserveInlineFormat>() }
fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
fn apply(&self, delta: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option<RichTextDelta> {
if contain_newline(text) {
return None;
}
@ -20,7 +28,7 @@ impl InsertExt for PreserveInlineFormat {
}
let mut attributes = prev.get_attributes();
if attributes.is_empty() || !attributes.contains_key(&AttributeKey::Link) {
if attributes.is_empty() || !attributes.contains_key(&RichTextAttributeKey::Link) {
return Some(
DeltaBuilder::new()
.retain(index + replace_len)
@ -52,7 +60,7 @@ pub struct PreserveLineFormatOnSplit {}
impl InsertExt for PreserveLineFormatOnSplit {
fn ext_name(&self) -> &str { std::any::type_name::<PreserveLineFormatOnSplit>() }
fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
fn apply(&self, delta: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option<RichTextDelta> {
if !is_newline(text) {
return None;
}
@ -69,7 +77,7 @@ impl InsertExt for PreserveLineFormatOnSplit {
return None;
}
let mut new_delta = Delta::new();
let mut new_delta = RichTextDelta::new();
new_delta.retain(index + replace_len, plain_attributes());
if newline_status.is_contain() {

View File

@ -1,11 +1,19 @@
use crate::{core::extensions::InsertExt, util::is_newline};
use lib_ot::core::{AttributeKey, Attributes, CharMetric, Delta, DeltaBuilder, DeltaIter, NEW_LINE};
use lib_ot::core::{
CharMetric,
DeltaBuilder,
DeltaIter,
RichTextAttributeKey,
RichTextAttributes,
RichTextDelta,
NEW_LINE,
};
pub struct ResetLineFormatOnNewLine {}
impl InsertExt for ResetLineFormatOnNewLine {
fn ext_name(&self) -> &str { std::any::type_name::<ResetLineFormatOnNewLine>() }
fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
fn apply(&self, delta: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option<RichTextDelta> {
if !is_newline(text) {
return None;
}
@ -17,9 +25,9 @@ impl InsertExt for ResetLineFormatOnNewLine {
return None;
}
let mut reset_attribute = Attributes::new();
if next_op.get_attributes().contains_key(&AttributeKey::Header) {
reset_attribute.delete(&AttributeKey::Header);
let mut reset_attribute = RichTextAttributes::new();
if next_op.get_attributes().contains_key(&RichTextAttributeKey::Header) {
reset_attribute.delete(&RichTextAttributeKey::Header);
}
let len = index + replace_len;

View File

@ -2,7 +2,7 @@ pub use delete::*;
pub use format::*;
pub use insert::*;
use lib_ot::core::{Attribute, Delta, Interval};
use lib_ot::core::{Interval, RichTextAttribute, RichTextDelta};
mod delete;
mod format;
@ -14,15 +14,15 @@ pub type DeleteExtension = Box<dyn DeleteExt + Send + Sync>;
pub trait InsertExt {
fn ext_name(&self) -> &str;
fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta>;
fn apply(&self, delta: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option<RichTextDelta>;
}
pub trait FormatExt {
fn ext_name(&self) -> &str;
fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option<Delta>;
fn apply(&self, delta: &RichTextDelta, interval: Interval, attribute: &RichTextAttribute) -> Option<RichTextDelta>;
}
pub trait DeleteExt {
fn ext_name(&self) -> &str;
fn apply(&self, delta: &Delta, interval: Interval) -> Option<Delta>;
fn apply(&self, delta: &RichTextDelta, interval: Interval) -> Option<RichTextDelta>;
}

View File

@ -1,4 +1,4 @@
use lib_ot::core::Delta;
use lib_ot::core::RichTextDelta;
const MAX_UNDOS: usize = 20;
@ -21,8 +21,8 @@ impl UndoResult {
pub struct History {
#[allow(dead_code)]
cur_undo: usize,
undos: Vec<Delta>,
redoes: Vec<Delta>,
undos: Vec<RichTextDelta>,
redoes: Vec<RichTextDelta>,
capacity: usize,
}
@ -44,11 +44,11 @@ impl History {
pub fn can_redo(&self) -> bool { !self.redoes.is_empty() }
pub fn add_undo(&mut self, delta: Delta) { self.undos.push(delta); }
pub fn add_undo(&mut self, delta: RichTextDelta) { self.undos.push(delta); }
pub fn add_redo(&mut self, delta: Delta) { self.redoes.push(delta); }
pub fn add_redo(&mut self, delta: RichTextDelta) { self.redoes.push(delta); }
pub fn record(&mut self, delta: Delta) {
pub fn record(&mut self, delta: RichTextDelta) {
if delta.ops.is_empty() {
return;
}
@ -61,7 +61,7 @@ impl History {
}
}
pub fn undo(&mut self) -> Option<Delta> {
pub fn undo(&mut self) -> Option<RichTextDelta> {
if !self.can_undo() {
return None;
}
@ -69,7 +69,7 @@ impl History {
Some(delta)
}
pub fn redo(&mut self) -> Option<Delta> {
pub fn redo(&mut self) -> Option<RichTextDelta> {
if !self.can_redo() {
return None;
}

View File

@ -1,6 +1,6 @@
use crate::core::extensions::*;
use lib_ot::{
core::{trim, Attribute, Delta, Interval},
core::{trim, Interval, RichTextAttribute, RichTextDelta},
errors::{ErrorBuilder, OTError, OTErrorCode},
};
@ -21,7 +21,12 @@ impl View {
}
}
pub(crate) fn insert(&self, delta: &Delta, text: &str, interval: Interval) -> Result<Delta, OTError> {
pub(crate) fn insert(
&self,
delta: &RichTextDelta,
text: &str,
interval: Interval,
) -> Result<RichTextDelta, OTError> {
let mut new_delta = None;
for ext in &self.insert_exts {
if let Some(mut delta) = ext.apply(delta, interval.size(), text, interval.start) {
@ -38,7 +43,7 @@ impl View {
}
}
pub(crate) fn delete(&self, delta: &Delta, interval: Interval) -> Result<Delta, OTError> {
pub(crate) fn delete(&self, delta: &RichTextDelta, interval: Interval) -> Result<RichTextDelta, OTError> {
let mut new_delta = None;
for ext in &self.delete_exts {
if let Some(mut delta) = ext.apply(delta, interval) {
@ -55,7 +60,12 @@ impl View {
}
}
pub(crate) fn format(&self, delta: &Delta, attribute: Attribute, interval: Interval) -> Result<Delta, OTError> {
pub(crate) fn format(
&self,
delta: &RichTextDelta,
attribute: RichTextAttribute,
interval: Interval,
) -> Result<RichTextDelta, OTError> {
let mut new_delta = None;
for ext in &self.format_exts {
if let Some(mut delta) = ext.apply(delta, interval, &attribute) {

View File

@ -1,5 +1,5 @@
use flowy_derive::ProtoBuf;
use lib_ot::{core::Delta, errors::OTError};
use lib_ot::{core::RichTextDelta, errors::OTError};
#[derive(ProtoBuf, Default, Debug, Clone)]
pub struct CreateDocParams {
@ -35,8 +35,8 @@ pub struct Doc {
}
impl Doc {
pub fn delta(&self) -> Result<Delta, OTError> {
let delta = Delta::from_bytes(&self.data)?;
pub fn delta(&self) -> Result<RichTextDelta, OTError> {
let delta = RichTextDelta::from_bytes(&self.data)?;
Ok(delta)
}
}
@ -59,7 +59,7 @@ pub struct DocDelta {
pub doc_id: String,
#[pb(index = 2)]
pub data: String, // Delta
pub data: String, // RichTextDelta
}
#[derive(ProtoBuf, Default, Debug, Clone)]

View File

@ -1,6 +1,6 @@
use crate::{entities::doc::Doc, util::md5};
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use lib_ot::core::Delta;
use lib_ot::core::RichTextDelta;
use std::{fmt::Formatter, ops::RangeInclusive};
#[derive(Debug, ProtoBuf_Enum, Clone, Eq, PartialEq)]
@ -87,7 +87,7 @@ impl std::fmt::Debug for Revision {
let _ = f.write_fmt(format_args!("doc_id {}, ", self.doc_id))?;
let _ = f.write_fmt(format_args!("base_rev_id {}, ", self.base_rev_id))?;
let _ = f.write_fmt(format_args!("rev_id {}, ", self.rev_id))?;
match Delta::from_bytes(&self.delta_data) {
match RichTextDelta::from_bytes(&self.delta_data) {
Ok(delta) => {
let _ = f.write_fmt(format_args!("delta {:?}", delta.to_json()))?;
},

View File

@ -1,15 +1,15 @@
use lib_ot::core::{Delta, DeltaBuilder};
use lib_ot::core::{DeltaBuilder, RichTextDelta};
#[inline]
pub fn doc_initial_delta() -> Delta { DeltaBuilder::new().insert("\n").build() }
pub fn doc_initial_delta() -> RichTextDelta { DeltaBuilder::new().insert("\n").build() }
#[inline]
pub fn doc_initial_string() -> String { doc_initial_delta().to_json() }
#[inline]
pub fn initial_read_me() -> Delta {
pub fn initial_read_me() -> RichTextDelta {
let json = include_str!("READ_ME.json");
Delta::from_json(json).unwrap()
RichTextDelta::from_json(json).unwrap()
}
#[cfg(test)]

View File

@ -1,19 +1,19 @@
#![allow(non_snake_case)]
use crate::{block_attribute, core::Attributes, ignore_attribute, inline_attribute, list_attribute};
use crate::{block_attribute, core::RichTextAttributes, ignore_attribute, inline_attribute, list_attribute};
use lazy_static::lazy_static;
use std::{collections::HashSet, fmt, fmt::Formatter, iter::FromIterator};
use strum_macros::Display;
#[derive(Debug, Clone)]
pub struct Attribute {
pub key: AttributeKey,
pub value: AttributeValue,
pub struct RichTextAttribute {
pub key: RichTextAttributeKey,
pub value: RichTextAttributeValue,
pub scope: AttributeScope,
}
impl Attribute {
impl RichTextAttribute {
// inline
inline_attribute!(Bold, bool);
inline_attribute!(Italic, bool);
@ -55,16 +55,16 @@ impl Attribute {
}
}
impl fmt::Display for Attribute {
impl fmt::Display for RichTextAttribute {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let s = format!("{:?}:{:?} {:?}", self.key, self.value.0, self.scope);
f.write_str(&s)
}
}
impl std::convert::From<Attribute> for Attributes {
fn from(attr: Attribute) -> Self {
let mut attributes = Attributes::new();
impl std::convert::From<RichTextAttribute> for RichTextAttributes {
fn from(attr: RichTextAttribute) -> Self {
let mut attributes = RichTextAttributes::new();
attributes.add(attr);
attributes
}
@ -73,7 +73,7 @@ impl std::convert::From<Attribute> for Attributes {
#[derive(Clone, Debug, Display, Hash, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
// serde.rs/variant-attrs.html
// #[serde(rename_all = "snake_case")]
pub enum AttributeKey {
pub enum RichTextAttributeKey {
#[serde(rename = "bold")]
Bold,
#[serde(rename = "italic")]
@ -114,80 +114,80 @@ pub enum AttributeKey {
// pub trait AttributeValueData<'a>: Serialize + Deserialize<'a> {}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct AttributeValue(pub Option<String>);
pub struct RichTextAttributeValue(pub Option<String>);
impl std::convert::From<&usize> for AttributeValue {
fn from(val: &usize) -> Self { AttributeValue::from(*val) }
impl std::convert::From<&usize> for RichTextAttributeValue {
fn from(val: &usize) -> Self { RichTextAttributeValue::from(*val) }
}
impl std::convert::From<usize> for AttributeValue {
impl std::convert::From<usize> for RichTextAttributeValue {
fn from(val: usize) -> Self {
if val > 0_usize {
AttributeValue(Some(format!("{}", val)))
RichTextAttributeValue(Some(format!("{}", val)))
} else {
AttributeValue(None)
RichTextAttributeValue(None)
}
}
}
impl std::convert::From<&str> for AttributeValue {
impl std::convert::From<&str> for RichTextAttributeValue {
fn from(val: &str) -> Self { val.to_owned().into() }
}
impl std::convert::From<String> for AttributeValue {
impl std::convert::From<String> for RichTextAttributeValue {
fn from(val: String) -> Self {
if val.is_empty() {
AttributeValue(None)
RichTextAttributeValue(None)
} else {
AttributeValue(Some(val))
RichTextAttributeValue(Some(val))
}
}
}
impl std::convert::From<&bool> for AttributeValue {
fn from(val: &bool) -> Self { AttributeValue::from(*val) }
impl std::convert::From<&bool> for RichTextAttributeValue {
fn from(val: &bool) -> Self { RichTextAttributeValue::from(*val) }
}
impl std::convert::From<bool> for AttributeValue {
impl std::convert::From<bool> for RichTextAttributeValue {
fn from(val: bool) -> Self {
let val = match val {
true => Some("true".to_owned()),
false => None,
};
AttributeValue(val)
RichTextAttributeValue(val)
}
}
pub fn is_block_except_header(k: &AttributeKey) -> bool {
if k == &AttributeKey::Header {
pub fn is_block_except_header(k: &RichTextAttributeKey) -> bool {
if k == &RichTextAttributeKey::Header {
return false;
}
BLOCK_KEYS.contains(k)
}
lazy_static! {
static ref BLOCK_KEYS: HashSet<AttributeKey> = HashSet::from_iter(vec![
AttributeKey::Header,
AttributeKey::Indent,
AttributeKey::Align,
AttributeKey::CodeBlock,
AttributeKey::List,
AttributeKey::BlockQuote,
static ref BLOCK_KEYS: HashSet<RichTextAttributeKey> = HashSet::from_iter(vec![
RichTextAttributeKey::Header,
RichTextAttributeKey::Indent,
RichTextAttributeKey::Align,
RichTextAttributeKey::CodeBlock,
RichTextAttributeKey::List,
RichTextAttributeKey::BlockQuote,
]);
static ref INLINE_KEYS: HashSet<AttributeKey> = HashSet::from_iter(vec![
AttributeKey::Bold,
AttributeKey::Italic,
AttributeKey::Underline,
AttributeKey::StrikeThrough,
AttributeKey::Link,
AttributeKey::Color,
AttributeKey::Font,
AttributeKey::Size,
AttributeKey::Background,
AttributeKey::InlineCode,
static ref INLINE_KEYS: HashSet<RichTextAttributeKey> = HashSet::from_iter(vec![
RichTextAttributeKey::Bold,
RichTextAttributeKey::Italic,
RichTextAttributeKey::Underline,
RichTextAttributeKey::StrikeThrough,
RichTextAttributeKey::Link,
RichTextAttributeKey::Color,
RichTextAttributeKey::Font,
RichTextAttributeKey::Size,
RichTextAttributeKey::Background,
RichTextAttributeKey::InlineCode,
]);
static ref INGORE_KEYS: HashSet<AttributeKey> =
HashSet::from_iter(vec![AttributeKey::Width, AttributeKey::Height,]);
static ref INGORE_KEYS: HashSet<RichTextAttributeKey> =
HashSet::from_iter(vec![RichTextAttributeKey::Width, RichTextAttributeKey::Height,]);
}
#[derive(Debug, PartialEq, Eq, Clone)]

View File

@ -1,15 +1,22 @@
use crate::{
core::{Attribute, AttributeKey, AttributeValue, Operation, OperationTransformable},
core::{
Attributes,
OperationTransformable,
RichTextAttribute,
RichTextAttributeKey,
RichTextAttributeValue,
RichTextOperation,
},
errors::OTError,
};
use std::{collections::HashMap, fmt};
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Attributes {
pub(crate) inner: HashMap<AttributeKey, AttributeValue>,
pub struct RichTextAttributes {
pub(crate) inner: HashMap<RichTextAttributeKey, RichTextAttributeValue>,
}
impl std::default::Default for Attributes {
impl std::default::Default for RichTextAttributes {
fn default() -> Self {
Self {
inner: HashMap::with_capacity(0),
@ -17,27 +24,31 @@ impl std::default::Default for Attributes {
}
}
impl fmt::Display for Attributes {
impl fmt::Display for RichTextAttributes {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_fmt(format_args!("{:?}", self.inner)) }
}
pub fn plain_attributes() -> Attributes { Attributes::default() }
pub fn plain_attributes() -> RichTextAttributes { RichTextAttributes::default() }
impl Attributes {
pub fn new() -> Self { Attributes { inner: HashMap::new() } }
impl RichTextAttributes {
pub fn new() -> Self { RichTextAttributes { inner: HashMap::new() } }
pub fn is_empty(&self) -> bool { self.inner.is_empty() }
pub fn add(&mut self, attribute: Attribute) {
let Attribute { key, value, scope: _ } = attribute;
pub fn add(&mut self, attribute: RichTextAttribute) {
let RichTextAttribute { key, value, scope: _ } = attribute;
self.inner.insert(key, value);
}
pub fn add_kv(&mut self, key: AttributeKey, value: AttributeValue) { self.inner.insert(key, value); }
pub fn add_kv(&mut self, key: RichTextAttributeKey, value: RichTextAttributeValue) {
self.inner.insert(key, value);
}
pub fn delete(&mut self, key: &AttributeKey) { self.inner.insert(key.clone(), AttributeValue(None)); }
pub fn delete(&mut self, key: &RichTextAttributeKey) {
self.inner.insert(key.clone(), RichTextAttributeValue(None));
}
pub fn mark_all_as_removed_except(&mut self, attribute: Option<AttributeKey>) {
pub fn mark_all_as_removed_except(&mut self, attribute: Option<RichTextAttributeKey>) {
match attribute {
None => {
self.inner.iter_mut().for_each(|(_k, v)| v.0 = None);
@ -52,7 +63,7 @@ impl Attributes {
}
}
pub fn remove(&mut self, key: AttributeKey) { self.inner.retain(|k, _| k != &key); }
pub fn remove(&mut self, key: RichTextAttributeKey) { self.inner.retain(|k, _| k != &key); }
// pub fn block_attributes_except_header(attributes: &Attributes) -> Attributes
// { let mut new_attributes = Attributes::new();
@ -65,14 +76,9 @@ impl Attributes {
// new_attributes
// }
// Remove the empty attribute which value is None.
pub fn remove_empty(&mut self) { self.inner.retain(|_, v| v.0.is_some()); }
pub fn extend(&mut self, other: Attributes) { self.inner.extend(other.inner); }
// Update inner by constructing new attributes from the other if it's
// not None and replace the key/value with self key/value.
pub fn merge(&mut self, other: Option<Attributes>) {
pub fn merge(&mut self, other: Option<RichTextAttributes>) {
if other.is_none() {
return;
}
@ -85,13 +91,21 @@ impl Attributes {
}
}
impl OperationTransformable for Attributes {
impl Attributes for RichTextAttributes {
fn is_empty(&self) -> bool { self.inner.is_empty() }
fn remove_empty(&mut self) { self.inner.retain(|_, v| v.0.is_some()); }
fn extend_other(&mut self, other: Self) { self.inner.extend(other.inner); }
}
impl OperationTransformable for RichTextAttributes {
fn compose(&self, other: &Self) -> Result<Self, OTError>
where
Self: Sized,
{
let mut attributes = self.clone();
attributes.extend(other.clone());
attributes.extend_other(other.clone());
Ok(attributes)
}
@ -99,25 +113,29 @@ impl OperationTransformable for Attributes {
where
Self: Sized,
{
let a = self.iter().fold(Attributes::new(), |mut new_attributes, (k, v)| {
if !other.contains_key(k) {
new_attributes.insert(k.clone(), v.clone());
}
new_attributes
});
let a = self
.iter()
.fold(RichTextAttributes::new(), |mut new_attributes, (k, v)| {
if !other.contains_key(k) {
new_attributes.insert(k.clone(), v.clone());
}
new_attributes
});
let b = other.iter().fold(Attributes::new(), |mut new_attributes, (k, v)| {
if !self.contains_key(k) {
new_attributes.insert(k.clone(), v.clone());
}
new_attributes
});
let b = other
.iter()
.fold(RichTextAttributes::new(), |mut new_attributes, (k, v)| {
if !self.contains_key(k) {
new_attributes.insert(k.clone(), v.clone());
}
new_attributes
});
Ok((a, b))
}
fn invert(&self, other: &Self) -> Self {
let base_inverted = other.iter().fold(Attributes::new(), |mut attributes, (k, v)| {
let base_inverted = other.iter().fold(RichTextAttributes::new(), |mut attributes, (k, v)| {
if other.get(k) != self.get(k) && self.contains_key(k) {
attributes.insert(k.clone(), v.clone());
}
@ -135,18 +153,18 @@ impl OperationTransformable for Attributes {
}
}
impl std::ops::Deref for Attributes {
type Target = HashMap<AttributeKey, AttributeValue>;
impl std::ops::Deref for RichTextAttributes {
type Target = HashMap<RichTextAttributeKey, RichTextAttributeValue>;
fn deref(&self) -> &Self::Target { &self.inner }
}
impl std::ops::DerefMut for Attributes {
impl std::ops::DerefMut for RichTextAttributes {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner }
}
pub fn attributes_except_header(op: &Operation) -> Attributes {
pub fn attributes_except_header(op: &RichTextOperation) -> RichTextAttributes {
let mut attributes = op.get_attributes();
attributes.remove(AttributeKey::Header);
attributes.remove(RichTextAttributeKey::Header);
attributes
}

View File

@ -1,6 +1,6 @@
#[rustfmt::skip]
use crate::core::AttributeValue;
use crate::core::{Attribute, AttributeKey, Attributes};
use crate::core::RichTextAttributeValue;
use crate::core::{RichTextAttribute, RichTextAttributeKey, RichTextAttributes};
use serde::{
de,
de::{MapAccess, Visitor},
@ -12,7 +12,7 @@ use serde::{
};
use std::fmt;
impl Serialize for Attribute {
impl Serialize for RichTextAttribute {
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where
S: Serializer,
@ -23,7 +23,7 @@ impl Serialize for Attribute {
}
}
impl Serialize for Attributes {
impl Serialize for RichTextAttributes {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
@ -40,39 +40,43 @@ impl Serialize for Attributes {
}
}
fn serial_attribute<S, E>(map_serializer: &mut S, key: &AttributeKey, value: &AttributeValue) -> Result<(), E>
fn serial_attribute<S, E>(
map_serializer: &mut S,
key: &RichTextAttributeKey,
value: &RichTextAttributeValue,
) -> Result<(), E>
where
S: SerializeMap,
E: From<<S as SerializeMap>::Error>,
{
if let Some(v) = &value.0 {
match key {
AttributeKey::Bold
| AttributeKey::Italic
| AttributeKey::Underline
| AttributeKey::StrikeThrough
| AttributeKey::CodeBlock
| AttributeKey::InlineCode
| AttributeKey::BlockQuote => match &v.parse::<bool>() {
RichTextAttributeKey::Bold
| RichTextAttributeKey::Italic
| RichTextAttributeKey::Underline
| RichTextAttributeKey::StrikeThrough
| RichTextAttributeKey::CodeBlock
| RichTextAttributeKey::InlineCode
| RichTextAttributeKey::BlockQuote => match &v.parse::<bool>() {
Ok(value) => map_serializer.serialize_entry(&key, value)?,
Err(e) => log::error!("Serial {:?} failed. {:?}", &key, e),
},
AttributeKey::Font
| AttributeKey::Size
| AttributeKey::Header
| AttributeKey::Indent
| AttributeKey::Width
| AttributeKey::Height => match &v.parse::<i32>() {
RichTextAttributeKey::Font
| RichTextAttributeKey::Size
| RichTextAttributeKey::Header
| RichTextAttributeKey::Indent
| RichTextAttributeKey::Width
| RichTextAttributeKey::Height => match &v.parse::<i32>() {
Ok(value) => map_serializer.serialize_entry(&key, value)?,
Err(e) => log::error!("Serial {:?} failed. {:?}", &key, e),
},
AttributeKey::Link
| AttributeKey::Color
| AttributeKey::Background
| AttributeKey::Align
| AttributeKey::List => {
RichTextAttributeKey::Link
| RichTextAttributeKey::Color
| RichTextAttributeKey::Background
| RichTextAttributeKey::Align
| RichTextAttributeKey::List => {
map_serializer.serialize_entry(&key, v)?;
},
}
@ -82,23 +86,23 @@ where
Ok(())
}
impl<'de> Deserialize<'de> for Attributes {
fn deserialize<D>(deserializer: D) -> Result<Attributes, D::Error>
impl<'de> Deserialize<'de> for RichTextAttributes {
fn deserialize<D>(deserializer: D) -> Result<RichTextAttributes, D::Error>
where
D: Deserializer<'de>,
{
struct AttributesVisitor;
impl<'de> Visitor<'de> for AttributesVisitor {
type Value = Attributes;
type Value = RichTextAttributes;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("Expect map") }
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'de>,
{
let mut attributes = Attributes::new();
while let Some(key) = map.next_key::<AttributeKey>()? {
let value = map.next_value::<AttributeValue>()?;
let mut attributes = RichTextAttributes::new();
while let Some(key) = map.next_key::<RichTextAttributeKey>()? {
let value = map.next_value::<RichTextAttributeValue>()?;
attributes.add_kv(key, value);
}
@ -109,7 +113,7 @@ impl<'de> Deserialize<'de> for Attributes {
}
}
impl Serialize for AttributeValue {
impl Serialize for RichTextAttributeValue {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
@ -121,14 +125,14 @@ impl Serialize for AttributeValue {
}
}
impl<'de> Deserialize<'de> for AttributeValue {
fn deserialize<D>(deserializer: D) -> Result<AttributeValue, D::Error>
impl<'de> Deserialize<'de> for RichTextAttributeValue {
fn deserialize<D>(deserializer: D) -> Result<RichTextAttributeValue, D::Error>
where
D: Deserializer<'de>,
{
struct AttributeValueVisitor;
impl<'de> Visitor<'de> for AttributeValueVisitor {
type Value = AttributeValue;
type Value = RichTextAttributeValue;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("bool, usize or string")
}
@ -143,56 +147,56 @@ impl<'de> Deserialize<'de> for AttributeValue {
where
E: de::Error,
{
Ok(AttributeValue(Some(format!("{}", value))))
Ok(RichTextAttributeValue(Some(format!("{}", value))))
}
fn visit_i16<E>(self, value: i16) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(AttributeValue(Some(format!("{}", value))))
Ok(RichTextAttributeValue(Some(format!("{}", value))))
}
fn visit_i32<E>(self, value: i32) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(AttributeValue(Some(format!("{}", value))))
Ok(RichTextAttributeValue(Some(format!("{}", value))))
}
fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(AttributeValue(Some(format!("{}", value))))
Ok(RichTextAttributeValue(Some(format!("{}", value))))
}
fn visit_u8<E>(self, value: u8) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(AttributeValue(Some(format!("{}", value))))
Ok(RichTextAttributeValue(Some(format!("{}", value))))
}
fn visit_u16<E>(self, value: u16) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(AttributeValue(Some(format!("{}", value))))
Ok(RichTextAttributeValue(Some(format!("{}", value))))
}
fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(AttributeValue(Some(format!("{}", value))))
Ok(RichTextAttributeValue(Some(format!("{}", value))))
}
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(AttributeValue(Some(format!("{}", value))))
Ok(RichTextAttributeValue(Some(format!("{}", value))))
}
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
@ -206,7 +210,7 @@ impl<'de> Deserialize<'de> for AttributeValue {
where
E: de::Error,
{
Ok(AttributeValue(None))
Ok(RichTextAttributeValue(None))
}
fn visit_unit<E>(self) -> Result<Self::Value, E>
@ -214,7 +218,7 @@ impl<'de> Deserialize<'de> for AttributeValue {
E: de::Error,
{
// the value that contains null will be processed here.
Ok(AttributeValue(None))
Ok(RichTextAttributeValue(None))
}
fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
@ -223,7 +227,7 @@ impl<'de> Deserialize<'de> for AttributeValue {
{
// https://github.com/serde-rs/json/issues/505
let mut map = map;
let value = map.next_value::<AttributeValue>()?;
let value = map.next_value::<RichTextAttributeValue>()?;
Ok(value)
}
}

View File

@ -1,13 +1,13 @@
#![allow(non_snake_case)]
use crate::core::{Attribute, Attributes};
use crate::core::{RichTextAttribute, RichTextAttributes};
pub struct AttributeBuilder {
inner: Attributes,
inner: RichTextAttributes,
}
impl std::default::Default for AttributeBuilder {
fn default() -> Self {
Self {
inner: Attributes::default(),
inner: RichTextAttributes::default(),
}
}
}
@ -15,10 +15,10 @@ impl std::default::Default for AttributeBuilder {
impl AttributeBuilder {
pub fn new() -> Self { AttributeBuilder::default() }
pub fn add_attr(mut self, attribute: Attribute) -> Self {
pub fn add_attr(mut self, attribute: RichTextAttribute) -> Self {
self.inner.add(attribute);
self
}
pub fn build(self) -> Attributes { self.inner }
pub fn build(self) -> RichTextAttributes { self.inner }
}

View File

@ -6,7 +6,7 @@ macro_rules! inline_attribute {
) => {
pub fn $key(value: $value) -> Self {
Self {
key: AttributeKey::$key,
key: RichTextAttributeKey::$key,
value: value.into(),
scope: AttributeScope::Inline,
}
@ -22,7 +22,7 @@ macro_rules! block_attribute {
) => {
pub fn $key(value: $value) -> Self {
Self {
key: AttributeKey::$key,
key: RichTextAttributeKey::$key,
value: value.into(),
scope: AttributeScope::Block,
}
@ -41,7 +41,7 @@ macro_rules! list_attribute {
true => $value,
false => "",
};
Attribute::List(value)
RichTextAttribute::List(value)
}
};
}
@ -54,7 +54,7 @@ macro_rules! ignore_attribute {
) => {
pub fn $key(value: $value) -> Self {
Self {
key: AttributeKey::$key,
key: RichTextAttributeKey::$key,
value: value.into(),
scope: AttributeScope::Ignore,
}

View File

@ -1,23 +1,29 @@
use crate::core::{plain_attributes, Attributes, Delta, Operation};
use crate::core::{Attributes, Delta, Operation};
pub struct DeltaBuilder {
delta: Delta,
pub struct DeltaBuilder<T: Attributes> {
delta: Delta<T>,
}
impl std::default::Default for DeltaBuilder {
impl<T> std::default::Default for DeltaBuilder<T>
where
T: Attributes,
{
fn default() -> Self { Self { delta: Delta::new() } }
}
impl DeltaBuilder {
impl<T> DeltaBuilder<T>
where
T: Attributes,
{
pub fn new() -> Self { DeltaBuilder::default() }
pub fn retain_with_attributes(mut self, n: usize, attrs: Attributes) -> Self {
pub fn retain_with_attributes(mut self, n: usize, attrs: T) -> Self {
self.delta.retain(n, attrs);
self
}
pub fn retain(mut self, n: usize) -> Self {
self.delta.retain(n, plain_attributes());
self.delta.retain(n, T::default());
self
}
@ -26,13 +32,13 @@ impl DeltaBuilder {
self
}
pub fn insert_with_attributes(mut self, s: &str, attrs: Attributes) -> Self {
pub fn insert_with_attributes(mut self, s: &str, attrs: T) -> Self {
self.delta.insert(s, attrs);
self
}
pub fn insert(mut self, s: &str) -> Self {
self.delta.insert(s, plain_attributes());
self.delta.insert(s, T::default());
self
}
@ -41,10 +47,10 @@ impl DeltaBuilder {
self
}
pub fn build(self) -> Delta { self.delta }
pub fn build(self) -> Delta<T> { self.delta }
}
pub fn trim(delta: &mut Delta) {
pub fn trim<T: Attributes>(delta: &mut Delta<T>) {
let remove_last = match delta.ops.last() {
None => false,
Some(op) => match op {

View File

@ -1,22 +1,25 @@
use crate::{
core::{Delta, Interval, Operation},
core::{Attributes, Delta, Interval, Operation},
errors::{ErrorBuilder, OTError, OTErrorCode},
};
use std::{cmp::min, iter::Enumerate, slice::Iter};
#[derive(Debug)]
pub struct OpCursor<'a> {
pub(crate) delta: &'a Delta,
pub struct OpCursor<'a, T: Attributes> {
pub(crate) delta: &'a Delta<T>,
pub(crate) origin_iv: Interval,
pub(crate) consume_iv: Interval,
pub(crate) consume_count: usize,
pub(crate) op_index: usize,
iter: Enumerate<Iter<'a, Operation>>,
next_op: Option<Operation>,
iter: Enumerate<Iter<'a, Operation<T>>>,
next_op: Option<Operation<T>>,
}
impl<'a> OpCursor<'a> {
pub fn new(delta: &'a Delta, interval: Interval) -> OpCursor<'a> {
impl<'a, T> OpCursor<'a, T>
where
T: Attributes,
{
pub fn new(delta: &'a Delta<T>, interval: Interval) -> OpCursor<'a, T> {
// debug_assert!(interval.start <= delta.target_len);
let mut cursor = Self {
delta,
@ -34,11 +37,11 @@ impl<'a> OpCursor<'a> {
// get the next operation interval
pub fn next_iv(&self) -> Interval { self.next_iv_before(None).unwrap_or_else(|| Interval::new(0, 0)) }
pub fn next_op(&mut self) -> Option<Operation> { self.next_with_len(None) }
pub fn next_op(&mut self) -> Option<Operation<T>> { self.next_with_len(None) }
// get the last operation before the end.
// checkout the delta_next_op_with_len_cross_op_return_last test for more detail
pub fn next_with_len(&mut self, force_end: Option<usize>) -> Option<Operation> {
pub fn next_with_len(&mut self, force_end: Option<usize>) -> Option<Operation<T>> {
let mut find_op = None;
let holder = self.next_op.clone();
let mut next_op = holder.as_ref();
@ -121,7 +124,7 @@ impl<'a> OpCursor<'a> {
Some(interval)
}
pub fn next_iter_op(&self) -> Option<&Operation> {
pub fn next_iter_op(&self) -> Option<&Operation<T>> {
let mut next_op = self.next_op.as_ref();
if next_op.is_none() {
let mut offset = 0;
@ -137,7 +140,10 @@ impl<'a> OpCursor<'a> {
}
}
fn find_next<'a>(cursor: &mut OpCursor<'a>) -> Option<&'a Operation> {
fn find_next<'a, T>(cursor: &mut OpCursor<'a, T>) -> Option<&'a Operation<T>>
where
T: Attributes,
{
match cursor.iter.next() {
None => None,
Some((o_index, op)) => {
@ -149,13 +155,13 @@ fn find_next<'a>(cursor: &mut OpCursor<'a>) -> Option<&'a Operation> {
type SeekResult = Result<(), OTError>;
pub trait Metric {
fn seek(cursor: &mut OpCursor, index: usize) -> SeekResult;
fn seek<T: Attributes>(cursor: &mut OpCursor<T>, index: usize) -> SeekResult;
}
pub struct OpMetric {}
pub struct OpMetric();
impl Metric for OpMetric {
fn seek(cursor: &mut OpCursor, index: usize) -> SeekResult {
fn seek<T: Attributes>(cursor: &mut OpCursor<T>, index: usize) -> SeekResult {
let _ = check_bound(cursor.op_index, index)?;
let mut seek_cursor = OpCursor::new(cursor.delta, cursor.origin_iv);
let mut offset = 0;
@ -170,10 +176,10 @@ impl Metric for OpMetric {
}
}
pub struct CharMetric {}
pub struct CharMetric();
impl Metric for CharMetric {
fn seek(cursor: &mut OpCursor, index: usize) -> SeekResult {
fn seek<T: Attributes>(cursor: &mut OpCursor<T>, index: usize) -> SeekResult {
if index > 0 {
let _ = check_bound(cursor.consume_count, index)?;
let _ = cursor.next_with_len(Some(index));

View File

@ -3,6 +3,7 @@ use crate::{
errors::{ErrorBuilder, OTError, OTErrorCode},
};
use bytes::Bytes;
use serde::de::DeserializeOwned;
use std::{
cmp::{min, Ordering},
fmt,
@ -13,13 +14,16 @@ use std::{
// Opti: optimize the memory usage with Arc_mut or Cow
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Delta {
pub ops: Vec<Operation>,
pub struct Delta<T: Attributes> {
pub ops: Vec<Operation<T>>,
pub base_len: usize,
pub target_len: usize,
}
impl Default for Delta {
impl<T> Default for Delta<T>
where
T: Attributes,
{
fn default() -> Self {
Self {
ops: Vec::new(),
@ -29,28 +33,10 @@ impl Default for Delta {
}
}
impl FromStr for Delta {
type Err = ();
fn from_str(s: &str) -> Result<Delta, Self::Err> {
let mut delta = Delta::with_capacity(1);
delta.add(Operation::Insert(s.into()));
Ok(delta)
}
}
impl std::convert::TryFrom<Vec<u8>> for Delta {
type Error = OTError;
fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> { Delta::from_bytes(bytes) }
}
impl std::convert::TryFrom<Bytes> for Delta {
type Error = OTError;
fn try_from(bytes: Bytes) -> Result<Self, Self::Error> { Delta::from_bytes(&bytes) }
}
impl fmt::Display for Delta {
impl<T> fmt::Display for Delta<T>
where
T: Attributes,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// f.write_str(&serde_json::to_string(self).unwrap_or("".to_owned()))?;
f.write_str("[ ")?;
@ -62,8 +48,11 @@ impl fmt::Display for Delta {
}
}
impl FromIterator<Operation> for Delta {
fn from_iter<T: IntoIterator<Item = Operation>>(ops: T) -> Self {
impl<T> FromIterator<Operation<T>> for Delta<T>
where
T: Attributes,
{
fn from_iter<I: IntoIterator<Item = Operation<T>>>(ops: I) -> Self {
let mut operations = Delta::default();
for op in ops {
operations.add(op);
@ -72,30 +61,12 @@ impl FromIterator<Operation> for Delta {
}
}
impl Delta {
impl<T> Delta<T>
where
T: Attributes,
{
pub fn new() -> Self { Self::default() }
pub fn from_json(json: &str) -> Result<Self, OTError> {
let delta: Delta = serde_json::from_str(json).map_err(|e| {
tracing::trace!("Deserialize failed: {:?}", e);
tracing::trace!("{:?}", json);
e
})?;
Ok(delta)
}
pub fn to_json(&self) -> String { serde_json::to_string(self).unwrap_or_else(|_| "".to_owned()) }
pub fn from_bytes<T: AsRef<[u8]>>(bytes: T) -> Result<Self, OTError> {
let json = str::from_utf8(bytes.as_ref())?;
Self::from_json(json)
}
pub fn to_bytes(&self) -> Bytes {
let json = self.to_json();
Bytes::from(json.into_bytes())
}
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Self {
@ -105,7 +76,7 @@ impl Delta {
}
}
pub fn add(&mut self, op: Operation) {
pub fn add(&mut self, op: Operation<T>) {
match op {
Operation::Delete(i) => self.delete(i),
Operation::Insert(i) => self.insert(&i.s, i.attributes),
@ -125,7 +96,7 @@ impl Delta {
}
}
pub fn insert(&mut self, s: &str, attributes: Attributes) {
pub fn insert(&mut self, s: &str, attributes: T) {
let s: FlowyStr = s.into();
if s.is_empty() {
return;
@ -133,20 +104,20 @@ impl Delta {
self.target_len += s.count_utf16_code_units();
let new_last = match self.ops.as_mut_slice() {
[.., Operation::Insert(insert)] => {
[.., Operation::<T>::Insert(insert)] => {
//
insert.merge_or_new_op(&s, attributes)
},
[.., Operation::Insert(pre_insert), Operation::Delete(_)] => {
[.., Operation::<T>::Insert(pre_insert), Operation::Delete(_)] => {
//
pre_insert.merge_or_new_op(&s, attributes)
},
[.., op_last @ Operation::Delete(_)] => {
[.., op_last @ Operation::<T>::Delete(_)] => {
let new_last = op_last.clone();
*op_last = OpBuilder::insert(&s).attributes(attributes).build();
*op_last = OpBuilder::<T>::insert(&s).attributes(attributes).build();
Some(new_last)
},
_ => Some(OpBuilder::insert(&s).attributes(attributes).build()),
_ => Some(OpBuilder::<T>::insert(&s).attributes(attributes).build()),
};
match new_last {
@ -155,19 +126,19 @@ impl Delta {
}
}
pub fn retain(&mut self, n: usize, attributes: Attributes) {
pub fn retain(&mut self, n: usize, attributes: T) {
if n == 0 {
return;
}
self.base_len += n as usize;
self.target_len += n as usize;
if let Some(Operation::Retain(retain)) = self.ops.last_mut() {
if let Some(Operation::<T>::Retain(retain)) = self.ops.last_mut() {
if let Some(new_op) = retain.merge_or_new(n, attributes) {
self.ops.push(new_op);
}
} else {
self.ops.push(OpBuilder::retain(n).attributes(attributes).build());
self.ops.push(OpBuilder::<T>::retain(n).attributes(attributes).build());
}
}
@ -207,7 +178,7 @@ impl Delta {
for op in &self.ops {
match &op {
Operation::Retain(retain) => {
inverted.retain(retain.n, Attributes::default());
inverted.retain(retain.n, T::default());
// TODO: use advance_by instead, but it's unstable now
// chars.advance_by(retain.num)
for _ in 0..retain.n {
@ -234,7 +205,10 @@ impl Delta {
pub fn extend(&mut self, other: Self) { other.ops.into_iter().for_each(|op| self.add(op)); }
}
impl OperationTransformable for Delta {
impl<T> OperationTransformable for Delta<T>
where
T: Attributes,
{
fn compose(&self, other: &Self) -> Result<Self, OTError>
where
Self: Sized,
@ -453,7 +427,13 @@ impl OperationTransformable for Delta {
}
}
fn invert_from_other(base: &mut Delta, other: &Delta, operation: &Operation, start: usize, end: usize) {
fn invert_from_other<T: Attributes>(
base: &mut Delta<T>,
other: &Delta<T>,
operation: &Operation<T>,
start: usize,
end: usize,
) {
tracing::trace!("invert op: {} [{}:{}]", operation, start, end);
let other_ops = DeltaIter::from_interval(other, Interval::new(start, end)).ops();
other_ops.into_iter().for_each(|other_op| match operation {
@ -476,10 +456,10 @@ fn invert_from_other(base: &mut Delta, other: &Delta, operation: &Operation, sta
});
}
fn transform_op_attribute(left: &Option<Operation>, right: &Option<Operation>) -> Attributes {
fn transform_op_attribute<T: Attributes>(left: &Option<Operation<T>>, right: &Option<Operation<T>>) -> T {
if left.is_none() {
if right.is_none() {
return Attributes::default();
return T::default();
}
return right.as_ref().unwrap().get_attributes();
}
@ -488,3 +468,58 @@ fn transform_op_attribute(left: &Option<Operation>, right: &Option<Operation>) -
// TODO: It's ok to unwrap?
left.transform(&right).unwrap().0
}
pub type RichTextDelta = Delta<RichTextAttributes>;
impl<T> Delta<T>
where
T: Attributes + DeserializeOwned,
{
pub fn from_json(json: &str) -> Result<Self, OTError> {
let delta = serde_json::from_str(json).map_err(|e| {
tracing::trace!("Deserialize failed: {:?}", e);
tracing::trace!("{:?}", json);
e
})?;
Ok(delta)
}
pub fn from_bytes<B: AsRef<[u8]>>(bytes: B) -> Result<Self, OTError> {
let json = str::from_utf8(bytes.as_ref())?.to_owned();
let val = Self::from_json(&json)?;
Ok(val)
}
}
impl<T> Delta<T>
where
T: Attributes + serde::Serialize,
{
pub fn to_json(&self) -> String { serde_json::to_string(self).unwrap_or_else(|_| "".to_owned()) }
pub fn to_bytes(&self) -> Bytes {
let json = self.to_json();
Bytes::from(json.into_bytes())
}
}
impl FromStr for RichTextDelta {
type Err = ();
fn from_str(s: &str) -> Result<RichTextDelta, Self::Err> {
let mut delta = Delta::with_capacity(1);
delta.add(Operation::Insert(s.into()));
Ok(delta)
}
}
impl std::convert::TryFrom<Vec<u8>> for RichTextDelta {
type Error = OTError;
fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> { Delta::from_bytes(bytes) }
}
impl std::convert::TryFrom<Bytes> for RichTextDelta {
type Error = OTError;
fn try_from(bytes: Bytes) -> Result<Self, Self::Error> { Delta::from_bytes(&bytes) }
}

View File

@ -1,4 +1,4 @@
use crate::core::Delta;
use crate::core::{Attributes, Delta};
use serde::{
de::{SeqAccess, Visitor},
ser::SerializeSeq,
@ -7,9 +7,12 @@ use serde::{
Serialize,
Serializer,
};
use std::fmt;
use std::{fmt, marker::PhantomData};
impl Serialize for Delta {
impl<T> Serialize for Delta<T>
where
T: Attributes + Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
@ -22,18 +25,25 @@ impl Serialize for Delta {
}
}
impl<'de> Deserialize<'de> for Delta {
fn deserialize<D>(deserializer: D) -> Result<Delta, D::Error>
impl<'de, T> Deserialize<'de> for Delta<T>
where
T: Attributes + Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Delta<T>, D::Error>
where
D: Deserializer<'de>,
{
struct OperationSeqVisitor;
struct OperationSeqVisitor<T>(PhantomData<fn() -> T>);
impl<'de> Visitor<'de> for OperationSeqVisitor {
type Value = Delta;
impl<'de, T> Visitor<'de> for OperationSeqVisitor<T>
where
T: Attributes + Deserialize<'de>,
{
type Value = Delta<T>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a sequence") }
#[inline]
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
@ -46,6 +56,6 @@ impl<'de> Deserialize<'de> for Delta {
}
}
deserializer.deserialize_seq(OperationSeqVisitor)
deserializer.deserialize_seq(OperationSeqVisitor(PhantomData))
}
}

View File

@ -1,32 +1,35 @@
use super::cursor::*;
use crate::core::{Attributes, Delta, Interval, Operation, NEW_LINE};
use crate::core::{Attributes, Delta, Interval, Operation, RichTextAttributes, NEW_LINE};
use std::ops::{Deref, DerefMut};
pub(crate) const MAX_IV_LEN: usize = i32::MAX as usize;
pub struct DeltaIter<'a> {
cursor: OpCursor<'a>,
pub struct DeltaIter<'a, T: Attributes> {
cursor: OpCursor<'a, T>,
}
impl<'a> DeltaIter<'a> {
pub fn new(delta: &'a Delta) -> Self {
impl<'a, T> DeltaIter<'a, T>
where
T: Attributes,
{
pub fn new(delta: &'a Delta<T>) -> Self {
let interval = Interval::new(0, MAX_IV_LEN);
Self::from_interval(delta, interval)
}
pub fn from_offset(delta: &'a Delta, offset: usize) -> Self {
pub fn from_offset(delta: &'a Delta<T>, offset: usize) -> Self {
let interval = Interval::new(0, MAX_IV_LEN);
let mut iter = Self::from_interval(delta, interval);
iter.seek::<CharMetric>(offset);
iter
}
pub fn from_interval(delta: &'a Delta, interval: Interval) -> Self {
pub fn from_interval(delta: &'a Delta<T>, interval: Interval) -> Self {
let cursor = OpCursor::new(delta, interval);
Self { cursor }
}
pub fn ops(&mut self) -> Vec<Operation> { self.collect::<Vec<_>>() }
pub fn ops(&mut self) -> Vec<Operation<T>> { self.collect::<Vec<_>>() }
pub fn next_op_len(&self) -> Option<usize> {
let interval = self.cursor.next_iv();
@ -37,12 +40,12 @@ impl<'a> DeltaIter<'a> {
}
}
pub fn next_op(&mut self) -> Option<Operation> { self.cursor.next_op() }
pub fn next_op(&mut self) -> Option<Operation<T>> { self.cursor.next_op() }
pub fn next_op_with_len(&mut self, len: usize) -> Option<Operation> { self.cursor.next_with_len(Some(len)) }
pub fn next_op_with_len(&mut self, len: usize) -> Option<Operation<T>> { self.cursor.next_with_len(Some(len)) }
// find next op contains NEW_LINE
pub fn next_op_with_newline(&mut self) -> Option<(Operation, usize)> {
pub fn next_op_with_newline(&mut self) -> Option<(Operation<T>, usize)> {
let mut offset = 0;
while self.has_next() {
if let Some(op) = self.next_op() {
@ -87,12 +90,15 @@ impl<'a> DeltaIter<'a> {
}
}
impl<'a> Iterator for DeltaIter<'a> {
type Item = Operation;
impl<'a, T> Iterator for DeltaIter<'a, T>
where
T: Attributes,
{
type Item = Operation<T>;
fn next(&mut self) -> Option<Self::Item> { self.next_op() }
}
pub fn is_empty_line_at_index(delta: &Delta, index: usize) -> bool {
pub fn is_empty_line_at_index(delta: &Delta<RichTextAttributes>, index: usize) -> bool {
let mut iter = DeltaIter::new(delta);
let (prev, next) = (iter.next_op_with_len(index), iter.next_op());
if prev.is_none() {
@ -108,58 +114,70 @@ pub fn is_empty_line_at_index(delta: &Delta, index: usize) -> bool {
OpNewline::parse(&prev).is_end() && OpNewline::parse(&next).is_start()
}
pub struct AttributesIter<'a> {
delta_iter: DeltaIter<'a>,
pub struct AttributesIter<'a, T: Attributes> {
delta_iter: DeltaIter<'a, T>,
}
impl<'a> AttributesIter<'a> {
pub fn new(delta: &'a Delta) -> Self {
impl<'a, T> AttributesIter<'a, T>
where
T: Attributes,
{
pub fn new(delta: &'a Delta<T>) -> Self {
let interval = Interval::new(0, usize::MAX);
Self::from_interval(delta, interval)
}
pub fn from_interval(delta: &'a Delta, interval: Interval) -> Self {
pub fn from_interval(delta: &'a Delta<T>, interval: Interval) -> Self {
let delta_iter = DeltaIter::from_interval(delta, interval);
Self { delta_iter }
}
pub fn next_or_empty(&mut self) -> Attributes {
pub fn next_or_empty(&mut self) -> T {
match self.next() {
None => Attributes::default(),
None => T::default(),
Some((_, attributes)) => attributes,
}
}
}
impl<'a> Deref for AttributesIter<'a> {
type Target = DeltaIter<'a>;
impl<'a, T> Deref for AttributesIter<'a, T>
where
T: Attributes,
{
type Target = DeltaIter<'a, T>;
fn deref(&self) -> &Self::Target { &self.delta_iter }
}
impl<'a> DerefMut for AttributesIter<'a> {
impl<'a, T> DerefMut for AttributesIter<'a, T>
where
T: Attributes,
{
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.delta_iter }
}
impl<'a> Iterator for AttributesIter<'a> {
type Item = (usize, Attributes);
impl<'a, T> Iterator for AttributesIter<'a, T>
where
T: Attributes,
{
type Item = (usize, T);
fn next(&mut self) -> Option<Self::Item> {
let next_op = self.delta_iter.next_op();
next_op.as_ref()?;
let mut length: usize = 0;
let mut attributes = Attributes::new();
let mut attributes = T::default();
match next_op.unwrap() {
Operation::Delete(_n) => {},
Operation::Retain(retain) => {
Operation::<T>::Delete(_n) => {},
Operation::<T>::Retain(retain) => {
tracing::trace!("extend retain attributes with {} ", &retain.attributes);
attributes.extend(retain.attributes.clone());
attributes.extend_other(retain.attributes.clone());
length = retain.n;
},
Operation::Insert(insert) => {
Operation::<T>::Insert(insert) => {
tracing::trace!("extend insert attributes with {} ", &insert.attributes);
attributes.extend(insert.attributes.clone());
attributes.extend_other(insert.attributes.clone());
length = insert.count_of_code_units();
},
}
@ -178,7 +196,7 @@ pub enum OpNewline {
}
impl OpNewline {
pub fn parse(op: &Operation) -> OpNewline {
pub fn parse<T: Attributes>(op: &Operation<T>) -> OpNewline {
let s = op.get_data();
if s == NEW_LINE {

View File

@ -1,30 +1,35 @@
use crate::core::{Attributes, Operation};
use crate::core::{Attributes, Operation, RichTextAttributes};
pub struct OpBuilder {
ty: Operation,
attrs: Attributes,
pub type RichTextOpBuilder = OpBuilder<RichTextAttributes>;
pub struct OpBuilder<T: Attributes> {
ty: Operation<T>,
attrs: T,
}
impl OpBuilder {
pub fn new(ty: Operation) -> OpBuilder {
impl<T> OpBuilder<T>
where
T: Attributes,
{
pub fn new(ty: Operation<T>) -> OpBuilder<T> {
OpBuilder {
ty,
attrs: Attributes::default(),
attrs: T::default(),
}
}
pub fn retain(n: usize) -> OpBuilder { OpBuilder::new(Operation::Retain(n.into())) }
pub fn retain(n: usize) -> OpBuilder<T> { OpBuilder::new(Operation::Retain(n.into())) }
pub fn delete(n: usize) -> OpBuilder { OpBuilder::new(Operation::Delete(n)) }
pub fn delete(n: usize) -> OpBuilder<T> { OpBuilder::new(Operation::Delete(n)) }
pub fn insert(s: &str) -> OpBuilder { OpBuilder::new(Operation::Insert(s.into())) }
pub fn insert(s: &str) -> OpBuilder<T> { OpBuilder::new(Operation::Insert(s.into())) }
pub fn attributes(mut self, attrs: Attributes) -> OpBuilder {
pub fn attributes(mut self, attrs: T) -> OpBuilder<T> {
self.attrs = attrs;
self
}
pub fn build(self) -> Operation {
pub fn build(self) -> Operation<T> {
let mut operation = self.ty;
match &mut operation {
Operation::Delete(_) => {},

View File

@ -1,19 +1,39 @@
use crate::core::{Attribute, Attributes, FlowyStr, Interval, OpBuilder};
use crate::core::{FlowyStr, Interval, OpBuilder, OperationTransformable, RichTextAttribute, RichTextAttributes};
use serde::__private::Formatter;
use std::{
cmp::min,
fmt,
fmt::Debug,
ops::{Deref, DerefMut},
};
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Operation {
Delete(usize),
Retain(Retain),
Insert(Insert),
pub trait Attributes: fmt::Display + Eq + PartialEq + Default + Clone + Debug + OperationTransformable {
fn is_empty(&self) -> bool;
// Remove the empty attribute which value is None.
fn remove_empty(&mut self);
fn extend_other(&mut self, other: Self);
}
impl Operation {
pub type RichTextOperation = Operation<RichTextAttributes>;
impl RichTextOperation {
pub fn contain_attribute(&self, attribute: &RichTextAttribute) -> bool {
self.get_attributes().contains_key(&attribute.key)
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Operation<T: Attributes> {
Delete(usize),
Retain(Retain<T>),
Insert(Insert<T>),
}
impl<T> Operation<T>
where
T: Attributes,
{
pub fn get_data(&self) -> &str {
match self {
Operation::Delete(_) => "",
@ -22,15 +42,15 @@ impl Operation {
}
}
pub fn get_attributes(&self) -> Attributes {
pub fn get_attributes(&self) -> T {
match self {
Operation::Delete(_) => Attributes::default(),
Operation::Delete(_) => T::default(),
Operation::Retain(retain) => retain.attributes.clone(),
Operation::Insert(insert) => insert.attributes.clone(),
}
}
pub fn set_attributes(&mut self, attributes: Attributes) {
pub fn set_attributes(&mut self, attributes: T) {
match self {
Operation::Delete(_) => log::error!("Delete should not contains attributes"),
Operation::Retain(retain) => retain.attributes = attributes,
@ -40,10 +60,6 @@ impl Operation {
pub fn has_attribute(&self) -> bool { !self.get_attributes().is_empty() }
pub fn contain_attribute(&self, attribute: &Attribute) -> bool {
self.get_attributes().contains_key(&attribute.key)
}
pub fn len(&self) -> usize {
match self {
Operation::Delete(n) => *n,
@ -55,28 +71,28 @@ impl Operation {
pub fn is_empty(&self) -> bool { self.len() == 0 }
#[allow(dead_code)]
pub fn split(&self, index: usize) -> (Option<Operation>, Option<Operation>) {
pub fn split(&self, index: usize) -> (Option<Operation<T>>, Option<Operation<T>>) {
debug_assert!(index < self.len());
let left;
let right;
match self {
Operation::Delete(n) => {
left = Some(OpBuilder::delete(index).build());
right = Some(OpBuilder::delete(*n - index).build());
left = Some(OpBuilder::<T>::delete(index).build());
right = Some(OpBuilder::<T>::delete(*n - index).build());
},
Operation::Retain(retain) => {
left = Some(OpBuilder::delete(index).build());
right = Some(OpBuilder::delete(retain.n - index).build());
left = Some(OpBuilder::<T>::delete(index).build());
right = Some(OpBuilder::<T>::delete(retain.n - index).build());
},
Operation::Insert(insert) => {
let attributes = self.get_attributes();
left = Some(
OpBuilder::insert(&insert.s[0..index])
OpBuilder::<T>::insert(&insert.s[0..index])
.attributes(attributes.clone())
.build(),
);
right = Some(
OpBuilder::insert(&insert.s[index..insert.count_of_code_units()])
OpBuilder::<T>::insert(&insert.s[index..insert.count_of_code_units()])
.attributes(attributes)
.build(),
);
@ -86,7 +102,7 @@ impl Operation {
(left, right)
}
pub fn shrink(&self, interval: Interval) -> Option<Operation> {
pub fn shrink(&self, interval: Interval) -> Option<Operation<T>> {
let op = match self {
Operation::Delete(n) => OpBuilder::delete(min(*n, interval.size())).build(),
Operation::Retain(retain) => OpBuilder::retain(min(retain.n, interval.size()))
@ -145,7 +161,10 @@ impl Operation {
}
}
impl fmt::Display for Operation {
impl<T> fmt::Display for Operation<T>
where
T: Attributes,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("{")?;
match self {
@ -164,15 +183,18 @@ impl fmt::Display for Operation {
}
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct Retain {
#[serde(rename(serialize = "retain", deserialize = "retain"))]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Retain<T: Attributes> {
// #[serde(rename(serialize = "retain", deserialize = "retain"))]
pub n: usize,
#[serde(skip_serializing_if = "is_empty")]
pub attributes: Attributes,
// #[serde(skip_serializing_if = "is_empty")]
pub attributes: T,
}
impl fmt::Display for Retain {
impl<T> fmt::Display for Retain<T>
where
T: Attributes,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
if self.attributes.is_empty() {
f.write_fmt(format_args!("retain: {}", self.n))
@ -182,8 +204,11 @@ impl fmt::Display for Retain {
}
}
impl Retain {
pub fn merge_or_new(&mut self, n: usize, attributes: Attributes) -> Option<Operation> {
impl<T> Retain<T>
where
T: Attributes,
{
pub fn merge_or_new(&mut self, n: usize, attributes: T) -> Option<Operation<T>> {
tracing::trace!(
"merge_retain_or_new_op: len: {:?}, l: {} - r: {}",
n,
@ -201,35 +226,47 @@ impl Retain {
pub fn is_plain(&self) -> bool { self.attributes.is_empty() }
}
impl std::convert::From<usize> for Retain {
impl<T> std::convert::From<usize> for Retain<T>
where
T: Attributes,
{
fn from(n: usize) -> Self {
Retain {
n,
attributes: Attributes::default(),
attributes: T::default(),
}
}
}
impl Deref for Retain {
impl<T> Deref for Retain<T>
where
T: Attributes,
{
type Target = usize;
fn deref(&self) -> &Self::Target { &self.n }
}
impl DerefMut for Retain {
impl<T> DerefMut for Retain<T>
where
T: Attributes,
{
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.n }
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct Insert {
#[serde(rename(serialize = "insert", deserialize = "insert"))]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Insert<T: Attributes> {
// #[serde(rename(serialize = "insert", deserialize = "insert"))]
pub s: FlowyStr,
#[serde(skip_serializing_if = "is_empty")]
pub attributes: Attributes,
// #[serde(skip_serializing_if = "is_empty")]
pub attributes: T,
}
impl fmt::Display for Insert {
impl<T> fmt::Display for Insert<T>
where
T: Attributes,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let mut s = self.s.clone();
if s.ends_with('\n') {
@ -247,41 +284,51 @@ impl fmt::Display for Insert {
}
}
impl Insert {
impl<T> Insert<T>
where
T: Attributes,
{
pub fn count_of_code_units(&self) -> usize { self.s.count_utf16_code_units() }
pub fn merge_or_new_op(&mut self, s: &str, attributes: Attributes) -> Option<Operation> {
pub fn merge_or_new_op(&mut self, s: &str, attributes: T) -> Option<Operation<T>> {
if self.attributes == attributes {
self.s += s;
None
} else {
Some(OpBuilder::insert(s).attributes(attributes).build())
Some(OpBuilder::<T>::insert(s).attributes(attributes).build())
}
}
pub fn is_plain(&self) -> bool { self.attributes.is_empty() }
}
impl std::convert::From<String> for Insert {
impl<T> std::convert::From<String> for Insert<T>
where
T: Attributes,
{
fn from(s: String) -> Self {
Insert {
s: s.into(),
attributes: Attributes::default(),
attributes: T::default(),
}
}
}
impl std::convert::From<&str> for Insert {
impl<T> std::convert::From<&str> for Insert<T>
where
T: Attributes,
{
fn from(s: &str) -> Self { Insert::from(s.to_owned()) }
}
impl std::convert::From<FlowyStr> for Insert {
impl<T> std::convert::From<FlowyStr> for Insert<T>
where
T: Attributes,
{
fn from(s: FlowyStr) -> Self {
Insert {
s,
attributes: Attributes::default(),
attributes: T::default(),
}
}
}
fn is_empty(attributes: &Attributes) -> bool { attributes.is_empty() }

View File

@ -1,16 +1,19 @@
use crate::core::{Attributes, Operation};
use crate::core::{Attributes, FlowyStr, Insert, Operation, Retain};
use serde::{
de,
de::{MapAccess, Visitor},
de::{MapAccess, SeqAccess, Visitor},
ser::SerializeMap,
Deserialize,
Deserializer,
Serialize,
Serializer,
};
use std::fmt;
use std::{fmt, marker::PhantomData};
impl Serialize for Operation {
impl<T> Serialize for Operation<T>
where
T: Attributes + Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
@ -27,20 +30,27 @@ impl Serialize for Operation {
}
}
impl<'de> Deserialize<'de> for Operation {
fn deserialize<D>(deserializer: D) -> Result<Operation, D::Error>
impl<'de, T> Deserialize<'de> for Operation<T>
where
T: Attributes + Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Operation<T>, D::Error>
where
D: Deserializer<'de>,
{
struct OperationVisitor;
struct OperationVisitor<T>(PhantomData<fn() -> T>);
impl<'de> Visitor<'de> for OperationVisitor {
type Value = Operation;
impl<'de, T> Visitor<'de> for OperationVisitor<T>
where
T: Attributes + Deserialize<'de>,
{
type Value = Operation<T>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("an integer between -2^64 and 2^63 or a string")
}
#[inline]
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
where
V: MapAccess<'de>,
@ -53,27 +63,27 @@ impl<'de> Deserialize<'de> for Operation {
if operation.is_some() {
return Err(de::Error::duplicate_field("operation"));
}
operation = Some(Operation::Delete(map.next_value()?));
operation = Some(Operation::<T>::Delete(map.next_value()?));
},
"retain" => {
if operation.is_some() {
return Err(de::Error::duplicate_field("operation"));
}
let i: usize = map.next_value()?;
operation = Some(Operation::Retain(i.into()));
operation = Some(Operation::<T>::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()));
operation = Some(Operation::<T>::Insert(i.into()));
},
"attributes" => {
if attributes.is_some() {
return Err(de::Error::duplicate_field("attributes"));
}
let map: Attributes = map.next_value()?;
let map: T = map.next_value()?;
attributes = Some(map);
},
_ => panic!(),
@ -91,6 +101,208 @@ impl<'de> Deserialize<'de> for Operation {
}
}
deserializer.deserialize_any(OperationVisitor)
deserializer.deserialize_any(OperationVisitor(PhantomData))
}
}
impl<T> Serialize for Retain<T>
where
T: Attributes + Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let len = false as usize + 1 + if self.attributes.is_empty() { 0 } else { 1 };
let mut serde_state = serializer.serialize_struct("Retain", len)?;
let _ = serde::ser::SerializeStruct::serialize_field(&mut serde_state, "retain", &self.n)?;
if !self.attributes.is_empty() {
let _ = serde::ser::SerializeStruct::serialize_field(&mut serde_state, "attributes", &self.attributes)?;
}
serde::ser::SerializeStruct::end(serde_state)
}
}
impl<'de, T> Deserialize<'de> for Retain<T>
where
T: Attributes + Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
where
D: Deserializer<'de>,
{
struct RetainVisitor<T>(PhantomData<fn() -> T>);
impl<'de, T> Visitor<'de> for RetainVisitor<T>
where
T: Attributes + Deserialize<'de>,
{
type Value = Retain<T>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("struct Retain") }
#[inline]
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let len = match serde::de::SeqAccess::next_element::<usize>(&mut seq)? {
Some(val) => val,
None => {
return Err(de::Error::invalid_length(0, &"struct Retain with 2 elements"));
},
};
let attributes = match serde::de::SeqAccess::next_element::<T>(&mut seq)? {
Some(val) => val,
None => {
return Err(de::Error::invalid_length(1, &"struct Retain with 2 elements"));
},
};
Ok(Retain::<T> { n: len, attributes })
}
#[inline]
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
where
V: MapAccess<'de>,
{
let mut len: Option<usize> = None;
let mut attributes: Option<T> = None;
while let Some(key) = map.next_key()? {
match key {
"retain" => {
if len.is_some() {
return Err(de::Error::duplicate_field("retain"));
}
len = Some(map.next_value()?);
},
"attributes" => {
if attributes.is_some() {
return Err(de::Error::duplicate_field("attributes"));
}
attributes = Some(map.next_value()?);
},
_ => panic!(),
}
}
if len.is_none() {
return Err(de::Error::missing_field("len"));
}
if attributes.is_none() {
return Err(de::Error::missing_field("attributes"));
}
Ok(Retain::<T> {
n: len.unwrap(),
attributes: attributes.unwrap(),
})
}
}
const FIELDS: &[&str] = &["retain", "attributes"];
serde::Deserializer::deserialize_struct(deserializer, "Retain", FIELDS, RetainVisitor(PhantomData))
}
}
impl<T> Serialize for Insert<T>
where
T: Attributes + Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let len = false as usize + 1 + if self.attributes.is_empty() { 0 } else { 1 };
let mut serde_state = serializer.serialize_struct("Insert", len)?;
let _ = serde::ser::SerializeStruct::serialize_field(&mut serde_state, "insert", &self.s)?;
if !self.attributes.is_empty() {
let _ = serde::ser::SerializeStruct::serialize_field(&mut serde_state, "attributes", &self.attributes)?;
}
serde::ser::SerializeStruct::end(serde_state)
}
}
impl<'de, T> Deserialize<'de> for Insert<T>
where
T: Attributes + Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
where
D: Deserializer<'de>,
{
struct InsertVisitor<T>(PhantomData<fn() -> T>);
impl<'de, T> Visitor<'de> for InsertVisitor<T>
where
T: Attributes + Deserialize<'de>,
{
type Value = Insert<T>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("struct Insert") }
#[inline]
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let s = match serde::de::SeqAccess::next_element::<FlowyStr>(&mut seq)? {
Some(val) => val,
None => {
return Err(de::Error::invalid_length(0, &"struct Insert with 2 elements"));
},
};
let attributes = match serde::de::SeqAccess::next_element::<T>(&mut seq)? {
Some(val) => val,
None => {
return Err(de::Error::invalid_length(1, &"struct Retain with 2 elements"));
},
};
Ok(Insert::<T> { s, attributes })
}
#[inline]
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
where
V: MapAccess<'de>,
{
let mut s: Option<FlowyStr> = None;
let mut attributes: Option<T> = None;
while let Some(key) = map.next_key()? {
match key {
"insert" => {
if s.is_some() {
return Err(de::Error::duplicate_field("insert"));
}
s = Some(map.next_value()?);
},
"attributes" => {
if attributes.is_some() {
return Err(de::Error::duplicate_field("attributes"));
}
attributes = Some(map.next_value()?);
},
_ => panic!(),
}
}
if s.is_none() {
return Err(de::Error::missing_field("s"));
}
if attributes.is_none() {
return Err(de::Error::missing_field("attributes"));
}
Ok(Insert::<T> {
s: s.unwrap(),
attributes: attributes.unwrap(),
})
}
}
const FIELDS: &[&str] = &["insert", "attributes"];
serde::Deserializer::deserialize_struct(deserializer, "Insert", FIELDS, InsertVisitor(PhantomData))
}
}