mirror of
https://github.com/loro-dev/loro.git
synced 2025-01-23 05:24:51 +00:00
refactor: add inner content
This commit is contained in:
parent
8dba7d1e3a
commit
7295e1c613
12 changed files with 81 additions and 60 deletions
|
@ -19,7 +19,7 @@ use crate::{
|
|||
},
|
||||
context::Context,
|
||||
id::{Counter, ID},
|
||||
op::{Content, Op, RemoteOp, RichOp},
|
||||
op::{Op, RemoteContent, RemoteOp, RichOp},
|
||||
value::LoroValue,
|
||||
version::IdSpanVector,
|
||||
};
|
||||
|
@ -54,7 +54,7 @@ impl ListContainer {
|
|||
self.state.insert(pos, slice.clone().into());
|
||||
let op = Op::new(
|
||||
id,
|
||||
Content::List(ListOp::Insert {
|
||||
RemoteContent::List(ListOp::Insert {
|
||||
slice: slice.into(),
|
||||
pos,
|
||||
}),
|
||||
|
@ -76,7 +76,7 @@ impl ListContainer {
|
|||
self.state.insert(pos, slice.clone().into());
|
||||
let op = Op::new(
|
||||
id,
|
||||
Content::List(ListOp::Insert {
|
||||
RemoteContent::List(ListOp::Insert {
|
||||
slice: slice.into(),
|
||||
pos,
|
||||
}),
|
||||
|
@ -101,7 +101,7 @@ impl ListContainer {
|
|||
let id = store.next_id();
|
||||
let op = Op::new(
|
||||
id,
|
||||
Content::List(ListOp::new_del(pos, len)),
|
||||
RemoteContent::List(ListOp::new_del(pos, len)),
|
||||
store.get_or_create_container_idx(&self.id),
|
||||
);
|
||||
|
||||
|
@ -199,7 +199,7 @@ impl Container for ListContainer {
|
|||
|
||||
fn update_state_directly(&mut self, op: &RichOp) {
|
||||
match &op.get_sliced().content {
|
||||
Content::List(op) => match op {
|
||||
RemoteContent::List(op) => match op {
|
||||
ListOp::Insert { slice, pos } => {
|
||||
self.state.insert(*pos, slice.as_slice().unwrap().clone())
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::ops::Range;
|
|||
use enum_as_inner::EnumAsInner;
|
||||
use rle::{HasLength, Mergable, Sliceable};
|
||||
|
||||
use crate::container::text::text_content::ListSlice;
|
||||
use crate::container::text::text_content::{ListSlice, SliceRange};
|
||||
|
||||
#[derive(EnumAsInner, Debug, Clone)]
|
||||
pub enum ListOp {
|
||||
|
@ -11,6 +11,12 @@ pub enum ListOp {
|
|||
Delete(DeleteSpan),
|
||||
}
|
||||
|
||||
#[derive(EnumAsInner, Debug, Clone)]
|
||||
pub enum InnerListOp {
|
||||
Insert { slice: SliceRange, pos: usize },
|
||||
Delete(DeleteSpan),
|
||||
}
|
||||
|
||||
/// `len` can be negative so that we can merge text deletions efficiently.
|
||||
/// It looks like [crate::span::CounterSpan], but how should they merge ([Mergable] impl) and slice ([Sliceable] impl) are very different
|
||||
///
|
||||
|
|
|
@ -10,7 +10,7 @@ use crate::{
|
|||
},
|
||||
context::Context,
|
||||
op::RemoteOp,
|
||||
op::{Content, Op, RichOp},
|
||||
op::{Op, RemoteContent, RichOp},
|
||||
span::HasLamport,
|
||||
value::LoroValue,
|
||||
version::{IdSpanVector, TotalOrderStamp},
|
||||
|
@ -70,7 +70,7 @@ impl MapContainer {
|
|||
store.append_local_ops(&[Op {
|
||||
counter: id.counter,
|
||||
container,
|
||||
content: Content::Map(MapSet {
|
||||
content: RemoteContent::Map(MapSet {
|
||||
key: key.clone(),
|
||||
value: value.clone(),
|
||||
}),
|
||||
|
@ -103,7 +103,7 @@ impl MapContainer {
|
|||
store.append_local_ops(&[Op {
|
||||
counter: id.counter,
|
||||
container,
|
||||
content: Content::Map(MapSet {
|
||||
content: RemoteContent::Map(MapSet {
|
||||
key: key.clone(),
|
||||
value: value.clone(),
|
||||
}),
|
||||
|
|
|
@ -2,13 +2,18 @@ use rle::{HasLength, Mergable, Sliceable};
|
|||
|
||||
use crate::{ContentType, InsertContentTrait, InternalString, LoroValue};
|
||||
|
||||
// TODO: use imported and exported format to save the space
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct MapSet {
|
||||
pub(crate) key: InternalString,
|
||||
pub(crate) value: LoroValue,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct InnerMapSet {
|
||||
pub(crate) key: InternalString,
|
||||
pub(crate) value: usize,
|
||||
}
|
||||
|
||||
impl Mergable for MapSet {}
|
||||
impl Sliceable for MapSet {
|
||||
fn slice(&self, from: usize, to: usize) -> Self {
|
||||
|
|
|
@ -4,4 +4,4 @@ mod tests;
|
|||
|
||||
pub use map_container::Map;
|
||||
pub(crate) use map_container::MapContainer;
|
||||
pub(crate) use map_content::MapSet;
|
||||
pub(crate) use map_content::{InnerMapSet, MapSet};
|
||||
|
|
|
@ -14,7 +14,7 @@ use crate::{
|
|||
context::Context,
|
||||
debug_log,
|
||||
id::{Counter, ID},
|
||||
op::{Content, Op, RemoteOp, RichOp},
|
||||
op::{Op, RemoteContent, RemoteOp, RichOp},
|
||||
value::LoroValue,
|
||||
version::IdSpanVector,
|
||||
};
|
||||
|
@ -59,7 +59,7 @@ impl TextContainer {
|
|||
self.state.insert(pos, slice.clone().into());
|
||||
let op = Op::new(
|
||||
id,
|
||||
Content::List(ListOp::Insert {
|
||||
RemoteContent::List(ListOp::Insert {
|
||||
slice: slice.into(),
|
||||
pos,
|
||||
}),
|
||||
|
@ -84,7 +84,7 @@ impl TextContainer {
|
|||
let id = store.next_id();
|
||||
let op = Op::new(
|
||||
id,
|
||||
Content::List(ListOp::new_del(pos, len)),
|
||||
RemoteContent::List(ListOp::new_del(pos, len)),
|
||||
store.get_or_create_container_idx(&self.id),
|
||||
);
|
||||
|
||||
|
@ -142,7 +142,7 @@ impl Container for TextContainer {
|
|||
.update_aliveness(self.state.iter().map(|x| x.as_ref().0.clone()))
|
||||
}
|
||||
|
||||
let mut contents: RleVec<[Content; 1]> = RleVec::new();
|
||||
let mut contents: RleVec<[RemoteContent; 1]> = RleVec::new();
|
||||
for content in op.contents.iter_mut() {
|
||||
if let Some((slice, pos)) = content.as_list_mut().and_then(|x| x.as_insert_mut()) {
|
||||
match slice {
|
||||
|
@ -158,13 +158,13 @@ impl Container for TextContainer {
|
|||
for span in self.raw_str.get_aliveness(&r.0) {
|
||||
match span {
|
||||
Alive::True(span) => {
|
||||
contents.push(Content::List(ListOp::Insert {
|
||||
contents.push(RemoteContent::List(ListOp::Insert {
|
||||
slice: ListSlice::RawStr(s[start..start + span].into()),
|
||||
pos: pos_start,
|
||||
}));
|
||||
}
|
||||
Alive::False(span) => {
|
||||
let v = Content::List(ListOp::Insert {
|
||||
let v = RemoteContent::List(ListOp::Insert {
|
||||
slice: ListSlice::Unknown(span),
|
||||
pos: pos_start,
|
||||
});
|
||||
|
@ -177,14 +177,14 @@ impl Container for TextContainer {
|
|||
}
|
||||
assert_eq!(start, r.atom_len());
|
||||
} else {
|
||||
contents.push(Content::List(ListOp::Insert {
|
||||
contents.push(RemoteContent::List(ListOp::Insert {
|
||||
slice: ListSlice::RawStr(s),
|
||||
pos: *pos,
|
||||
}));
|
||||
}
|
||||
}
|
||||
this => {
|
||||
contents.push(Content::List(ListOp::Insert {
|
||||
contents.push(RemoteContent::List(ListOp::Insert {
|
||||
slice: this.clone(),
|
||||
pos: *pos,
|
||||
}));
|
||||
|
@ -220,7 +220,7 @@ impl Container for TextContainer {
|
|||
|
||||
fn update_state_directly(&mut self, op: &RichOp) {
|
||||
match &op.get_sliced().content {
|
||||
Content::List(op) => match op {
|
||||
RemoteContent::List(op) => match op {
|
||||
ListOp::Insert { slice, pos } => {
|
||||
let v = match slice {
|
||||
ListSlice::Slice(slice) => slice.clone(),
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
|||
container::{list::list_op::ListOp, text::tracker::yata_impl::YataImpl},
|
||||
debug_log,
|
||||
id::{Counter, ID},
|
||||
op::{Content, RichOp},
|
||||
op::{RemoteContent, RichOp},
|
||||
span::{HasId, HasIdSpan, IdSpan},
|
||||
version::IdSpanVector,
|
||||
VersionVector,
|
||||
|
@ -303,7 +303,7 @@ impl Tracker {
|
|||
}
|
||||
|
||||
/// apply an operation directly to the current tracker
|
||||
fn apply(&mut self, id: ID, content: &Content) {
|
||||
fn apply(&mut self, id: ID, content: &RemoteContent) {
|
||||
self.real_checkout();
|
||||
assert!(*self.current_vv.get(&id.client_id).unwrap_or(&0) <= id.counter);
|
||||
assert!(*self.all_vv.get(&id.client_id).unwrap_or(&0) <= id.counter);
|
||||
|
|
|
@ -192,7 +192,7 @@ impl HasLength for YSpan {
|
|||
|
||||
#[cfg(any(test, features = "test_utils"))]
|
||||
pub mod test {
|
||||
use crate::{container::text::text_content::ListSlice, op::Content, ContentType, Op, ID};
|
||||
use crate::{container::text::text_content::ListSlice, op::RemoteContent, ContentType, Op, ID};
|
||||
use rle::{HasLength, RleVecWithIndex};
|
||||
|
||||
use super::YSpan;
|
||||
|
@ -202,7 +202,7 @@ pub mod test {
|
|||
let mut vec: RleVecWithIndex<Op> = RleVecWithIndex::new();
|
||||
vec.push(Op::new(
|
||||
ID::new(0, 1),
|
||||
Content::Dyn(Box::new(YSpan {
|
||||
RemoteContent::Dyn(Box::new(YSpan {
|
||||
origin_left: Some(ID::new(0, 0)),
|
||||
origin_right: None,
|
||||
id: ID::new(0, 1),
|
||||
|
@ -213,7 +213,7 @@ pub mod test {
|
|||
));
|
||||
vec.push(Op::new(
|
||||
ID::new(0, 2),
|
||||
Content::Dyn(Box::new(YSpan {
|
||||
RemoteContent::Dyn(Box::new(YSpan {
|
||||
origin_left: Some(ID::new(0, 1)),
|
||||
origin_right: None,
|
||||
id: ID::new(0, 2),
|
||||
|
@ -235,7 +235,7 @@ pub mod test {
|
|||
let mut vec: RleVecWithIndex<Op> = RleVecWithIndex::new();
|
||||
vec.push(Op::new(
|
||||
ID::new(0, 1),
|
||||
Content::Dyn(Box::new(YSpan {
|
||||
RemoteContent::Dyn(Box::new(YSpan {
|
||||
origin_left: Some(ID::new(0, 0)),
|
||||
origin_right: None,
|
||||
id: ID::new(0, 1),
|
||||
|
@ -246,7 +246,7 @@ pub mod test {
|
|||
));
|
||||
vec.push(Op::new(
|
||||
ID::new(0, 2),
|
||||
Content::Dyn(Box::new(YSpan {
|
||||
RemoteContent::Dyn(Box::new(YSpan {
|
||||
origin_left: Some(ID::new(0, 0)),
|
||||
origin_right: Some(ID::new(0, 1)),
|
||||
id: ID::new(0, 5),
|
||||
|
|
|
@ -20,7 +20,7 @@ use crate::{
|
|||
},
|
||||
dag::remove_included_frontiers,
|
||||
id::{ClientID, ContainerIdx, Counter, ID},
|
||||
op::{Content, Op, RemoteOp},
|
||||
op::{Op, RemoteContent, RemoteOp},
|
||||
smstring::SmString,
|
||||
span::{HasIdSpan, HasLamportSpan},
|
||||
ContainerType, InternalString, LogStore, LoroValue, VersionVector,
|
||||
|
@ -129,7 +129,7 @@ fn encode_changes(store: &LogStore) -> Encoded {
|
|||
for (op, container) in remote_ops.into_iter().zip(containers.into_iter()) {
|
||||
for content in op.contents.into_iter() {
|
||||
let (prop, gc, value) = match content {
|
||||
crate::op::Content::Map(MapSet { key, value }) => (
|
||||
crate::op::RemoteContent::Map(MapSet { key, value }) => (
|
||||
*key_to_idx.entry(key.clone()).or_insert_with(|| {
|
||||
keys.push(key);
|
||||
keys.len() - 1
|
||||
|
@ -137,7 +137,7 @@ fn encode_changes(store: &LogStore) -> Encoded {
|
|||
0,
|
||||
value,
|
||||
),
|
||||
crate::op::Content::List(list) => match list {
|
||||
crate::op::RemoteContent::List(list) => match list {
|
||||
ListOp::Insert { slice, pos } => (
|
||||
pos,
|
||||
match &slice {
|
||||
|
@ -155,7 +155,7 @@ fn encode_changes(store: &LogStore) -> Encoded {
|
|||
(span.pos as usize, 0, LoroValue::I32(span.len as i32))
|
||||
}
|
||||
},
|
||||
crate::op::Content::Dyn(_) => unreachable!(),
|
||||
crate::op::RemoteContent::Dyn(_) => unreachable!(),
|
||||
};
|
||||
op_len += 1;
|
||||
ops.push(OpEncoding {
|
||||
|
@ -256,7 +256,7 @@ fn decode_changes(
|
|||
let content = match container_type {
|
||||
ContainerType::Map => {
|
||||
let key = keys[prop].clone();
|
||||
Content::Map(MapSet { key, value })
|
||||
RemoteContent::Map(MapSet { key, value })
|
||||
}
|
||||
ContainerType::List | ContainerType::Text => {
|
||||
let pos = prop;
|
||||
|
@ -278,7 +278,7 @@ fn decode_changes(
|
|||
ListOp::Insert { slice, pos }
|
||||
}
|
||||
};
|
||||
Content::List(list_op)
|
||||
RemoteContent::List(list_op)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -23,14 +23,14 @@ use smallvec::{smallvec, SmallVec};
|
|||
pub struct Op {
|
||||
pub(crate) counter: Counter,
|
||||
pub(crate) container: ContainerIdx,
|
||||
pub(crate) content: Content,
|
||||
pub(crate) content: RemoteContent,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RemoteOp {
|
||||
pub(crate) counter: Counter,
|
||||
pub(crate) container: ContainerID,
|
||||
pub(crate) contents: RleVec<[Content; 1]>,
|
||||
pub(crate) contents: RleVec<[RemoteContent; 1]>,
|
||||
}
|
||||
|
||||
/// RichOp includes lamport and timestamp info, which is used for conflict resolution.
|
||||
|
@ -46,7 +46,7 @@ pub struct RichOp<'a> {
|
|||
|
||||
impl Op {
|
||||
#[inline]
|
||||
pub(crate) fn new(id: ID, content: Content, container: u32) -> Self {
|
||||
pub(crate) fn new(id: ID, content: RemoteContent, container: u32) -> Self {
|
||||
Op {
|
||||
counter: id.counter,
|
||||
content,
|
||||
|
@ -104,7 +104,7 @@ impl HasLength for Op {
|
|||
impl Sliceable for Op {
|
||||
fn slice(&self, from: usize, to: usize) -> Self {
|
||||
assert!(to > from);
|
||||
let content: Content = self.content.slice(from, to);
|
||||
let content: RemoteContent = self.content.slice(from, to);
|
||||
Op {
|
||||
counter: (self.counter + from as Counter),
|
||||
content,
|
||||
|
|
|
@ -3,7 +3,10 @@ use std::any::{Any, TypeId};
|
|||
use enum_as_inner::EnumAsInner;
|
||||
use rle::{HasLength, Mergable, Sliceable};
|
||||
|
||||
use crate::container::{list::list_op::ListOp, map::MapSet};
|
||||
use crate::container::{
|
||||
list::list_op::{InnerListOp, ListOp},
|
||||
map::{InnerMapSet, MapSet},
|
||||
};
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
|
||||
pub enum ContentType {
|
||||
|
@ -16,13 +19,20 @@ pub enum ContentType {
|
|||
}
|
||||
|
||||
#[derive(EnumAsInner, Debug)]
|
||||
pub enum Content {
|
||||
pub enum InnerContent {
|
||||
Unknown(usize),
|
||||
List(InnerListOp),
|
||||
Map(InnerMapSet),
|
||||
}
|
||||
|
||||
#[derive(EnumAsInner, Debug)]
|
||||
pub enum RemoteContent {
|
||||
Map(MapSet),
|
||||
List(ListOp),
|
||||
Dyn(Box<dyn InsertContentTrait>),
|
||||
}
|
||||
|
||||
impl Clone for Content {
|
||||
impl Clone for RemoteContent {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Self::Map(arg0) => Self::Map(arg0.clone()),
|
||||
|
@ -32,7 +42,7 @@ impl Clone for Content {
|
|||
}
|
||||
}
|
||||
|
||||
impl Content {
|
||||
impl RemoteContent {
|
||||
pub fn id(&self) -> ContentType {
|
||||
match self {
|
||||
Self::Map(_) => ContentType::Map,
|
||||
|
@ -90,35 +100,35 @@ impl<T: Mergable + Any> MergeableContent for T {
|
|||
}
|
||||
}
|
||||
|
||||
impl HasLength for Content {
|
||||
impl HasLength for RemoteContent {
|
||||
fn content_len(&self) -> usize {
|
||||
match self {
|
||||
Content::Map(x) => x.content_len(),
|
||||
Content::Dyn(x) => x.content_len(),
|
||||
Content::List(x) => x.content_len(),
|
||||
RemoteContent::Map(x) => x.content_len(),
|
||||
RemoteContent::Dyn(x) => x.content_len(),
|
||||
RemoteContent::List(x) => x.content_len(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sliceable for Content {
|
||||
impl Sliceable for RemoteContent {
|
||||
fn slice(&self, from: usize, to: usize) -> Self {
|
||||
match self {
|
||||
Content::Map(x) => Content::Map(x.slice(from, to)),
|
||||
Content::Dyn(x) => Content::Dyn(x.slice_content(from, to)),
|
||||
Content::List(x) => Content::List(x.slice(from, to)),
|
||||
RemoteContent::Map(x) => RemoteContent::Map(x.slice(from, to)),
|
||||
RemoteContent::Dyn(x) => RemoteContent::Dyn(x.slice_content(from, to)),
|
||||
RemoteContent::List(x) => RemoteContent::List(x.slice(from, to)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mergable for Content {
|
||||
impl Mergable for RemoteContent {
|
||||
fn is_mergable(&self, other: &Self, _conf: &()) -> bool
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
match (self, other) {
|
||||
(Content::Map(x), Content::Map(y)) => x.is_mergable(y, &()),
|
||||
(Content::List(x), Content::List(y)) => x.is_mergable(y, &()),
|
||||
(Content::Dyn(x), Content::Dyn(y)) => x.is_mergable_content(&**y),
|
||||
(RemoteContent::Map(x), RemoteContent::Map(y)) => x.is_mergable(y, &()),
|
||||
(RemoteContent::List(x), RemoteContent::List(y)) => x.is_mergable(y, &()),
|
||||
(RemoteContent::Dyn(x), RemoteContent::Dyn(y)) => x.is_mergable_content(&**y),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -128,15 +138,15 @@ impl Mergable for Content {
|
|||
Self: Sized,
|
||||
{
|
||||
match self {
|
||||
Content::Map(x) => match _other {
|
||||
Content::Map(y) => x.merge(y, &()),
|
||||
RemoteContent::Map(x) => match _other {
|
||||
RemoteContent::Map(y) => x.merge(y, &()),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Content::List(x) => match _other {
|
||||
Content::List(y) => x.merge(y, &()),
|
||||
RemoteContent::List(x) => match _other {
|
||||
RemoteContent::List(y) => x.merge(y, &()),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Content::Dyn(x) => x.merge_content(&**_other.as_dyn().unwrap()),
|
||||
RemoteContent::Dyn(x) => x.merge_content(&**_other.as_dyn().unwrap()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ fn size_of() {
|
|||
use crate::{
|
||||
container::{map::MapSet, text::text_content::ListSlice, ContainerID},
|
||||
id::ID,
|
||||
op::{Content, Op},
|
||||
op::{Op, RemoteContent},
|
||||
span::IdSpan,
|
||||
Container, InternalString,
|
||||
};
|
||||
|
@ -28,7 +28,7 @@ fn size_of() {
|
|||
|
||||
println!("Change {}", std::mem::size_of::<Change>());
|
||||
println!("Op {}", std::mem::size_of::<Op>());
|
||||
println!("InsertContent {}", std::mem::size_of::<Content>());
|
||||
println!("InsertContent {}", std::mem::size_of::<RemoteContent>());
|
||||
println!("MapSet {}", std::mem::size_of::<MapSet>());
|
||||
println!("ListSlice {}", std::mem::size_of::<ListSlice>());
|
||||
println!("Box {}", std::mem::size_of::<Box<dyn Container>>());
|
||||
|
|
Loading…
Reference in a new issue