mirror of
https://github.com/loro-dev/loro.git
synced 2025-01-23 13:39:12 +00:00
feat: add context check
This commit is contained in:
parent
42ded24721
commit
df3a708e48
6 changed files with 98 additions and 39 deletions
|
@ -19,7 +19,7 @@ use crate::{
|
|||
Container, ContainerID, ContainerType,
|
||||
},
|
||||
context::Context,
|
||||
id::{Counter, ID},
|
||||
id::{ClientID, Counter, ID},
|
||||
op::{InnerContent, Op, RemoteContent, RichOp},
|
||||
value::LoroValue,
|
||||
version::IdSpanVector,
|
||||
|
@ -259,19 +259,31 @@ impl Container for ListContainer {
|
|||
|
||||
pub struct List {
|
||||
instance: Arc<Mutex<ContainerInstance>>,
|
||||
client_id: ClientID,
|
||||
}
|
||||
|
||||
impl Clone for List {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
instance: Arc::clone(&self.instance),
|
||||
client_id: self.client_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl List {
|
||||
pub(crate) fn from_instance(
|
||||
instance: Arc<Mutex<ContainerInstance>>,
|
||||
client_id: ClientID,
|
||||
) -> Self {
|
||||
Self {
|
||||
instance,
|
||||
client_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_batch<C: Context>(&mut self, ctx: &C, pos: usize, values: Vec<LoroValue>) {
|
||||
self.with_container(|x| x.insert_batch(ctx, pos, values))
|
||||
self.with_container_checked(ctx, |x| x.insert_batch(ctx, pos, values))
|
||||
}
|
||||
|
||||
pub fn insert<C: Context, V: Into<LoroValue>>(
|
||||
|
@ -280,7 +292,7 @@ impl List {
|
|||
pos: usize,
|
||||
value: V,
|
||||
) -> Option<ID> {
|
||||
self.with_container(|x| x.insert(ctx, pos, value))
|
||||
self.with_container_checked(ctx, |x| x.insert(ctx, pos, value))
|
||||
}
|
||||
|
||||
pub fn insert_obj<C: Context>(
|
||||
|
@ -289,11 +301,11 @@ impl List {
|
|||
pos: usize,
|
||||
obj: ContainerType,
|
||||
) -> ContainerID {
|
||||
self.with_container(|x| x.insert_obj(ctx, pos, obj))
|
||||
self.with_container_checked(ctx, |x| x.insert_obj(ctx, pos, obj))
|
||||
}
|
||||
|
||||
pub fn delete<C: Context>(&mut self, ctx: &C, pos: usize, len: usize) -> Option<ID> {
|
||||
self.with_container(|text| text.delete(ctx, pos, len))
|
||||
self.with_container_checked(ctx, |text| text.delete(ctx, pos, len))
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
|
@ -317,10 +329,8 @@ impl ContainerWrapper for List {
|
|||
let list = container_instance.as_list_mut().unwrap();
|
||||
f(list)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Arc<Mutex<ContainerInstance>>> for List {
|
||||
fn from(text: Arc<Mutex<ContainerInstance>>) -> Self {
|
||||
List { instance: text }
|
||||
fn client_id(&self) -> ClientID {
|
||||
self.client_id
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ use crate::{
|
|||
Container, ContainerID, ContainerType,
|
||||
},
|
||||
context::Context,
|
||||
id::ClientID,
|
||||
op::{InnerContent, Op, RemoteContent, RichOp},
|
||||
span::HasLamport,
|
||||
value::LoroValue,
|
||||
|
@ -209,19 +210,31 @@ impl Container for MapContainer {
|
|||
|
||||
pub struct Map {
|
||||
instance: Arc<Mutex<ContainerInstance>>,
|
||||
client_id: ClientID,
|
||||
}
|
||||
|
||||
impl Clone for Map {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
instance: Arc::clone(&self.instance),
|
||||
client_id: self.client_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Map {
|
||||
pub(crate) fn from_instance(
|
||||
instance: Arc<Mutex<ContainerInstance>>,
|
||||
client_id: ClientID,
|
||||
) -> Self {
|
||||
Self {
|
||||
instance,
|
||||
client_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert<C: Context, V: Into<LoroValue>>(&mut self, ctx: &C, key: &str, value: V) {
|
||||
self.with_container(|map| {
|
||||
self.with_container_checked(ctx, |map| {
|
||||
map.insert(ctx, key.into(), value);
|
||||
})
|
||||
}
|
||||
|
@ -232,11 +245,11 @@ impl Map {
|
|||
key: &str,
|
||||
obj: ContainerType,
|
||||
) -> ContainerID {
|
||||
self.with_container(|map| map.insert_obj(ctx, key.into(), obj))
|
||||
self.with_container_checked(ctx, |map| map.insert_obj(ctx, key.into(), obj))
|
||||
}
|
||||
|
||||
pub fn delete<C: Context>(&mut self, ctx: &C, key: &str) {
|
||||
self.with_container(|map| {
|
||||
self.with_container_checked(ctx, |map| {
|
||||
map.delete(ctx, key.into());
|
||||
})
|
||||
}
|
||||
|
@ -271,10 +284,8 @@ impl ContainerWrapper for Map {
|
|||
let map = container_instance.as_map_mut().unwrap();
|
||||
f(map)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Arc<Mutex<ContainerInstance>>> for Map {
|
||||
fn from(map: Arc<Mutex<ContainerInstance>>) -> Self {
|
||||
Map { instance: map }
|
||||
fn client_id(&self) -> ClientID {
|
||||
self.client_id
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ use smallvec::SmallVec;
|
|||
|
||||
use crate::{
|
||||
context::Context,
|
||||
id::ContainerIdx,
|
||||
id::{ClientID, ContainerIdx},
|
||||
op::{RemoteContent, RichOp},
|
||||
version::IdSpanVector,
|
||||
LoroValue, VersionVector,
|
||||
|
@ -297,6 +297,23 @@ pub trait ContainerWrapper {
|
|||
where
|
||||
F: FnOnce(&mut Self::Container) -> R;
|
||||
|
||||
fn with_container_checked<C: Context, F, R>(&self, ctx: &C, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&mut Self::Container) -> R,
|
||||
{
|
||||
let store_client_id = ctx.log_store().read().unwrap().this_client_id();
|
||||
if store_client_id != self.client_id() {
|
||||
panic!(
|
||||
"Context's client_id({}) does not match Container's client_id({})",
|
||||
store_client_id,
|
||||
self.client_id()
|
||||
);
|
||||
}
|
||||
self.with_container(f)
|
||||
}
|
||||
|
||||
fn client_id(&self) -> ClientID;
|
||||
|
||||
fn id(&self) -> ContainerID {
|
||||
self.with_container(|x| x.id().clone())
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ use crate::{
|
|||
},
|
||||
context::Context,
|
||||
debug_log,
|
||||
id::{Counter, ID},
|
||||
id::{ClientID, Counter, ID},
|
||||
op::{InnerContent, Op, RemoteContent, RichOp},
|
||||
value::LoroValue,
|
||||
version::IdSpanVector,
|
||||
|
@ -278,27 +278,39 @@ impl Container for TextContainer {
|
|||
|
||||
pub struct Text {
|
||||
instance: Arc<Mutex<ContainerInstance>>,
|
||||
client_id: ClientID,
|
||||
}
|
||||
|
||||
impl Clone for Text {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
instance: Arc::clone(&self.instance),
|
||||
client_id: self.client_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Text {
|
||||
pub(crate) fn from_instance(
|
||||
instance: Arc<Mutex<ContainerInstance>>,
|
||||
client_id: ClientID,
|
||||
) -> Self {
|
||||
Self {
|
||||
instance,
|
||||
client_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn id(&self) -> ContainerID {
|
||||
self.instance.lock().unwrap().as_text().unwrap().id.clone()
|
||||
}
|
||||
|
||||
pub fn insert<C: Context>(&mut self, ctx: &C, pos: usize, text: &str) -> Option<ID> {
|
||||
self.with_container(|x| x.insert(ctx, pos, text))
|
||||
self.with_container_checked(ctx, |x| x.insert(ctx, pos, text))
|
||||
}
|
||||
|
||||
pub fn delete<C: Context>(&mut self, ctx: &C, pos: usize, len: usize) -> Option<ID> {
|
||||
self.with_container(|text| text.delete(ctx, pos, len))
|
||||
self.with_container_checked(ctx, |text| text.delete(ctx, pos, len))
|
||||
}
|
||||
|
||||
pub fn get_value(&self) -> LoroValue {
|
||||
|
@ -326,10 +338,8 @@ impl ContainerWrapper for Text {
|
|||
let text = container_instance.as_text_mut().unwrap();
|
||||
f(text)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Arc<Mutex<ContainerInstance>>> for Text {
|
||||
fn from(text: Arc<Mutex<ContainerInstance>>) -> Self {
|
||||
Text { instance: text }
|
||||
fn client_id(&self) -> crate::id::ClientID {
|
||||
self.client_id
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,34 +36,34 @@ impl LoroCore {
|
|||
#[inline(always)]
|
||||
pub fn get_list<I: Into<ContainerIdRaw>>(&mut self, id: I) -> List {
|
||||
let id: ContainerIdRaw = id.into();
|
||||
self.log_store
|
||||
.write()
|
||||
.unwrap()
|
||||
let mut store = self.log_store.write().unwrap();
|
||||
let instance = store
|
||||
.get_or_create_container(&id.with_type(ContainerType::List))
|
||||
.clone()
|
||||
.into()
|
||||
.clone();
|
||||
let cid = store.this_client_id();
|
||||
List::from_instance(instance, cid)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_map<I: Into<ContainerIdRaw>>(&mut self, id: I) -> Map {
|
||||
let id: ContainerIdRaw = id.into();
|
||||
self.log_store
|
||||
.write()
|
||||
.unwrap()
|
||||
let mut store = self.log_store.write().unwrap();
|
||||
let instance = store
|
||||
.get_or_create_container(&id.with_type(ContainerType::Map))
|
||||
.clone()
|
||||
.into()
|
||||
.clone();
|
||||
let cid = store.this_client_id();
|
||||
Map::from_instance(instance, cid)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_text<I: Into<ContainerIdRaw>>(&mut self, id: I) -> Text {
|
||||
let id: ContainerIdRaw = id.into();
|
||||
self.log_store
|
||||
.write()
|
||||
.unwrap()
|
||||
let mut store = self.log_store.write().unwrap();
|
||||
let instance = store
|
||||
.get_or_create_container(&id.with_type(ContainerType::Text))
|
||||
.clone()
|
||||
.into()
|
||||
.clone();
|
||||
let cid = store.this_client_id();
|
||||
Text::from_instance(instance, cid)
|
||||
}
|
||||
|
||||
pub fn export(
|
||||
|
|
|
@ -136,6 +136,17 @@ fn two_client_text_sync() {
|
|||
assert_eq!(&**value, "abc");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_recursive_should_panic() {
|
||||
let mut store_a = LoroCore::new(Default::default(), Some(1));
|
||||
let mut store_b = LoroCore::new(Default::default(), Some(2));
|
||||
let mut text_a = store_a.get_text("text_a");
|
||||
let mut text_b = store_b.get_text("text_b");
|
||||
text_a.insert(&store_a, 0, "012");
|
||||
text_b.insert(&store_a, 1, "34");
|
||||
}
|
||||
|
||||
#[ctor]
|
||||
fn init_color_backtrace() {
|
||||
color_backtrace::install();
|
||||
|
|
Loading…
Reference in a new issue