diff --git a/crates/loro-core/src/container/map/map_container.rs b/crates/loro-core/src/container/map/map_container.rs index f1ee61d1..78976ee7 100644 --- a/crates/loro-core/src/container/map/map_container.rs +++ b/crates/loro-core/src/container/map/map_container.rs @@ -6,7 +6,7 @@ use crate::{ log_store::LogStoreWeakRef, op::{InsertContent, Op, RichOp}, op::{OpContent, RemoteOp}, - span::{HasId, IdSpan}, + span::IdSpan, value::{InsertValue, LoroValue}, version::TotalOrderStamp, InternalString, LogStore, @@ -57,7 +57,7 @@ impl MapContainer { let counter = id.counter; let container = store.get_container_idx(self_id).unwrap(); store.append_local_ops(&[Op { - id, + counter: id.counter, container, content: OpContent::Normal { content: InsertContent::Dyn(Box::new(MapSet { @@ -109,7 +109,7 @@ impl Container for MapContainer { let v: &MapSet = content.as_map().unwrap(); let order = TotalOrderStamp { lamport, - client_id: op.id_start().client_id, + client_id: id_span.client_id, }; if let Some(slot) = self.state.get_mut(&v.key) { if slot.order < order { @@ -123,7 +123,7 @@ impl Container for MapContainer { ValueSlot { value: v.value.clone(), order, - counter: op.id_start().counter, + counter: op.counter, }, ); diff --git a/crates/loro-core/src/container/text/text_container.rs b/crates/loro-core/src/container/text/text_container.rs index fcf1c016..2a1a6dde 100644 --- a/crates/loro-core/src/container/text/text_container.rs +++ b/crates/loro-core/src/container/text/text_container.rs @@ -1,6 +1,6 @@ use std::ops::Range; -use rle::{rle_tree::tree_trait::CumulateTreeTrait, RleTree, Sliceable}; +use rle::{rle_tree::tree_trait::CumulateTreeTrait, HasLength, RleTree, Sliceable}; use smallvec::{smallvec, SmallVec}; use crate::{ @@ -11,7 +11,7 @@ use crate::{ log_store::LogStoreWeakRef, op::{InsertContent, Op, OpContent, RemoteOp}, smstring::SmString, - span::{HasIdSpan, IdSpan}, + span::{HasCounter, HasCounterSpan, HasIdSpan, IdSpan}, value::LoroValue, LogStore, VersionVector, }; @@ -82,7 +82,10 @@ impl TextContainer { }, store.get_or_create_container_idx(&self.id), ); - let last_id = op.id_last(); + let last_id = ID::new( + store.this_client_id, + op.counter + op.atom_len() as Counter - 1, + ); store.append_local_ops(&[op]); self.head = smallvec![last_id]; self.vv.set_last(last_id); @@ -106,7 +109,7 @@ impl TextContainer { store.get_or_create_container_idx(&self.id), ); - let last_id = op.id_last(); + let last_id = ID::new(store.this_client_id, op.ctr_last()); store.append_local_ops(&[op]); self.state.delete_range(Some(pos), Some(pos + len)); self.head = smallvec![last_id]; @@ -198,7 +201,13 @@ impl Container for TextContainer { for op in change.ops.iter() { if op.container == self_idx { // TODO: convert op to local - self.tracker.apply(op.id, &op.content) + self.tracker.apply( + ID { + client_id: change.id.client_id, + counter: op.counter, + }, + &op.content, + ) } } } diff --git a/crates/loro-core/src/log_store.rs b/crates/loro-core/src/log_store.rs index 42b8de81..90018c31 100644 --- a/crates/loro-core/src/log_store.rs +++ b/crates/loro-core/src/log_store.rs @@ -19,7 +19,7 @@ use crate::{ id::{ClientID, Counter}, isomorph::{Irc, IsoRw, IsoWeak}, op::RemoteOp, - span::{HasIdSpan, HasLamportSpan, IdSpan}, + span::{HasCounterSpan, HasIdSpan, HasLamportSpan, IdSpan}, Lamport, Op, Timestamp, VersionVector, ID, }; @@ -257,7 +257,9 @@ impl LogStore { client_id: self.this_client_id, counter: self.get_next_counter(self.this_client_id), }; - let last_id = ops.last().unwrap().id_last(); + let last = ops.last().unwrap(); + let last_ctr = last.ctr_last(); + let last_id = ID::new(self.this_client_id, last_ctr); let change = Change { id, deps: std::mem::replace(&mut self.frontier, smallvec::smallvec![last_id]), diff --git a/crates/loro-core/src/log_store/iter.rs b/crates/loro-core/src/log_store/iter.rs index 155bb5e4..579514ea 100644 --- a/crates/loro-core/src/log_store/iter.rs +++ b/crates/loro-core/src/log_store/iter.rs @@ -1,7 +1,6 @@ use crate::Op; use crate::change::Lamport; -use crate::container::ContainerID; use crate::id::ClientID; use crate::id::ContainerIdx; @@ -93,7 +92,7 @@ impl<'a> Iterator for OpSpanIter<'a> { return Some(RichOp { op, - lamport: (op.id.counter - change.id.counter) as Lamport + change.lamport, + lamport: (op.counter - change.id.counter) as Lamport + change.lamport, timestamp: change.timestamp, }); } else { diff --git a/crates/loro-core/src/op.rs b/crates/loro-core/src/op.rs index eba6a63b..508ec170 100644 --- a/crates/loro-core/src/op.rs +++ b/crates/loro-core/src/op.rs @@ -2,7 +2,7 @@ use crate::{ change::{Lamport, Timestamp}, container::ContainerID, id::{Counter, ID}, - span::HasId, + span::HasCounter, LogStore, }; use rle::{HasIndex, HasLength, Mergable, Sliceable}; @@ -31,14 +31,14 @@ pub enum OpType { /// A Op may have multiple atomic operations, since Op can be merged. #[derive(Debug, Clone)] pub struct Op { - pub(crate) id: ID, + pub(crate) counter: Counter, pub(crate) container: u32, pub(crate) content: OpContent, } #[derive(Debug, Clone)] pub struct RemoteOp { - pub(crate) id: ID, + pub(crate) counter: Counter, pub(crate) container: ContainerID, pub(crate) content: OpContent, } @@ -47,7 +47,7 @@ impl Op { #[inline] pub(crate) fn new(id: ID, content: OpContent, container: u32) -> Self { Op { - id, + counter: id.counter, content, container, } @@ -69,7 +69,7 @@ impl Op { pub(crate) fn convert(self, log: &LogStore) -> RemoteOp { let container = log.get_container_id(self.container).clone(); RemoteOp { - id: self.id, + counter: self.counter, container, content: self.content, } @@ -78,11 +78,10 @@ impl Op { impl RemoteOp { pub(crate) fn convert(self, log: &mut LogStore) -> Op { - let id = self.id; let container = log.get_or_create_container_idx(&self.container); let content = self.content; Op { - id, + counter: self.counter, container, content, } @@ -91,7 +90,7 @@ impl RemoteOp { impl Mergable for Op { fn is_mergable(&self, other: &Self, cfg: &()) -> bool { - self.id.is_connected_id(&other.id, self.content_len()) + self.counter + self.content_len() as Counter == other.counter && self.content.is_mergable(&other.content, cfg) && self.container == other.container } @@ -135,10 +134,7 @@ impl Sliceable for Op { assert!(to > from); let content: OpContent = self.content.slice(from, to); Op { - id: ID { - client_id: self.id.client_id, - counter: (self.id.counter + from as Counter), - }, + counter: (self.counter + from as Counter), content, container: self.container.clone(), } @@ -147,7 +143,7 @@ impl Sliceable for Op { impl Mergable for RemoteOp { fn is_mergable(&self, other: &Self, cfg: &()) -> bool { - self.id.is_connected_id(&other.id, self.content_len()) + self.counter + self.content_len() as Counter == other.counter && self.content.is_mergable(&other.content, cfg) && self.container == other.container } @@ -191,22 +187,13 @@ impl Sliceable for RemoteOp { assert!(to > from); let content: OpContent = self.content.slice(from, to); RemoteOp { - id: ID { - client_id: self.id.client_id, - counter: (self.id.counter + from as Counter), - }, + counter: (self.counter + from as Counter), content, container: self.container.clone(), } } } -impl HasId for Op { - fn id_start(&self) -> ID { - self.id - } -} - pub struct RichOp<'a> { pub op: &'a Op, pub lamport: Lamport, @@ -217,7 +204,7 @@ impl HasIndex for Op { type Int = Counter; fn get_start_index(&self) -> Self::Int { - self.id.counter + self.counter } } @@ -225,6 +212,18 @@ impl HasIndex for RemoteOp { type Int = Counter; fn get_start_index(&self) -> Self::Int { - self.id.counter + self.counter + } +} + +impl HasCounter for Op { + fn ctr_start(&self) -> Counter { + self.counter + } +} + +impl HasCounter for RemoteOp { + fn ctr_start(&self) -> Counter { + self.counter } } diff --git a/crates/loro-core/src/span.rs b/crates/loro-core/src/span.rs index 8a8c4466..e7d3c06e 100644 --- a/crates/loro-core/src/span.rs +++ b/crates/loro-core/src/span.rs @@ -218,6 +218,36 @@ pub trait HasId { fn id_start(&self) -> ID; } +pub trait HasCounter { + fn ctr_start(&self) -> Counter; +} + +pub trait HasCounterSpan: HasCounter + HasLength { + fn ctr_end(&self) -> Counter { + self.ctr_start() + self.atom_len() as Counter + } + + fn ctr_last(&self) -> Counter { + self.ctr_start() + self.atom_len() as Counter - 1 + } + + fn ctr_span(&self) -> CounterSpan { + CounterSpan { + start: self.ctr_start(), + end: self.ctr_end(), + } + } +} + +impl HasCounterSpan for T {} + +impl HasCounter for T { + #[inline] + fn ctr_start(&self) -> Counter { + self.id_start().counter + } +} + pub trait HasIdSpan: HasId + HasLength { fn intersect(&self, other: &T) -> bool { let self_start = self.id_start(); @@ -250,14 +280,6 @@ pub trait HasIdSpan: HasId + HasLength { self.id_start().inc(self.content_len() as i32 - 1) } - fn ctr_last(&self) -> Counter { - self.id_start().counter + self.content_len() as i32 - 1 - } - - fn ctr_first(&self) -> Counter { - self.id_start().counter - } - fn contains_id(&self, id: ID) -> bool { let id_start = self.id_start(); if id.client_id != id_start.client_id {