feat: add context check

This commit is contained in:
leeeon233 2022-11-21 17:10:04 +08:00 committed by Leonzhao
parent 42ded24721
commit df3a708e48
6 changed files with 98 additions and 39 deletions

View file

@ -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
}
}

View file

@ -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
}
}

View file

@ -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())
}

View file

@ -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
}
}

View file

@ -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(

View file

@ -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();