feat: use ContainerTrait

fix: op counter
This commit is contained in:
leeeon233 2023-03-06 16:03:17 +08:00
parent 6fd81c8d20
commit 9fefd75fb6
18 changed files with 1702 additions and 130 deletions

View file

@ -5,15 +5,17 @@
//! Every [Container] can take a [Snapshot], which contains [crate::LoroValue] that describes the state.
//!
use crate::{
container::registry::ContainerWrapper,
event::{Observer, ObserverHandler, SubscriptionID},
hierarchy::Hierarchy,
log_store::ImportContext,
op::{InnerContent, Op, RemoteContent, RichOp},
transaction::op::TransactionOp,
version::PatchedVersionVector,
InternalString, LogStore, LoroError, LoroValue, ID,
InternalString, List, LogStore, LoroCore, LoroError, LoroValue, Map, Text, ID,
};
use enum_as_inner::EnumAsInner;
use serde::{Deserialize, Serialize};
use smallvec::SmallVec;
@ -46,6 +48,49 @@ pub enum ContainerType {
// Custom(u16),
}
#[derive(Debug, EnumAsInner)]
pub enum Container {
Text(Text),
Map(Map),
List(List),
}
impl Container {
pub fn idx(&self) -> ContainerIdx {
match self {
Container::List(x) => x.idx(),
Container::Map(x) => x.idx(),
Container::Text(x) => x.idx(),
}
}
pub fn type_(&self) -> ContainerType {
match self {
Container::List(_x) => ContainerType::List,
Container::Map(_x) => ContainerType::Map,
Container::Text(_x) => ContainerType::Text,
}
}
}
impl From<List> for Container {
fn from(value: List) -> Self {
Container::List(value)
}
}
impl From<Map> for Container {
fn from(value: Map) -> Self {
Container::Map(value)
}
}
impl From<Text> for Container {
fn from(value: Text) -> Self {
Container::Text(value)
}
}
impl Display for ContainerType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
@ -71,7 +116,7 @@ impl TryFrom<&str> for ContainerType {
}
}
pub trait Container: Debug + Any + Unpin + Send + Sync {
pub trait ContainerTrait: Debug + Any + Unpin + Send + Sync {
fn id(&self) -> &ContainerID;
fn idx(&self) -> ContainerIdx;
fn type_(&self) -> ContainerType;

View file

@ -20,19 +20,20 @@ use crate::{
text_content::{ListSlice, SliceRange},
tracker::{Effect, Tracker},
},
Container, ContainerID, ContainerType,
ContainerID, ContainerTrait, ContainerType,
},
context::Context,
delta::{Delta, DeltaItem},
event::{Diff, Index},
hierarchy::Hierarchy,
id::{ClientID, Counter},
id::{ClientID, Counter, ID},
log_store::ImportContext,
op::{InnerContent, Op, RemoteContent, RichOp},
prelim::Prelim,
transaction::op::{ListTxnOps, TransactionOp},
value::LoroValue,
version::PatchedVersionVector,
LogStore, LoroError, Transact,
Container, LogStore, LoroCore, LoroError, Map, Text, Transact,
};
use super::list_op::InnerListOp;
@ -64,18 +65,24 @@ impl ListContainer {
fn apply_txn_op_impl(&mut self, store: &mut LogStore, op: &ListTxnOps) -> Vec<Op> {
let mut index = 0;
let mut ops = Vec::new();
let id = store.next_id();
let mut offset = 0;
for item in op.items() {
let item = item.clone().into_event_format();
match item {
DeltaItem::Retain { len, .. } => index += len,
DeltaItem::Insert { value, .. } => {
let len = value.len();
let op = self.apply_batch_insert(index, value, store);
let id = id.inc(offset);
offset += 1;
let op = self.apply_batch_insert(index, value, id);
index += len;
ops.push(op);
}
DeltaItem::Delete(len) => {
let op = self.apply_delete(index, len, store);
let id = id.inc(offset);
offset += 1;
let op = self.apply_delete(index, len, id);
ops.push(op);
}
}
@ -83,13 +90,7 @@ impl ListContainer {
ops
}
fn apply_batch_insert(
&mut self,
pos: usize,
values: Vec<LoroValue>,
store: &mut LogStore,
) -> Op {
let id = store.next_id();
fn apply_batch_insert(&mut self, pos: usize, values: Vec<LoroValue>, id: ID) -> Op {
let slice = self.raw_data.alloc_arr(values);
self.state.insert(pos, slice.clone().into());
Op::new(
@ -102,8 +103,7 @@ impl ListContainer {
)
}
fn apply_delete(&mut self, pos: usize, len: usize, store: &mut LogStore) -> Op {
let id = store.next_id();
fn apply_delete(&mut self, pos: usize, len: usize, id: ID) -> Op {
self.state.delete_range(Some(pos), Some(pos + len));
Op::new(
id,
@ -191,7 +191,7 @@ impl ListContainer {
}
}
impl Container for ListContainer {
impl ContainerTrait for ListContainer {
#[inline(always)]
fn id(&self) -> &ContainerID {
&self.id
@ -495,7 +495,10 @@ pub struct List {
}
impl List {
pub fn from_instance(instance: Weak<Mutex<ContainerInstance>>, client_id: ClientID) -> Self {
pub(crate) fn from_instance(
instance: Weak<Mutex<ContainerInstance>>,
client_id: ClientID,
) -> Self {
let container_idx = instance.upgrade().unwrap().try_lock().unwrap().idx();
Self {
container: ContainerInner::from(instance),
@ -504,7 +507,7 @@ impl List {
}
}
pub fn from_idx(idx: ContainerIdx, client_id: ClientID) -> Self {
pub(crate) fn from_idx(idx: ContainerIdx, client_id: ClientID) -> Self {
Self {
container: ContainerInner::from(ContainerTemp::new(idx, ContainerType::List)),
client_id,
@ -523,18 +526,23 @@ impl List {
txn: &T,
pos: usize,
value: P,
) -> Result<Option<ContainerTemp>, LoroError> {
) -> Result<Option<Container>, LoroError> {
self.with_transaction_checked(txn, |txn, _x| {
let (value, maybe_container) = value.convert_value()?;
if let Some(prelim) = maybe_container {
let idx = txn.next_container_idx();
let type_ = value.into_container().unwrap();
let idx = txn.next_container_idx();
txn.push(
TransactionOp::insert_list_container(self.idx(), pos, type_, idx),
Some(idx),
)?;
prelim.integrate(txn, idx)?;
Ok(Some(ContainerTemp::new(idx, type_)))
let container = match type_ {
ContainerType::List => Container::from(List::from_idx(idx, self.client_id)),
ContainerType::Map => Container::from(Map::from_idx(idx, self.client_id)),
ContainerType::Text => Container::from(Text::from_idx(idx, self.client_id)),
};
Ok(Some(container))
} else {
let value = value.into_value().unwrap();
txn.push(
@ -566,7 +574,7 @@ impl List {
&mut self,
txn: &T,
value: P,
) -> Result<Option<ContainerTemp>, LoroError> {
) -> Result<Option<Container>, LoroError> {
let pos = self.len();
self.insert(txn, pos, value)
}
@ -576,7 +584,7 @@ impl List {
&mut self,
txn: &T,
value: P,
) -> Result<Option<ContainerTemp>, LoroError> {
) -> Result<Option<Container>, LoroError> {
let pos = 0;
self.insert(txn, pos, value)
}
@ -670,6 +678,10 @@ impl ContainerWrapper for List {
Ok(f(list))
}
fn is_instance(&self) -> bool {
matches!(self.container, ContainerInner::Instance(_))
}
fn client_id(&self) -> ClientID {
self.client_id
}
@ -677,6 +689,14 @@ impl ContainerWrapper for List {
fn container_inner(&self) -> &ContainerInner {
&self.container
}
fn try_to_update(&mut self, loro: &LoroCore) {
if !self.is_instance() {
let idx = self.idx();
let new = loro.get_list_by_idx(&idx).unwrap();
*self = new;
}
}
}
#[cfg(test)]

View file

@ -8,9 +8,10 @@ use crate::{
temp::ContainerTemp,
},
delta::MapDiff,
id::ID,
op::OwnedRichOp,
transaction::op::{MapTxnOps, TransactionOp},
LogStore, LoroError, Transact,
Container, List, LogStore, LoroCore, LoroError, Text, Transact,
};
use fxhash::FxHashMap;
use smallvec::{smallvec, SmallVec};
@ -18,7 +19,7 @@ use smallvec::{smallvec, SmallVec};
use crate::{
container::{
registry::{ContainerInstance, ContainerWrapper},
Container, ContainerID, ContainerType,
ContainerID, ContainerTrait, ContainerType,
},
event::{Diff, Index},
hierarchy::Hierarchy,
@ -67,8 +68,13 @@ impl MapContainer {
}
}
fn apply_insert(&mut self, store: &mut LogStore, key: InternalString, value: LoroValue) -> Op {
let id = store.next_id();
fn apply_insert(
&mut self,
key: InternalString,
value: LoroValue,
id: ID,
store: &mut LogStore,
) -> Op {
let value_index = self.pool.alloc(value).start;
let order = TotalOrderStamp {
client_id: store.this_client_id,
@ -94,11 +100,17 @@ impl MapContainer {
fn apply_txn_op_impl(&mut self, store: &mut LogStore, ops: &MapTxnOps) -> Vec<Op> {
let ops = ops.clone();
let mut store_ops = Vec::with_capacity(ops.added.len() + ops.deleted.len());
let mut offset = 0;
let id = store.next_id();
for (k, v) in ops.added.into_iter() {
store_ops.push(self.apply_insert(store, k, v.into_value().unwrap()));
let id = id.inc(offset);
offset += 1;
store_ops.push(self.apply_insert(k, v.into_value().unwrap(), id, store));
}
for k in ops.deleted {
store_ops.push(self.apply_insert(store, k, LoroValue::Null));
let id = id.inc(offset);
offset += 1;
store_ops.push(self.apply_insert(k, LoroValue::Null, id, store));
}
store_ops
}
@ -141,6 +153,10 @@ impl MapContainer {
self.get_value().resolve_deep(reg)
}
pub fn len(&self) -> usize {
self.state.len()
}
pub fn keys(&self) -> Vec<InternalString> {
self.state.keys().cloned().collect()
}
@ -157,7 +173,7 @@ impl MapContainer {
}
}
impl Container for MapContainer {
impl ContainerTrait for MapContainer {
#[inline(always)]
fn id(&self) -> &ContainerID {
&self.id
@ -390,7 +406,10 @@ pub struct Map {
}
impl Map {
pub fn from_instance(instance: Weak<Mutex<ContainerInstance>>, client_id: ClientID) -> Self {
pub(crate) fn from_instance(
instance: Weak<Mutex<ContainerInstance>>,
client_id: ClientID,
) -> Self {
let container_idx = instance.upgrade().unwrap().try_lock().unwrap().idx();
Self {
container: ContainerInner::from(instance),
@ -399,7 +418,7 @@ impl Map {
}
}
pub fn from_idx(idx: ContainerIdx, client_id: ClientID) -> Self {
pub(crate) fn from_idx(idx: ContainerIdx, client_id: ClientID) -> Self {
Self {
container: ContainerInner::from(ContainerTemp::new(idx, ContainerType::Map)),
client_id,
@ -417,7 +436,7 @@ impl Map {
txn: &T,
key: &str,
value: V,
) -> Result<Option<ContainerTemp>, LoroError> {
) -> Result<Option<Container>, LoroError> {
self.with_transaction_checked(txn, |txn, _| {
let (value, maybe_container) = value.convert_value()?;
if let Some(prelim) = maybe_container {
@ -428,7 +447,12 @@ impl Map {
Some(idx),
)?;
prelim.integrate(txn, idx)?;
Ok(Some(ContainerTemp::new(idx, type_)))
let container = match type_ {
ContainerType::List => Container::from(List::from_idx(idx, self.client_id)),
ContainerType::Map => Container::from(Map::from_idx(idx, self.client_id)),
ContainerType::Text => Container::from(Text::from_idx(idx, self.client_id)),
};
Ok(Some(container))
} else {
let value = value.into_value().unwrap();
txn.push(
@ -458,8 +482,12 @@ impl Map {
self.with_container(|map| map.get(&key.into()).cloned())
}
pub fn keys(&self) -> Vec<String> {
todo!()
/// Need clone
pub fn keys(&self) -> Vec<InternalString> {
match &self.container {
ContainerInner::Instance(_) => self.with_container(|x| x.keys()).unwrap(),
ContainerInner::Temp(temp) => temp.as_map().unwrap().keys(),
}
}
pub fn values(&self) -> Result<Vec<LoroValue>, LoroError> {
@ -491,7 +519,10 @@ impl Map {
}
pub fn len(&self) -> usize {
todo!()
match &self.container {
ContainerInner::Instance(_) => self.with_container(|x| x.len()).unwrap(),
ContainerInner::Temp(temp) => temp.as_map().unwrap().len(),
}
}
#[must_use]
@ -507,6 +538,18 @@ impl ContainerWrapper for Map {
self.client_id
}
fn is_instance(&self) -> bool {
matches!(self.container, ContainerInner::Instance(_))
}
fn try_to_update(&mut self, loro: &LoroCore) {
if !self.is_instance() {
let idx = self.idx();
let new = loro.get_map_by_idx(&idx).unwrap();
*self = new;
}
}
fn container_inner(&self) -> &ContainerInner {
&self.container
}

View file

@ -22,12 +22,12 @@ use crate::{
op::{Op, RemoteContent, RichOp},
transaction::{op::TransactionOp, Transaction},
version::PatchedVersionVector,
LogStore, LoroError, LoroValue, Transact,
LogStore, LoroCore, LoroError, LoroValue, Transact,
};
use super::{
list::ListContainer, map::MapContainer, pool_mapping::StateContent, temp::ContainerTemp,
text::TextContainer, Container, ContainerID, ContainerType,
text::TextContainer, ContainerID, ContainerTrait, ContainerType,
};
#[derive(Debug, Clone, EnumAsInner)]
@ -45,15 +45,6 @@ impl ContainerInner {
}
}
// impl Clone for ContainerInner {
// fn clone(&self) -> Self {
// match self {
// ContainerInner::Instance(weak) => ContainerInner::Instance(Weak::clone(weak)),
// ContainerInner::Temp(x) => ContainerInner::Temp(*x.clone()),
// }
// }
// }
impl From<Weak<Mutex<ContainerInstance>>> for ContainerInner {
fn from(value: Weak<Mutex<ContainerInstance>>) -> Self {
Self::Instance(value)
@ -85,16 +76,16 @@ pub enum ContainerInstance {
List(Box<ListContainer>),
Text(Box<TextContainer>),
Map(Box<MapContainer>),
Dyn(Box<dyn Container>),
Dyn(Box<dyn ContainerTrait>),
}
impl Container for ContainerInstance {
impl ContainerTrait for ContainerInstance {
fn id(&self) -> &ContainerID {
match self {
ContainerInstance::Map(x) => x.id(),
ContainerInstance::Text(x) => x.id(),
ContainerInstance::Dyn(x) => x.id(),
ContainerInstance::List(x) => x.id(),
ContainerInstance::Dyn(x) => x.id(),
}
}
@ -102,8 +93,8 @@ impl Container for ContainerInstance {
match self {
ContainerInstance::Map(x) => x.idx(),
ContainerInstance::Text(x) => x.idx(),
ContainerInstance::Dyn(x) => x.idx(),
ContainerInstance::List(x) => x.idx(),
ContainerInstance::Dyn(x) => x.idx(),
}
}
@ -121,8 +112,8 @@ impl Container for ContainerInstance {
match self {
ContainerInstance::Map(x) => x.tracker_init(vv),
ContainerInstance::Text(x) => x.tracker_init(vv),
ContainerInstance::Dyn(x) => x.tracker_init(vv),
ContainerInstance::List(x) => x.tracker_init(vv),
ContainerInstance::Dyn(x) => x.tracker_init(vv),
}
}
@ -131,8 +122,8 @@ impl Container for ContainerInstance {
match self {
ContainerInstance::Map(x) => x.tracker_checkout(vv),
ContainerInstance::Text(x) => x.tracker_checkout(vv),
ContainerInstance::Dyn(x) => x.tracker_checkout(vv),
ContainerInstance::List(x) => x.tracker_checkout(vv),
ContainerInstance::Dyn(x) => x.tracker_checkout(vv),
}
}
@ -141,8 +132,8 @@ impl Container for ContainerInstance {
match self {
ContainerInstance::Map(x) => x.get_value(),
ContainerInstance::Text(x) => x.get_value(),
ContainerInstance::Dyn(x) => x.get_value(),
ContainerInstance::List(x) => x.get_value(),
ContainerInstance::Dyn(x) => x.get_value(),
}
}
@ -156,8 +147,8 @@ impl Container for ContainerInstance {
match self {
ContainerInstance::Map(x) => x.update_state_directly(hierarchy, op, context),
ContainerInstance::Text(x) => x.update_state_directly(hierarchy, op, context),
ContainerInstance::Dyn(x) => x.update_state_directly(hierarchy, op, context),
ContainerInstance::List(x) => x.update_state_directly(hierarchy, op, context),
ContainerInstance::Dyn(x) => x.update_state_directly(hierarchy, op, context),
}
}
@ -166,8 +157,8 @@ impl Container for ContainerInstance {
match self {
ContainerInstance::Map(x) => x.track_apply(hierarchy, op, ctx),
ContainerInstance::Text(x) => x.track_apply(hierarchy, op, ctx),
ContainerInstance::Dyn(x) => x.track_apply(hierarchy, op, ctx),
ContainerInstance::List(x) => x.track_apply(hierarchy, op, ctx),
ContainerInstance::Dyn(x) => x.track_apply(hierarchy, op, ctx),
}
}
@ -180,8 +171,8 @@ impl Container for ContainerInstance {
match self {
ContainerInstance::Map(x) => x.apply_tracked_effects_from(h, import_context),
ContainerInstance::Text(x) => x.apply_tracked_effects_from(h, import_context),
ContainerInstance::Dyn(x) => x.apply_tracked_effects_from(h, import_context),
ContainerInstance::List(x) => x.apply_tracked_effects_from(h, import_context),
ContainerInstance::Dyn(x) => x.apply_tracked_effects_from(h, import_context),
}
}
@ -194,8 +185,8 @@ impl Container for ContainerInstance {
match self {
ContainerInstance::Map(x) => x.to_export(content, gc),
ContainerInstance::Text(x) => x.to_export(content, gc),
ContainerInstance::Dyn(x) => x.to_export(content, gc),
ContainerInstance::List(x) => x.to_export(content, gc),
ContainerInstance::Dyn(x) => x.to_export(content, gc),
}
}
@ -204,8 +195,8 @@ impl Container for ContainerInstance {
match self {
ContainerInstance::Map(x) => x.to_import(content),
ContainerInstance::Text(x) => x.to_import(content),
ContainerInstance::Dyn(x) => x.to_import(content),
ContainerInstance::List(x) => x.to_import(content),
ContainerInstance::Dyn(x) => x.to_import(content),
}
}
@ -217,8 +208,8 @@ impl Container for ContainerInstance {
match self {
ContainerInstance::Map(x) => x.to_export_snapshot(content, gc),
ContainerInstance::Text(x) => x.to_export_snapshot(content, gc),
ContainerInstance::Dyn(x) => x.to_export_snapshot(content, gc),
ContainerInstance::List(x) => x.to_export_snapshot(content, gc),
ContainerInstance::Dyn(x) => x.to_export_snapshot(content, gc),
}
}
@ -226,8 +217,8 @@ impl Container for ContainerInstance {
match self {
ContainerInstance::Map(x) => x.initialize_pool_mapping(),
ContainerInstance::Text(x) => x.initialize_pool_mapping(),
ContainerInstance::Dyn(x) => x.initialize_pool_mapping(),
ContainerInstance::List(x) => x.initialize_pool_mapping(),
ContainerInstance::Dyn(x) => x.initialize_pool_mapping(),
}
}
@ -235,8 +226,8 @@ impl Container for ContainerInstance {
match self {
ContainerInstance::Map(x) => x.encode_and_release_pool_mapping(),
ContainerInstance::Text(x) => x.encode_and_release_pool_mapping(),
ContainerInstance::Dyn(x) => x.encode_and_release_pool_mapping(),
ContainerInstance::List(x) => x.encode_and_release_pool_mapping(),
ContainerInstance::Dyn(x) => x.encode_and_release_pool_mapping(),
}
}
@ -249,8 +240,8 @@ impl Container for ContainerInstance {
match self {
ContainerInstance::Map(x) => x.to_import_snapshot(state_content, hierarchy, ctx),
ContainerInstance::Text(x) => x.to_import_snapshot(state_content, hierarchy, ctx),
ContainerInstance::Dyn(x) => x.to_import_snapshot(state_content, hierarchy, ctx),
ContainerInstance::List(x) => x.to_import_snapshot(state_content, hierarchy, ctx),
ContainerInstance::Dyn(x) => x.to_import_snapshot(state_content, hierarchy, ctx),
}
}
@ -368,8 +359,7 @@ impl ContainerRegistry {
#[inline(always)]
pub(crate) fn next_idx_and_add_1(&self) -> ContainerIdx {
let idx = self.next_container_idx.fetch_add(1, Ordering::SeqCst);
let ans = ContainerIdx::from_u32(idx);
ans
ContainerIdx::from_u32(idx)
}
pub(crate) fn register(&mut self, id: &ContainerID) -> ContainerIdx {
@ -438,7 +428,7 @@ impl ContainerRegistry {
pub(crate) fn export(&self) -> (&FxHashMap<ContainerID, ContainerIdx>, Vec<ContainerID>) {
(
&self.container_to_idx,
self.containers.iter().map(|(_, x)| x.id.clone()).collect(),
self.containers.values().map(|x| x.id.clone()).collect(),
)
}
}
@ -488,7 +478,12 @@ pub trait LockContainer {
}
pub trait ContainerWrapper {
type Container: Container;
type Container: ContainerTrait;
fn is_instance(&self) -> bool;
/// If Container is temporary, convert it to ContainerInstance
fn try_to_update(&mut self, loro: &LoroCore);
fn container_inner(&self) -> &ContainerInner;

View file

@ -79,8 +79,12 @@ impl MapTemp {
checker: MapChecker::from_idx(idx),
}
}
pub(crate) fn keys(&self) -> &FxHashSet<InternalString> {
&self.checker.keys
pub(crate) fn keys(&self) -> Vec<InternalString> {
self.checker.keys.iter().cloned().collect()
}
pub(crate) fn len(&self) -> usize {
self.checker.keys.len()
}
}

View file

@ -11,18 +11,18 @@ use crate::{
pool_mapping::{PoolMapping, StateContent},
registry::{ContainerIdx, ContainerInner, ContainerInstance, ContainerWrapper},
temp::ContainerTemp,
Container, ContainerID, ContainerType,
ContainerID, ContainerTrait, ContainerType,
},
delta::{Delta, DeltaItem},
event::Diff,
hierarchy::Hierarchy,
id::{ClientID, Counter},
id::{ClientID, Counter, ID},
log_store::ImportContext,
op::{InnerContent, Op, RemoteContent, RichOp},
transaction::op::{TextTxnOps, TransactionOp},
value::LoroValue,
version::PatchedVersionVector,
LogStore, LoroError, Transact,
LogStore, LoroCore, LoroError, Transact,
};
use super::{
@ -57,17 +57,23 @@ impl TextContainer {
pub(crate) fn apply_txn_op_impl(&mut self, store: &mut LogStore, op: &TextTxnOps) -> Vec<Op> {
let mut index = 0;
let mut ops = Vec::new();
let mut offset = 0;
let id = store.next_id();
for item in op.items() {
match item {
DeltaItem::Retain { len, .. } => index += len,
DeltaItem::Insert { value, .. } => {
let len = value.len();
let op = self.apply_insert(index, value, store);
let id = id.inc(offset);
offset += 1;
let op = self.apply_insert(index, value, id);
index += len;
ops.push(op);
}
DeltaItem::Delete(len) => {
let op = self.apply_delete(index, *len, store);
let id = id.inc(offset);
offset += 1;
let op = self.apply_delete(index, *len, id);
ops.push(op);
}
}
@ -75,11 +81,10 @@ impl TextContainer {
ops
}
pub(crate) fn apply_insert(&mut self, pos: usize, text: &str, store: &mut LogStore) -> Op {
pub(crate) fn apply_insert(&mut self, pos: usize, text: &str, id: ID) -> Op {
if self.state.len() < pos {
panic!("insert index out of range");
}
let id = store.next_id();
let slice = self.raw_str.alloc(text);
let op_slice = SliceRange::from_pool_string(&slice);
self.state.insert(pos, slice);
@ -93,11 +98,10 @@ impl TextContainer {
)
}
pub(crate) fn apply_delete(&mut self, pos: usize, len: usize, store: &mut LogStore) -> Op {
pub(crate) fn apply_delete(&mut self, pos: usize, len: usize, id: ID) -> Op {
if self.state.len() < pos + len {
panic!("deletion out of range");
}
let id = store.next_id();
self.state.delete_range(Some(pos), Some(pos + len));
Op::new(
id,
@ -132,7 +136,7 @@ impl TextContainer {
}
}
impl Container for TextContainer {
impl ContainerTrait for TextContainer {
#[inline(always)]
fn id(&self) -> &ContainerID {
&self.id
@ -567,6 +571,18 @@ impl ContainerWrapper for Text {
self.client_id
}
fn is_instance(&self) -> bool {
matches!(self.container, ContainerInner::Instance(_))
}
fn try_to_update(&mut self, loro: &LoroCore) {
if !self.is_instance() {
let idx = self.idx();
let new = loro.get_text_by_idx(&idx).unwrap();
*self = new;
}
}
fn container_inner(&self) -> &ContainerInner {
&self.container
}

View file

@ -4,6 +4,7 @@ use debug_log::debug_log;
use enum_as_inner::EnumAsInner;
use tabled::{TableIteratorExt, Tabled};
pub mod recursive;
pub mod recursive_txn;
use crate::{
array_mut_ref, id::ClientID, log_store::EncodeConfig, LoroCore, Transact, VersionVector,

View file

@ -16,7 +16,7 @@ use crate::{
event::{Diff, Observer},
id::ClientID,
log_store::EncodeConfig,
ContainerType, List, LoroCore, LoroValue, Map, Text, Transact,
Container, ContainerType, List, LoroCore, LoroValue, Map, Text, Transact,
};
#[derive(Arbitrary, EnumAsInner, Clone, PartialEq, Eq, Debug)]
@ -262,7 +262,7 @@ trait Actionable {
}
impl Actor {
fn add_new_container(&mut self, container: ContainerTemp) {
fn add_new_container(&mut self, container: Container) {
let new = container.idx();
let type_ = container.type_();
let store = self.loro.log_store.try_read().unwrap();

File diff suppressed because it is too large Load diff

View file

@ -42,7 +42,7 @@ pub(crate) use op::{ContentType, InsertContentTrait, Op};
// TODO: rename as Key?
pub(crate) type InternalString = DefaultAtom;
pub(crate) use container::Container;
pub use container::{Container, ContainerTrait};
pub use container::{list::List, map::Map, text::Text, ContainerType};
pub use log_store::LogStore;

View file

@ -15,7 +15,7 @@ use crate::{
map::{InnerMapSet, ValueSlot},
pool_mapping::StateContent,
registry::ContainerIdx,
Container, ContainerID,
ContainerID, ContainerTrait,
},
dag::remove_included_frontiers,
event::RawEvent,

View file

@ -16,7 +16,7 @@ use fxhash::{FxHashMap, FxHashSet};
use rle::{slice_vec_by, HasLength, RleVecWithIndex};
use crate::{
container::{registry::ContainerInstance, Container, ContainerID},
container::{registry::ContainerInstance, ContainerID, ContainerTrait},
dag::{remove_included_frontiers, DagUtils},
op::RichOp,
span::{HasCounter, HasIdSpan, HasLamportSpan, IdSpan},

View file

@ -1,7 +1,7 @@
use std::sync::{Arc, Mutex, RwLock};
use crate::{
container::{temp::ContainerTemp, ContainerID},
container::{registry::ContainerIdx, temp::ContainerTemp, ContainerID},
context::Context,
event::{ObserverHandler, RawEvent},
hierarchy::Hierarchy,
@ -76,21 +76,21 @@ impl LoroCore {
Text::from_instance(instance, cid)
}
pub fn get_list_by_temp(&self, temp_container: ContainerTemp) -> Option<List> {
pub fn get_list_by_idx(&self, idx: &ContainerIdx) -> Option<List> {
let cid = self.client_id();
self.get_container_by_idx(&temp_container.idx())
self.get_container_by_idx(idx)
.map(|i| List::from_instance(i, cid))
}
pub fn get_map_by_temp(&self, temp_container: ContainerTemp) -> Option<Map> {
pub fn get_map_by_idx(&self, idx: &ContainerIdx) -> Option<Map> {
let cid = self.client_id();
self.get_container_by_idx(&temp_container.idx())
self.get_container_by_idx(idx)
.map(|i| Map::from_instance(i, cid))
}
pub fn get_text_by_temp(&self, temp_container: ContainerTemp) -> Option<Text> {
pub fn get_text_by_idx(&self, idx: &ContainerIdx) -> Option<Text> {
let cid = self.client_id();
self.get_container_by_idx(&temp_container.idx())
self.get_container_by_idx(idx)
.map(|i| Text::from_instance(i, cid))
}

View file

@ -2,7 +2,7 @@ use crate::{
change::{Change, Lamport, Timestamp},
container::{
registry::{ContainerIdx, ContainerInstance},
Container, ContainerID,
ContainerID, ContainerTrait,
},
id::{ClientID, Counter, ID},
span::{HasCounter, HasId, HasLamport},

View file

@ -16,11 +16,11 @@ pub const PROPTEST_FACTOR_1: usize = 0;
fn size_of() {
use crate::change::Change;
use crate::{
container::{map::MapSet, text::text_content::ListSlice, ContainerID},
container::{map::MapSet, text::text_content::ListSlice, ContainerID, ContainerTrait},
id::ID,
op::{Op, RemoteContent},
span::IdSpan,
Container, InternalString,
InternalString,
};
use std::ops::Range;
@ -31,7 +31,7 @@ fn size_of() {
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>>());
println!("Box {}", std::mem::size_of::<Box<dyn ContainerTrait>>());
println!("LoroValue {}", std::mem::size_of::<LoroValue>());
println!("ID {}", std::mem::size_of::<ID>());
println!("Vec {}", std::mem::size_of::<Vec<ID>>());

View file

@ -6,7 +6,7 @@ use std::{
use fxhash::{FxHashMap, FxHashSet};
use crate::{
container::{registry::ContainerIdx, Container, ContainerID},
container::{registry::ContainerIdx, ContainerID, ContainerTrait},
event::{Diff, RawEvent},
hierarchy::Hierarchy,
id::ClientID,
@ -104,19 +104,6 @@ impl Transaction {
Ok(())
}
pub(crate) fn get_container_idx_by_id(&self, id: &ContainerID) -> Option<ContainerIdx> {
self.with_store(|store| store.reg.get_idx(id))
}
fn with_store<F, R>(&self, f: F) -> R
where
F: FnOnce(&LogStore) -> R,
{
let store = self.store.upgrade().unwrap();
let store = store.read().unwrap();
f(&store)
}
fn with_store_hierarchy_mut<F, R>(&self, f: F) -> R
where
F: FnOnce(&Self, &mut LogStore, &mut Hierarchy) -> R,
@ -130,6 +117,7 @@ impl Transaction {
fn apply_ops_emit_event(&mut self) {
let compressed_op = std::mem::take(&mut self.compressed_op);
println!("compressed op {:?}", compressed_op);
let events = self.with_store_hierarchy_mut(|_txn, store, hierarchy| {
let mut events = Vec::with_capacity(compressed_op.len());
for op in compressed_op {
@ -140,6 +128,7 @@ impl Transaction {
let container_id = container.id().clone();
let type_ = container_id.container_type();
let store_ops = container.apply_txn_op(store, &op);
println!("store ops: {:?}", store_ops);
drop(container);
let (old_version, new_version) = store.append_local_ops(&store_ops);
let new_version = new_version.into();
@ -209,7 +198,13 @@ impl Transaction {
) -> ContainerID {
self.with_store_hierarchy_mut(|_txn, s, h| {
let id = s.next_id();
let container_id = ContainerID::new_normal(id, type_);
let mut container_id = ContainerID::new_normal(id, type_);
while s.reg.contains(&container_id) {
if let ContainerID::Normal { id, .. } = &mut container_id {
id.counter += 1;
}
}
let parent_id = s.reg.get_id(parent_idx).unwrap();
h.add_child(parent_id, &container_id);

View file

@ -8,7 +8,7 @@ use crate::{
container::{registry::ContainerRegistry, ContainerID},
delta::DeltaItem,
event::{Diff, Index, Path},
Container,
ContainerTrait,
};
/// [LoroValue] is used to represents the state of CRDT at a given version

View file

@ -6,7 +6,7 @@ use loro_internal::context::Context;
use loro_internal::id::ID;
use loro_internal::log_store::EncodeConfig;
use loro_internal::{ContainerType, LoroCore, Text, Transact, VersionVector};
use loro_internal::{ContainerType, LoroCore, Text, VersionVector};
#[test]
fn send_sync() {
@ -47,13 +47,18 @@ fn example() {
let mut doc = LoroCore::default();
let mut list = doc.get_list("list");
list.insert(&doc, 0, 123).unwrap();
let map_id = list.insert(&doc, 1, ContainerType::Map).unwrap().unwrap();
let mut map = doc.get_map_by_temp(map_id).unwrap();
let map_id = list
.insert(&doc, 1, ContainerType::Map)
.unwrap()
.unwrap()
.idx();
let mut map = doc.get_map_by_idx(&map_id).unwrap();
let text = map
.insert(&doc, "map_b", ContainerType::Text)
.unwrap()
.unwrap();
let mut text = doc.get_text_by_temp(text).unwrap();
.unwrap()
.idx();
let mut text = doc.get_text_by_idx(&text).unwrap();
text.insert(&doc, 0, "world!").unwrap();
text.insert(&doc, 0, "hello ").unwrap();
assert_eq!(
@ -91,10 +96,15 @@ fn text_observe() {
let list = map
.insert(&doc, "to-dos", ContainerType::List)
.unwrap()
.unwrap();
let mut list = doc.get_list_by_temp(list).unwrap();
let todo_item = list.insert(&doc, 0, ContainerType::Map).unwrap().unwrap();
let mut todo_item = doc.get_map_by_temp(todo_item).unwrap();
.unwrap()
.idx();
let mut list = doc.get_list_by_idx(&list).unwrap();
let todo_item = list
.insert(&doc, 0, ContainerType::Map)
.unwrap()
.unwrap()
.idx();
let mut todo_item = doc.get_map_by_idx(&todo_item).unwrap();
todo_item.insert(&doc, "todo", "coding").unwrap();
assert_eq!(&doc.to_json(), &*track_value.lock().unwrap());
let mut text = doc.get_text("text");
@ -123,8 +133,9 @@ fn list() {
let map_id = list_b
.insert(&loro_b, 1, loro_internal::ContainerType::Map)
.unwrap()
.unwrap();
let mut map = loro_b.get_map_by_temp(map_id).unwrap();
.unwrap()
.idx();
let mut map = loro_b.get_map_by_idx(&map_id).unwrap();
map.insert(&loro_b, "map_b", 123).unwrap();
println!("{}", list_a.get_value().to_json());
println!("{}", list_b.get_value().to_json());
@ -158,11 +169,9 @@ fn map() {
let map_id = root
.insert(&loro, "map", loro_internal::ContainerType::Map)
.unwrap()
.unwrap()
.idx();
.unwrap();
drop(root);
let sub_map = loro.get_container_by_idx(&map_id).unwrap();
let mut sub_map = Map::from_instance(sub_map, loro.client_id());
let mut sub_map = loro.get_map_by_idx(&map_id.idx()).unwrap();
sub_map.insert(&loro, "sub", false).unwrap();
drop(sub_map);
let root = loro.get_map("root");
@ -284,8 +293,12 @@ fn encode_hierarchy() {
let mut c1 = LoroCore::default();
let mut map = c1.get_map("map");
let list_id = map.insert(&c1, "a", ContainerType::List).unwrap().unwrap();
let mut list = c1.get_list_by_temp(list_id).unwrap();
let list_id = map
.insert(&c1, "a", ContainerType::List)
.unwrap()
.unwrap()
.idx();
let mut list = c1.get_list_by_idx(&list_id).unwrap();
let idx = list
.insert(&c1, 0, ContainerType::Text)
.unwrap()