diff --git a/crates/loro-internal/src/handler.rs b/crates/loro-internal/src/handler.rs index 3857ea51..02ade94a 100644 --- a/crates/loro-internal/src/handler.rs +++ b/crates/loro-internal/src/handler.rs @@ -284,6 +284,13 @@ impl TextHandler { return Ok(()); } + if pos > self.len_event() { + return Err(LoroError::OutOfBound { + pos, + len: self.len_event(), + }); + } + let (entity_index, styles) = self .state .upgrade() @@ -424,6 +431,11 @@ impl TextHandler { )); } + let len = self.len_event(); + if end > len { + return Err(LoroError::OutOfBound { pos: end, len }); + } + let (entity_start, entity_end) = self .state .upgrade() @@ -551,6 +563,13 @@ impl ListHandler { } pub fn insert(&self, txn: &mut Transaction, pos: usize, v: LoroValue) -> LoroResult<()> { + if pos > self.len() { + return Err(LoroError::OutOfBound { + pos, + len: self.len(), + }); + } + if let Some(container) = v.as_container() { self.insert_container(txn, pos, container.container_type())?; return Ok(()); @@ -631,6 +650,13 @@ impl ListHandler { return Ok(()); } + if pos + len > self.len() { + return Err(LoroError::OutOfBound { + pos: pos + len, + len: self.len(), + }); + } + txn.apply_local_op( self.container_idx, crate::op::RawOpContent::List(ListOp::Delete(DeleteSpan { diff --git a/crates/loro-internal/tests/test.rs b/crates/loro-internal/tests/test.rs index b105ecf8..37b60be7 100644 --- a/crates/loro-internal/tests/test.rs +++ b/crates/loro-internal/tests/test.rs @@ -18,9 +18,26 @@ fn list() { .into_map() .unwrap(); map.insert_("Hello", LoroValue::from("u")).unwrap(); + let pos = map + .insert_container_("pos", ContainerType::Map) + .unwrap() + .into_map() + .unwrap(); + pos.insert_("x", 0.into()).unwrap(); + pos.insert_("y", 100.into()).unwrap(); + let cid = map.id(); let id = a.get_list("list").get(1); - assert_eq!(id.unwrap().as_container().unwrap(), &cid); + assert_eq!(id.as_ref().unwrap().as_container().unwrap(), &cid); + let map = a.get_map(id.unwrap().into_container().unwrap()); + let new_pos = a.get_map(map.get("pos").unwrap().into_container().unwrap()); + assert_eq!( + new_pos.get_deep_value().to_json_value(), + json!({ + "x": 0, + "y": 100, + }) + ); } #[test] diff --git a/crates/loro-wasm/src/lib.rs b/crates/loro-wasm/src/lib.rs index 6a972683..6c7ce500 100644 --- a/crates/loro-wasm/src/lib.rs +++ b/crates/loro-wasm/src/lib.rs @@ -154,7 +154,10 @@ fn js_value_to_container_id( kind: ContainerType, ) -> Result { if !cid.is_string() { - return Err(JsValue::from_str("ContainerID must be a string")); + return Err(JsValue::from_str(&format!( + "ContainerID must be a string, but found {}", + cid.js_typeof().as_string().unwrap(), + ))); } let s = cid.as_string().unwrap();