From 268f3c1e966c6f77c2ccc0455a8a69220952c7b6 Mon Sep 17 00:00:00 2001 From: Zixuan Chen Date: Fri, 15 Jul 2022 20:34:23 +0800 Subject: [PATCH] refactor: add container type & twist many things --- crates/loro-core/Cargo.toml | 1 + crates/loro-core/src/change.rs | 5 ++- crates/loro-core/src/container.rs | 48 +++++++++++++++++++++ crates/loro-core/src/lib.rs | 2 +- crates/loro-core/src/op.rs | 25 +++++------ crates/loro-core/src/op/op_content.rs | 16 +++---- crates/loro-core/src/op/op_proxy.rs | 30 +++++++++++++ crates/loro-framework/src/loro.rs | 3 +- crates/loro-text/src/text_insert_content.rs | 24 +++++------ 9 files changed, 114 insertions(+), 40 deletions(-) create mode 100644 crates/loro-core/src/container.rs create mode 100644 crates/loro-core/src/op/op_proxy.rs diff --git a/crates/loro-core/Cargo.toml b/crates/loro-core/Cargo.toml index 25d9daf3..69bd5ccc 100644 --- a/crates/loro-core/Cargo.toml +++ b/crates/loro-core/Cargo.toml @@ -9,3 +9,4 @@ edition = "2021" string_cache = "0.8.3" rle = {path = "../rle"} smallvec = "1.8.0" +smartstring = "1.0.1" diff --git a/crates/loro-core/src/change.rs b/crates/loro-core/src/change.rs index b7cc1c49..3da4ffcf 100644 --- a/crates/loro-core/src/change.rs +++ b/crates/loro-core/src/change.rs @@ -5,9 +5,9 @@ use rle::{HasLength, Mergable, RleVec}; use smallvec::SmallVec; pub type Timestamp = i64; -pub type Lamport = u64; +pub type Lamport = u32; -/// Change +/// A `Change` contains a list of [Op]s. #[derive(Debug)] pub struct Change { pub(crate) ops: RleVec, @@ -89,5 +89,6 @@ impl Mergable for Change { self.id.client_id == other.id.client_id && self.id.counter + self.len() as u32 == other.id.counter + && self.lamport + self.len() as Lamport == other.lamport } } diff --git a/crates/loro-core/src/container.rs b/crates/loro-core/src/container.rs new file mode 100644 index 00000000..fa1b5166 --- /dev/null +++ b/crates/loro-core/src/container.rs @@ -0,0 +1,48 @@ +use rle::{HasLength, Mergable, Sliceable}; +use smartstring::{LazyCompact, SmartString}; + +use crate::{InsertContent, ID}; + +/// Container is a special kind of op content. Each container has its own CRDT implementation. +/// Each [Op] must be associated with a container. +/// +#[derive(Debug, Clone)] +pub struct Container { + parent: Option, + parent_slot: SmartString, +} + +impl HasLength for Container { + fn len(&self) -> usize { + 1 + } +} + +impl Mergable for Container { + fn is_mergable(&self, other: &Self, conf: &()) -> bool + where + Self: Sized, + { + false + } + + fn merge(&mut self, other: &Self, conf: &()) + where + Self: Sized, + { + unreachable!() + } +} + +impl Sliceable for Container { + fn slice(&self, from: usize, to: usize) -> Self { + assert!(from == 0 && to == 1); + self.clone() + } +} + +impl InsertContent for Container { + fn id(&self) -> crate::ContentTypeID { + crate::ContentTypeID::Container + } +} diff --git a/crates/loro-core/src/lib.rs b/crates/loro-core/src/lib.rs index ebcf7a7d..27b12681 100644 --- a/crates/loro-core/src/lib.rs +++ b/crates/loro-core/src/lib.rs @@ -1,7 +1,7 @@ #![allow(dead_code, unused_imports)] -#![feature(trait_upcasting)] mod change; +mod container; mod id; mod id_span; mod log_store; diff --git a/crates/loro-core/src/op.rs b/crates/loro-core/src/op.rs index c7585f69..31f26c4c 100644 --- a/crates/loro-core/src/op.rs +++ b/crates/loro-core/src/op.rs @@ -2,6 +2,7 @@ use crate::{id::ID, id_span::IdSpan}; use rle::{HasLength, Mergable, RleVec, Sliceable}; mod insert_content; mod op_content; +mod op_proxy; pub use insert_content::*; pub use op_content::*; @@ -15,6 +16,14 @@ pub enum OpType { } #[derive(Debug, Clone)] +/// Operation is a unit of change. +/// +/// It has 3 types: +/// - Insert +/// - Delete +/// - Restore +/// +/// A Op may have multiple atomic operations, since Op can be merged. pub struct Op { id: ID, content: OpContent, @@ -59,24 +68,16 @@ impl Mergable for Op { } => container == &other_container && content.is_mergable_content(&**other_content), _ => false, }, - OpContent::Delete { target, lamport } => match other.content { + OpContent::Delete { target } => match other.content { OpContent::Delete { target: ref other_target, - lamport: ref other_lamport, - } => { - lamport + target.len() == *other_lamport - && target.is_mergable(other_target, cfg) - } + } => target.is_mergable(other_target, cfg), _ => false, }, - OpContent::Restore { target, lamport } => match other.content { + OpContent::Restore { target } => match other.content { OpContent::Restore { target: ref other_target, - lamport: ref other_lamport, - } => { - lamport + target.len() == *other_lamport - && target.is_mergable(other_target, cfg) - } + } => target.is_mergable(other_target, cfg), _ => false, }, } diff --git a/crates/loro-core/src/op/op_content.rs b/crates/loro-core/src/op/op_content.rs index a4ec1724..36dfa1a5 100644 --- a/crates/loro-core/src/op/op_content.rs +++ b/crates/loro-core/src/op/op_content.rs @@ -12,11 +12,9 @@ pub enum OpContent { }, Delete { target: RleVec, - lamport: usize, }, Restore { target: RleVec, - lamport: usize, }, } @@ -37,13 +35,11 @@ impl Clone for OpContent { container: *container, content: content.clone_content(), }, - OpContent::Delete { target, lamport } => OpContent::Delete { + OpContent::Delete { target } => OpContent::Delete { target: target.clone(), - lamport: *lamport, }, - OpContent::Restore { target, lamport } => OpContent::Restore { + OpContent::Restore { target } => OpContent::Restore { target: target.clone(), - lamport: *lamport, }, } } @@ -54,15 +50,13 @@ impl Sliceable for OpContent { match self { OpContent::Insert { container, content } => OpContent::Insert { container: *container, - content: content.slice(from, to), + content: content.slice_content(from, to), }, - OpContent::Delete { target, lamport } => OpContent::Delete { + OpContent::Delete { target } => OpContent::Delete { target: target.slice(from, to), - lamport: lamport + from, }, - OpContent::Restore { target, lamport } => OpContent::Restore { + OpContent::Restore { target } => OpContent::Restore { target: target.slice(from, to), - lamport: lamport + from, }, } } diff --git a/crates/loro-core/src/op/op_proxy.rs b/crates/loro-core/src/op/op_proxy.rs new file mode 100644 index 00000000..9e323550 --- /dev/null +++ b/crates/loro-core/src/op/op_proxy.rs @@ -0,0 +1,30 @@ +use crate::{Change, Lamport, Op, Timestamp, ID}; + +pub struct OpProxy<'a> { + change: &'a Change, + op: &'a Op, + /// offset of op in change + offset: u32, +} + +impl<'a> OpProxy<'a> { + pub fn new(change: &'a Change, op: &'a Op) -> Self { + OpProxy { + change, + op, + offset: 0, + } + } + + pub fn lamport(&self) -> Lamport { + self.change.lamport + self.offset + } + + pub fn id(&self) -> ID { + self.op.id + } + + pub fn timestamp(&self) -> Timestamp { + self.change.timestamp + } +} diff --git a/crates/loro-framework/src/loro.rs b/crates/loro-framework/src/loro.rs index bca7fe1e..d3ac7f17 100644 --- a/crates/loro-framework/src/loro.rs +++ b/crates/loro-framework/src/loro.rs @@ -1,9 +1,10 @@ -use loro_core::LogStore; +use loro_core::{ClientID, LogStore}; use crate::raw_store::RawStore; #[derive(Default)] pub struct Loro { + pub this_client_id: ClientID, pub raw_store: Option, pub log_store: Option, } diff --git a/crates/loro-text/src/text_insert_content.rs b/crates/loro-text/src/text_insert_content.rs index f6bdea90..351d76c6 100644 --- a/crates/loro-text/src/text_insert_content.rs +++ b/crates/loro-text/src/text_insert_content.rs @@ -1,5 +1,5 @@ use loro_core::{content, ContentTypeID, InsertContent, ID}; -use rle::{HasLength, Mergable}; +use rle::{HasLength, Mergable, Sliceable}; #[derive(Debug, Clone)] pub struct TextInsertContent { @@ -23,21 +23,17 @@ impl Mergable for TextInsertContent { } } -impl InsertContent for TextInsertContent { - fn id(&self) -> ContentTypeID { - ContentTypeID::Text - } - - fn slice(&self, from: usize, to: usize) -> Box { +impl Sliceable for TextInsertContent { + fn slice(&self, from: usize, to: usize) -> Self { if from == 0 { - Box::new(TextInsertContent { + TextInsertContent { origin_left: self.origin_left, origin_right: self.origin_right, id: self.id, text: self.text[..to].to_owned(), - }) + } } else { - Box::new(TextInsertContent { + TextInsertContent { origin_left: ID { client_id: self.id.client_id, counter: self.id.counter + from as u32 - 1, @@ -48,12 +44,14 @@ impl InsertContent for TextInsertContent { counter: self.id.counter + from as u32, }, text: self.text[from..to].to_owned(), - }) + } } } +} - fn clone_content(&self) -> Box { - Box::new(self.clone()) +impl InsertContent for TextInsertContent { + fn id(&self) -> ContentTypeID { + ContentTypeID::Text } }