1use super::{state::DocState, txn::Transaction};
2use crate::sync::Mutex;
3use crate::{
4 container::{
5 idx::ContainerIdx,
6 list::list_op::{DeleteSpan, DeleteSpanWithId, ListOp},
7 richtext::{richtext_state::PosType, RichtextState, StyleOp, TextStyleInfoFlag},
8 },
9 cursor::{Cursor, Side},
10 delta::{DeltaItem, Meta, StyleMeta, TreeExternalDiff},
11 diff::{diff, diff_impl::UpdateTimeoutError, OperateProxy},
12 event::{Diff, TextDiff, TextDiffItem, TextMeta},
13 op::ListSlice,
14 state::{IndexType, State, TreeParentId},
15 txn::EventHint,
16 utils::{string_slice::StringSlice, utf16::count_utf16_len},
17 LoroDoc, LoroDocInner,
18};
19use append_only_bytes::BytesSlice;
20use enum_as_inner::EnumAsInner;
21use generic_btree::rle::HasLength;
22use loro_common::{
23 ContainerID, ContainerType, IdFull, InternalString, LoroError, LoroResult, LoroValue, PeerID,
24 TreeID, ID,
25};
26use rustc_hash::FxHashMap;
27use serde::{Deserialize, Serialize};
28use std::{borrow::Cow, cmp::Reverse, collections::BinaryHeap, fmt::Debug, ops::Deref, sync::Arc};
29use tracing::{error, instrument};
30
31pub use crate::diff::diff_impl::UpdateOptions;
32pub use tree::TreeHandler;
33mod movable_list_apply_delta;
34mod tree;
35
36const INSERT_CONTAINER_VALUE_ARG_ERROR: &str =
37 "Cannot insert a LoroValue::Container directly. To create child container, use insert_container";
38
39mod text_update;
40
41pub trait HandlerTrait: Clone + Sized {
42 fn is_attached(&self) -> bool;
43 fn attached_handler(&self) -> Option<&BasicHandler>;
44 fn get_value(&self) -> LoroValue;
45 fn get_deep_value(&self) -> LoroValue;
46 fn kind(&self) -> ContainerType;
47 fn to_handler(&self) -> Handler;
48 fn from_handler(h: Handler) -> Option<Self>;
49 fn doc(&self) -> Option<LoroDoc>;
50 fn attach(
52 &self,
53 txn: &mut Transaction,
54 parent: &BasicHandler,
55 self_id: ContainerID,
56 ) -> LoroResult<Self>;
57 fn get_attached(&self) -> Option<Self>;
59
60 fn parent(&self) -> Option<Handler> {
61 self.attached_handler().and_then(|x| x.parent())
62 }
63
64 fn idx(&self) -> ContainerIdx {
65 self.attached_handler()
66 .map(|x| x.container_idx)
67 .unwrap_or_else(|| ContainerIdx::from_index_and_type(u32::MAX, self.kind()))
68 }
69
70 fn id(&self) -> ContainerID {
71 self.attached_handler()
72 .map(|x| x.id.clone())
73 .unwrap_or_else(|| ContainerID::new_normal(ID::NONE_ID, self.kind()))
74 }
75
76 fn with_state<R>(&self, f: impl FnOnce(&mut State) -> LoroResult<R>) -> LoroResult<R> {
77 let inner = self
78 .attached_handler()
79 .ok_or(LoroError::MisuseDetachedContainer {
80 method: "with_state",
81 })?;
82 let state = inner.doc.state.clone();
83 let mut guard = state.lock().unwrap();
84 guard.with_state_mut(inner.container_idx, f)
85 }
86}
87
88fn create_handler(inner: &BasicHandler, id: ContainerID) -> Handler {
89 Handler::new_attached(id, inner.doc.clone())
90}
91
92#[derive(Clone, Debug)]
94pub struct BasicHandler {
95 id: ContainerID,
96 container_idx: ContainerIdx,
97 doc: LoroDoc,
98}
99
100struct DetachedInner<T> {
101 value: T,
102 attached: Option<BasicHandler>,
104}
105
106impl<T> DetachedInner<T> {
107 fn new(v: T) -> Self {
108 Self {
109 value: v,
110 attached: None,
111 }
112 }
113}
114
115enum MaybeDetached<T> {
116 Detached(Arc<Mutex<DetachedInner<T>>>),
117 Attached(BasicHandler),
118}
119
120impl<T> Clone for MaybeDetached<T> {
121 fn clone(&self) -> Self {
122 match self {
123 MaybeDetached::Detached(a) => MaybeDetached::Detached(Arc::clone(a)),
124 MaybeDetached::Attached(a) => MaybeDetached::Attached(a.clone()),
125 }
126 }
127}
128
129impl<T> MaybeDetached<T> {
130 fn new_detached(v: T) -> Self {
131 MaybeDetached::Detached(Arc::new(Mutex::new(DetachedInner::new(v))))
132 }
133
134 fn is_attached(&self) -> bool {
135 match self {
136 MaybeDetached::Detached(_) => false,
137 MaybeDetached::Attached(_) => true,
138 }
139 }
140
141 fn attached_handler(&self) -> Option<&BasicHandler> {
142 match self {
143 MaybeDetached::Detached(_) => None,
144 MaybeDetached::Attached(a) => Some(a),
145 }
146 }
147
148 fn try_attached_state(&self) -> LoroResult<&BasicHandler> {
149 match self {
150 MaybeDetached::Detached(_) => Err(LoroError::MisuseDetachedContainer {
151 method: "inner_state",
152 }),
153 MaybeDetached::Attached(a) => Ok(a),
154 }
155 }
156}
157
158impl<T> From<BasicHandler> for MaybeDetached<T> {
159 fn from(a: BasicHandler) -> Self {
160 MaybeDetached::Attached(a)
161 }
162}
163
164impl BasicHandler {
165 pub(crate) fn doc(&self) -> LoroDoc {
166 self.doc.clone()
167 }
168
169 #[inline]
170 fn with_doc_state<R>(&self, f: impl FnOnce(&mut DocState) -> R) -> R {
171 let state = self.doc.state.clone();
172 let mut guard = state.lock().unwrap();
173 f(&mut guard)
174 }
175
176 fn with_txn<R>(
177 &self,
178 f: impl FnOnce(&mut Transaction) -> Result<R, LoroError>,
179 ) -> Result<R, LoroError> {
180 with_txn(&self.doc, f)
181 }
182
183 fn get_parent(&self) -> Option<Handler> {
184 let parent_idx = self.doc.arena.get_parent(self.container_idx)?;
185 let parent_id = self.doc.arena.get_container_id(parent_idx).unwrap();
186 {
187 let kind = parent_id.container_type();
188 let handler = BasicHandler {
189 container_idx: parent_idx,
190 id: parent_id,
191 doc: self.doc.clone(),
192 };
193
194 Some(match kind {
195 ContainerType::Map => Handler::Map(MapHandler {
196 inner: handler.into(),
197 }),
198 ContainerType::List => Handler::List(ListHandler {
199 inner: handler.into(),
200 }),
201 ContainerType::Tree => Handler::Tree(TreeHandler {
202 inner: handler.into(),
203 }),
204 ContainerType::Text => Handler::Text(TextHandler {
205 inner: handler.into(),
206 }),
207 ContainerType::MovableList => Handler::MovableList(MovableListHandler {
208 inner: handler.into(),
209 }),
210 #[cfg(feature = "counter")]
211 ContainerType::Counter => Handler::Counter(counter::CounterHandler {
212 inner: handler.into(),
213 }),
214 ContainerType::Unknown(_) => unreachable!(),
215 })
216 }
217 }
218
219 pub fn get_value(&self) -> LoroValue {
220 self.doc
221 .state
222 .lock()
223 .unwrap()
224 .get_value_by_idx(self.container_idx)
225 }
226
227 pub fn get_deep_value(&self) -> LoroValue {
228 self.doc
229 .state
230 .lock()
231 .unwrap()
232 .get_container_deep_value(self.container_idx)
233 }
234
235 fn with_state<R>(&self, f: impl FnOnce(&mut State) -> R) -> R {
236 let mut guard = self.doc.state.lock().unwrap();
237 guard.with_state_mut(self.container_idx, f)
238 }
239
240 pub fn parent(&self) -> Option<Handler> {
241 self.get_parent()
242 }
243
244 fn is_deleted(&self) -> bool {
245 self.doc
246 .state
247 .lock()
248 .unwrap()
249 .is_deleted(self.container_idx)
250 }
251}
252
253#[derive(Clone)]
255pub struct TextHandler {
256 inner: MaybeDetached<RichtextState>,
257}
258
259impl HandlerTrait for TextHandler {
260 fn to_handler(&self) -> Handler {
261 Handler::Text(self.clone())
262 }
263
264 fn attach(
265 &self,
266 txn: &mut Transaction,
267 parent: &BasicHandler,
268 self_id: ContainerID,
269 ) -> LoroResult<Self> {
270 match &self.inner {
271 MaybeDetached::Detached(t) => {
272 let mut t = t.lock().unwrap();
273 let inner = create_handler(parent, self_id);
274 let text = inner.into_text().unwrap();
275 let mut delta: Vec<TextDelta> = Vec::new();
276 for span in t.value.iter() {
277 delta.push(TextDelta::Insert {
278 insert: span.text.to_string(),
279 attributes: span.attributes.to_option_map(),
280 });
281 }
282
283 text.apply_delta_with_txn(txn, &delta)?;
284 t.attached = text.attached_handler().cloned();
285 Ok(text)
286 }
287 MaybeDetached::Attached(a) => {
288 let new_inner = create_handler(a, self_id);
289 let ans = new_inner.into_text().unwrap();
290
291 let delta = self.get_delta();
292 ans.apply_delta_with_txn(txn, &delta)?;
293 Ok(ans)
294 }
295 }
296 }
297
298 fn attached_handler(&self) -> Option<&BasicHandler> {
299 self.inner.attached_handler()
300 }
301
302 fn get_value(&self) -> LoroValue {
303 match &self.inner {
304 MaybeDetached::Detached(t) => {
305 let t = t.lock().unwrap();
306 LoroValue::String((t.value.to_string()).into())
307 }
308 MaybeDetached::Attached(a) => a.get_value(),
309 }
310 }
311
312 fn get_deep_value(&self) -> LoroValue {
313 self.get_value()
314 }
315
316 fn is_attached(&self) -> bool {
317 matches!(&self.inner, MaybeDetached::Attached(..))
318 }
319
320 fn kind(&self) -> ContainerType {
321 ContainerType::Text
322 }
323
324 fn get_attached(&self) -> Option<Self> {
325 match &self.inner {
326 MaybeDetached::Detached(d) => d.lock().unwrap().attached.clone().map(|x| Self {
327 inner: MaybeDetached::Attached(x),
328 }),
329 MaybeDetached::Attached(_a) => Some(self.clone()),
330 }
331 }
332
333 fn from_handler(h: Handler) -> Option<Self> {
334 match h {
335 Handler::Text(x) => Some(x),
336 _ => None,
337 }
338 }
339
340 fn doc(&self) -> Option<LoroDoc> {
341 match &self.inner {
342 MaybeDetached::Detached(_) => None,
343 MaybeDetached::Attached(a) => Some(a.doc()),
344 }
345 }
346}
347
348impl std::fmt::Debug for TextHandler {
349 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
350 match &self.inner {
351 MaybeDetached::Detached(_) => {
352 write!(f, "TextHandler(Unattached)")
353 }
354 MaybeDetached::Attached(a) => {
355 write!(f, "TextHandler({:?})", &a.id)
356 }
357 }
358 }
359}
360
361#[derive(Debug, Clone, EnumAsInner, Deserialize, Serialize, PartialEq)]
362#[serde(untagged)]
363pub enum TextDelta {
364 Retain {
365 retain: usize,
366 attributes: Option<FxHashMap<String, LoroValue>>,
367 },
368 Insert {
369 insert: String,
370 attributes: Option<FxHashMap<String, LoroValue>>,
371 },
372 Delete {
373 delete: usize,
374 },
375}
376
377impl TextDelta {
378 pub fn from_text_diff<'a>(diff: impl Iterator<Item = &'a TextDiffItem>) -> Vec<TextDelta> {
379 let mut ans = Vec::with_capacity(diff.size_hint().0);
380 for iter in diff {
381 match iter {
382 loro_delta::DeltaItem::Retain { len, attr } => {
383 ans.push(TextDelta::Retain {
384 retain: *len,
385 attributes: if attr.0.is_empty() {
386 None
387 } else {
388 Some(attr.0.clone())
389 },
390 });
391 }
392 loro_delta::DeltaItem::Replace {
393 value,
394 attr,
395 delete,
396 } => {
397 if value.rle_len() > 0 {
398 ans.push(TextDelta::Insert {
399 insert: value.to_string(),
400 attributes: if attr.0.is_empty() {
401 None
402 } else {
403 Some(attr.0.clone())
404 },
405 });
406 }
407 if *delete > 0 {
408 ans.push(TextDelta::Delete { delete: *delete });
409 }
410 }
411 }
412 }
413
414 ans
415 }
416
417 pub fn into_text_diff(vec: impl Iterator<Item = Self>) -> TextDiff {
418 let mut delta = TextDiff::new();
419 for item in vec {
420 match item {
421 TextDelta::Retain { retain, attributes } => {
422 delta.push_retain(retain, TextMeta(attributes.unwrap_or_default().clone()));
423 }
424 TextDelta::Insert { insert, attributes } => {
425 delta.push_insert(
426 StringSlice::from(insert.as_str()),
427 TextMeta(attributes.unwrap_or_default()),
428 );
429 }
430 TextDelta::Delete { delete } => {
431 delta.push_delete(delete);
432 }
433 }
434 }
435
436 delta
437 }
438}
439
440impl From<&DeltaItem<StringSlice, StyleMeta>> for TextDelta {
441 fn from(value: &DeltaItem<StringSlice, StyleMeta>) -> Self {
442 match value {
443 crate::delta::DeltaItem::Retain { retain, attributes } => TextDelta::Retain {
444 retain: *retain,
445 attributes: attributes.to_option_map(),
446 },
447 crate::delta::DeltaItem::Insert { insert, attributes } => TextDelta::Insert {
448 insert: insert.to_string(),
449 attributes: attributes.to_option_map(),
450 },
451 crate::delta::DeltaItem::Delete {
452 delete,
453 attributes: _,
454 } => TextDelta::Delete { delete: *delete },
455 }
456 }
457}
458
459#[derive(Clone)]
460pub struct MapHandler {
461 inner: MaybeDetached<FxHashMap<String, ValueOrHandler>>,
462}
463
464impl HandlerTrait for MapHandler {
465 fn is_attached(&self) -> bool {
466 matches!(&self.inner, MaybeDetached::Attached(..))
467 }
468
469 fn attached_handler(&self) -> Option<&BasicHandler> {
470 match &self.inner {
471 MaybeDetached::Detached(_) => None,
472 MaybeDetached::Attached(a) => Some(a),
473 }
474 }
475
476 fn get_value(&self) -> LoroValue {
477 match &self.inner {
478 MaybeDetached::Detached(m) => {
479 let m = m.lock().unwrap();
480 let mut map = FxHashMap::default();
481 for (k, v) in m.value.iter() {
482 map.insert(k.to_string(), v.to_value());
483 }
484 LoroValue::Map(map.into())
485 }
486 MaybeDetached::Attached(a) => a.get_value(),
487 }
488 }
489
490 fn get_deep_value(&self) -> LoroValue {
491 match &self.inner {
492 MaybeDetached::Detached(m) => {
493 let m = m.lock().unwrap();
494 let mut map = FxHashMap::default();
495 for (k, v) in m.value.iter() {
496 map.insert(k.to_string(), v.to_deep_value());
497 }
498 LoroValue::Map(map.into())
499 }
500 MaybeDetached::Attached(a) => a.get_deep_value(),
501 }
502 }
503
504 fn kind(&self) -> ContainerType {
505 ContainerType::Map
506 }
507
508 fn to_handler(&self) -> Handler {
509 Handler::Map(self.clone())
510 }
511
512 fn attach(
513 &self,
514 txn: &mut Transaction,
515 parent: &BasicHandler,
516 self_id: ContainerID,
517 ) -> LoroResult<Self> {
518 match &self.inner {
519 MaybeDetached::Detached(m) => {
520 let mut m = m.lock().unwrap();
521 let inner = create_handler(parent, self_id);
522 let map = inner.into_map().unwrap();
523 for (k, v) in m.value.iter() {
524 match v {
525 ValueOrHandler::Value(v) => {
526 map.insert_with_txn(txn, k, v.clone())?;
527 }
528 ValueOrHandler::Handler(h) => {
529 map.insert_container_with_txn(txn, k, h.clone())?;
530 }
531 }
532 }
533 m.attached = map.attached_handler().cloned();
534 Ok(map)
535 }
536 MaybeDetached::Attached(a) => {
537 let new_inner = create_handler(a, self_id);
538 let ans = new_inner.into_map().unwrap();
539
540 for (k, v) in self.get_value().into_map().unwrap().iter() {
541 if let LoroValue::Container(id) = v {
542 ans.insert_container_with_txn(txn, k, create_handler(a, id.clone()))?;
543 } else {
544 ans.insert_with_txn(txn, k, v.clone())?;
545 }
546 }
547
548 Ok(ans)
549 }
550 }
551 }
552
553 fn get_attached(&self) -> Option<Self> {
554 match &self.inner {
555 MaybeDetached::Detached(d) => d.lock().unwrap().attached.clone().map(|x| Self {
556 inner: MaybeDetached::Attached(x),
557 }),
558 MaybeDetached::Attached(_a) => Some(self.clone()),
559 }
560 }
561
562 fn from_handler(h: Handler) -> Option<Self> {
563 match h {
564 Handler::Map(x) => Some(x),
565 _ => None,
566 }
567 }
568
569 fn doc(&self) -> Option<LoroDoc> {
570 match &self.inner {
571 MaybeDetached::Detached(_) => None,
572 MaybeDetached::Attached(a) => Some(a.doc()),
573 }
574 }
575}
576
577impl std::fmt::Debug for MapHandler {
578 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
579 match &self.inner {
580 MaybeDetached::Detached(_) => write!(f, "MapHandler Detached"),
581 MaybeDetached::Attached(a) => write!(f, "MapHandler {}", a.id),
582 }
583 }
584}
585
586#[derive(Clone)]
587pub struct ListHandler {
588 inner: MaybeDetached<Vec<ValueOrHandler>>,
589}
590
591#[derive(Clone)]
592pub struct MovableListHandler {
593 inner: MaybeDetached<Vec<ValueOrHandler>>,
594}
595
596impl HandlerTrait for MovableListHandler {
597 fn is_attached(&self) -> bool {
598 matches!(&self.inner, MaybeDetached::Attached(..))
599 }
600
601 fn attached_handler(&self) -> Option<&BasicHandler> {
602 match &self.inner {
603 MaybeDetached::Detached(_) => None,
604 MaybeDetached::Attached(a) => Some(a),
605 }
606 }
607
608 fn get_value(&self) -> LoroValue {
609 match &self.inner {
610 MaybeDetached::Detached(a) => {
611 let a = a.lock().unwrap();
612 LoroValue::List(a.value.iter().map(|v| v.to_value()).collect())
613 }
614 MaybeDetached::Attached(a) => a.get_value(),
615 }
616 }
617
618 fn get_deep_value(&self) -> LoroValue {
619 match &self.inner {
620 MaybeDetached::Detached(a) => {
621 let a = a.lock().unwrap();
622 LoroValue::List(a.value.iter().map(|v| v.to_deep_value()).collect())
623 }
624 MaybeDetached::Attached(a) => a.get_deep_value(),
625 }
626 }
627
628 fn kind(&self) -> ContainerType {
629 ContainerType::MovableList
630 }
631
632 fn to_handler(&self) -> Handler {
633 Handler::MovableList(self.clone())
634 }
635
636 fn from_handler(h: Handler) -> Option<Self> {
637 match h {
638 Handler::MovableList(x) => Some(x),
639 _ => None,
640 }
641 }
642
643 fn attach(
644 &self,
645 txn: &mut Transaction,
646 parent: &BasicHandler,
647 self_id: ContainerID,
648 ) -> LoroResult<Self> {
649 match &self.inner {
650 MaybeDetached::Detached(l) => {
651 let mut l = l.lock().unwrap();
652 let inner = create_handler(parent, self_id);
653 let list = inner.into_movable_list().unwrap();
654 for (index, v) in l.value.iter().enumerate() {
655 match v {
656 ValueOrHandler::Value(v) => {
657 list.insert_with_txn(txn, index, v.clone())?;
658 }
659 ValueOrHandler::Handler(h) => {
660 list.insert_container_with_txn(txn, index, h.clone())?;
661 }
662 }
663 }
664 l.attached = list.attached_handler().cloned();
665 Ok(list)
666 }
667 MaybeDetached::Attached(a) => {
668 let new_inner = create_handler(a, self_id);
669 let ans = new_inner.into_movable_list().unwrap();
670
671 for (i, v) in self.get_value().into_list().unwrap().iter().enumerate() {
672 if let LoroValue::Container(id) = v {
673 ans.insert_container_with_txn(txn, i, create_handler(a, id.clone()))?;
674 } else {
675 ans.insert_with_txn(txn, i, v.clone())?;
676 }
677 }
678
679 Ok(ans)
680 }
681 }
682 }
683
684 fn get_attached(&self) -> Option<Self> {
685 match &self.inner {
686 MaybeDetached::Detached(d) => d.lock().unwrap().attached.clone().map(|x| Self {
687 inner: MaybeDetached::Attached(x),
688 }),
689 MaybeDetached::Attached(_a) => Some(self.clone()),
690 }
691 }
692
693 fn doc(&self) -> Option<LoroDoc> {
694 match &self.inner {
695 MaybeDetached::Detached(_) => None,
696 MaybeDetached::Attached(a) => Some(a.doc()),
697 }
698 }
699}
700
701impl std::fmt::Debug for MovableListHandler {
702 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
703 write!(f, "MovableListHandler {}", self.id())
704 }
705}
706
707impl std::fmt::Debug for ListHandler {
708 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
709 match &self.inner {
710 MaybeDetached::Detached(_) => write!(f, "ListHandler Detached"),
711 MaybeDetached::Attached(a) => write!(f, "ListHandler {}", a.id),
712 }
713 }
714}
715
716impl HandlerTrait for ListHandler {
717 fn is_attached(&self) -> bool {
718 self.inner.is_attached()
719 }
720
721 fn attached_handler(&self) -> Option<&BasicHandler> {
722 self.inner.attached_handler()
723 }
724
725 fn get_value(&self) -> LoroValue {
726 match &self.inner {
727 MaybeDetached::Detached(a) => {
728 let a = a.lock().unwrap();
729 LoroValue::List(a.value.iter().map(|v| v.to_value()).collect())
730 }
731 MaybeDetached::Attached(a) => a.get_value(),
732 }
733 }
734
735 fn get_deep_value(&self) -> LoroValue {
736 match &self.inner {
737 MaybeDetached::Detached(a) => {
738 let a = a.lock().unwrap();
739 LoroValue::List(a.value.iter().map(|v| v.to_deep_value()).collect())
740 }
741 MaybeDetached::Attached(a) => a.get_deep_value(),
742 }
743 }
744
745 fn kind(&self) -> ContainerType {
746 ContainerType::List
747 }
748
749 fn to_handler(&self) -> Handler {
750 Handler::List(self.clone())
751 }
752
753 fn attach(
754 &self,
755 txn: &mut Transaction,
756 parent: &BasicHandler,
757 self_id: ContainerID,
758 ) -> LoroResult<Self> {
759 match &self.inner {
760 MaybeDetached::Detached(l) => {
761 let mut l = l.lock().unwrap();
762 let inner = create_handler(parent, self_id);
763 let list = inner.into_list().unwrap();
764 for (index, v) in l.value.iter().enumerate() {
765 match v {
766 ValueOrHandler::Value(v) => {
767 list.insert_with_txn(txn, index, v.clone())?;
768 }
769 ValueOrHandler::Handler(h) => {
770 list.insert_container_with_txn(txn, index, h.clone())?;
771 }
772 }
773 }
774 l.attached = list.attached_handler().cloned();
775 Ok(list)
776 }
777 MaybeDetached::Attached(a) => {
778 let new_inner = create_handler(a, self_id);
779 let ans = new_inner.into_list().unwrap();
780
781 for (i, v) in self.get_value().into_list().unwrap().iter().enumerate() {
782 if let LoroValue::Container(id) = v {
783 ans.insert_container_with_txn(txn, i, create_handler(a, id.clone()))?;
784 } else {
785 ans.insert_with_txn(txn, i, v.clone())?;
786 }
787 }
788
789 Ok(ans)
790 }
791 }
792 }
793
794 fn get_attached(&self) -> Option<Self> {
795 match &self.inner {
796 MaybeDetached::Detached(d) => d.lock().unwrap().attached.clone().map(|x| Self {
797 inner: MaybeDetached::Attached(x),
798 }),
799 MaybeDetached::Attached(_a) => Some(self.clone()),
800 }
801 }
802
803 fn from_handler(h: Handler) -> Option<Self> {
804 match h {
805 Handler::List(x) => Some(x),
806 _ => None,
807 }
808 }
809
810 fn doc(&self) -> Option<LoroDoc> {
811 match &self.inner {
812 MaybeDetached::Detached(_) => None,
813 MaybeDetached::Attached(a) => Some(a.doc()),
814 }
815 }
816}
817
818#[derive(Clone)]
819pub struct UnknownHandler {
820 inner: BasicHandler,
821}
822
823impl Debug for UnknownHandler {
824 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
825 write!(f, "UnknownHandler")
826 }
827}
828
829impl UnknownHandler {
830 pub fn is_deleted(&self) -> bool {
831 self.inner.is_deleted()
832 }
833}
834
835impl HandlerTrait for UnknownHandler {
836 fn is_attached(&self) -> bool {
837 true
838 }
839
840 fn attached_handler(&self) -> Option<&BasicHandler> {
841 Some(&self.inner)
842 }
843
844 fn get_value(&self) -> LoroValue {
845 todo!()
846 }
847
848 fn get_deep_value(&self) -> LoroValue {
849 todo!()
850 }
851
852 fn kind(&self) -> ContainerType {
853 self.inner.id.container_type()
854 }
855
856 fn to_handler(&self) -> Handler {
857 Handler::Unknown(self.clone())
858 }
859
860 fn from_handler(h: Handler) -> Option<Self> {
861 match h {
862 Handler::Unknown(x) => Some(x),
863 _ => None,
864 }
865 }
866
867 fn attach(
868 &self,
869 _txn: &mut Transaction,
870 _parent: &BasicHandler,
871 self_id: ContainerID,
872 ) -> LoroResult<Self> {
873 let new_inner = create_handler(&self.inner, self_id);
874 let ans = new_inner.into_unknown().unwrap();
875 Ok(ans)
876 }
877
878 fn get_attached(&self) -> Option<Self> {
879 Some(self.clone())
880 }
881
882 fn doc(&self) -> Option<LoroDoc> {
883 Some(self.inner.doc())
884 }
885}
886
887#[derive(Clone, EnumAsInner, Debug)]
888pub enum Handler {
889 Text(TextHandler),
890 Map(MapHandler),
891 List(ListHandler),
892 MovableList(MovableListHandler),
893 Tree(TreeHandler),
894 #[cfg(feature = "counter")]
895 Counter(counter::CounterHandler),
896 Unknown(UnknownHandler),
897}
898
899impl HandlerTrait for Handler {
900 fn is_attached(&self) -> bool {
901 match self {
902 Self::Text(x) => x.is_attached(),
903 Self::Map(x) => x.is_attached(),
904 Self::List(x) => x.is_attached(),
905 Self::Tree(x) => x.is_attached(),
906 Self::MovableList(x) => x.is_attached(),
907 #[cfg(feature = "counter")]
908 Self::Counter(x) => x.is_attached(),
909 Self::Unknown(x) => x.is_attached(),
910 }
911 }
912
913 fn attached_handler(&self) -> Option<&BasicHandler> {
914 match self {
915 Self::Text(x) => x.attached_handler(),
916 Self::Map(x) => x.attached_handler(),
917 Self::List(x) => x.attached_handler(),
918 Self::MovableList(x) => x.attached_handler(),
919 Self::Tree(x) => x.attached_handler(),
920 #[cfg(feature = "counter")]
921 Self::Counter(x) => x.attached_handler(),
922 Self::Unknown(x) => x.attached_handler(),
923 }
924 }
925
926 fn get_value(&self) -> LoroValue {
927 match self {
928 Self::Text(x) => x.get_value(),
929 Self::Map(x) => x.get_value(),
930 Self::List(x) => x.get_value(),
931 Self::MovableList(x) => x.get_value(),
932 Self::Tree(x) => x.get_value(),
933 #[cfg(feature = "counter")]
934 Self::Counter(x) => x.get_value(),
935 Self::Unknown(x) => x.get_value(),
936 }
937 }
938
939 fn get_deep_value(&self) -> LoroValue {
940 match self {
941 Self::Text(x) => x.get_deep_value(),
942 Self::Map(x) => x.get_deep_value(),
943 Self::List(x) => x.get_deep_value(),
944 Self::MovableList(x) => x.get_deep_value(),
945 Self::Tree(x) => x.get_deep_value(),
946 #[cfg(feature = "counter")]
947 Self::Counter(x) => x.get_deep_value(),
948 Self::Unknown(x) => x.get_deep_value(),
949 }
950 }
951
952 fn kind(&self) -> ContainerType {
953 match self {
954 Self::Text(x) => x.kind(),
955 Self::Map(x) => x.kind(),
956 Self::List(x) => x.kind(),
957 Self::MovableList(x) => x.kind(),
958 Self::Tree(x) => x.kind(),
959 #[cfg(feature = "counter")]
960 Self::Counter(x) => x.kind(),
961 Self::Unknown(x) => x.kind(),
962 }
963 }
964
965 fn to_handler(&self) -> Handler {
966 match self {
967 Self::Text(x) => x.to_handler(),
968 Self::Map(x) => x.to_handler(),
969 Self::List(x) => x.to_handler(),
970 Self::MovableList(x) => x.to_handler(),
971 Self::Tree(x) => x.to_handler(),
972 #[cfg(feature = "counter")]
973 Self::Counter(x) => x.to_handler(),
974 Self::Unknown(x) => x.to_handler(),
975 }
976 }
977
978 fn attach(
979 &self,
980 txn: &mut Transaction,
981 parent: &BasicHandler,
982 self_id: ContainerID,
983 ) -> LoroResult<Self> {
984 match self {
985 Self::Text(x) => Ok(Handler::Text(x.attach(txn, parent, self_id)?)),
986 Self::Map(x) => Ok(Handler::Map(x.attach(txn, parent, self_id)?)),
987 Self::List(x) => Ok(Handler::List(x.attach(txn, parent, self_id)?)),
988 Self::MovableList(x) => Ok(Handler::MovableList(x.attach(txn, parent, self_id)?)),
989 Self::Tree(x) => Ok(Handler::Tree(x.attach(txn, parent, self_id)?)),
990 #[cfg(feature = "counter")]
991 Self::Counter(x) => Ok(Handler::Counter(x.attach(txn, parent, self_id)?)),
992 Self::Unknown(x) => Ok(Handler::Unknown(x.attach(txn, parent, self_id)?)),
993 }
994 }
995
996 fn get_attached(&self) -> Option<Self> {
997 match self {
998 Self::Text(x) => x.get_attached().map(Handler::Text),
999 Self::Map(x) => x.get_attached().map(Handler::Map),
1000 Self::List(x) => x.get_attached().map(Handler::List),
1001 Self::MovableList(x) => x.get_attached().map(Handler::MovableList),
1002 Self::Tree(x) => x.get_attached().map(Handler::Tree),
1003 #[cfg(feature = "counter")]
1004 Self::Counter(x) => x.get_attached().map(Handler::Counter),
1005 Self::Unknown(x) => x.get_attached().map(Handler::Unknown),
1006 }
1007 }
1008
1009 fn from_handler(h: Handler) -> Option<Self> {
1010 Some(h)
1011 }
1012
1013 fn doc(&self) -> Option<LoroDoc> {
1014 match self {
1015 Self::Text(x) => x.doc(),
1016 Self::Map(x) => x.doc(),
1017 Self::List(x) => x.doc(),
1018 Self::MovableList(x) => x.doc(),
1019 Self::Tree(x) => x.doc(),
1020 #[cfg(feature = "counter")]
1021 Self::Counter(x) => x.doc(),
1022 Self::Unknown(x) => x.doc(),
1023 }
1024 }
1025}
1026
1027impl Handler {
1028 pub(crate) fn new_attached(id: ContainerID, doc: LoroDoc) -> Self {
1029 let kind = id.container_type();
1030 let handler = BasicHandler {
1031 container_idx: doc.arena.register_container(&id),
1032 id,
1033 doc,
1034 };
1035
1036 match kind {
1037 ContainerType::Map => Self::Map(MapHandler {
1038 inner: handler.into(),
1039 }),
1040 ContainerType::List => Self::List(ListHandler {
1041 inner: handler.into(),
1042 }),
1043 ContainerType::Tree => Self::Tree(TreeHandler {
1044 inner: handler.into(),
1045 }),
1046 ContainerType::Text => Self::Text(TextHandler {
1047 inner: handler.into(),
1048 }),
1049 ContainerType::MovableList => Self::MovableList(MovableListHandler {
1050 inner: handler.into(),
1051 }),
1052 #[cfg(feature = "counter")]
1053 ContainerType::Counter => Self::Counter(counter::CounterHandler {
1054 inner: handler.into(),
1055 }),
1056 ContainerType::Unknown(_) => Self::Unknown(UnknownHandler { inner: handler }),
1057 }
1058 }
1059
1060 #[allow(unused)]
1061 pub(crate) fn new_unattached(kind: ContainerType) -> Self {
1062 match kind {
1063 ContainerType::Text => Self::Text(TextHandler::new_detached()),
1064 ContainerType::Map => Self::Map(MapHandler::new_detached()),
1065 ContainerType::List => Self::List(ListHandler::new_detached()),
1066 ContainerType::Tree => Self::Tree(TreeHandler::new_detached()),
1067 ContainerType::MovableList => Self::MovableList(MovableListHandler::new_detached()),
1068 #[cfg(feature = "counter")]
1069 ContainerType::Counter => Self::Counter(counter::CounterHandler::new_detached()),
1070 ContainerType::Unknown(_) => unreachable!(),
1071 }
1072 }
1073
1074 pub fn id(&self) -> ContainerID {
1075 match self {
1076 Self::Map(x) => x.id(),
1077 Self::List(x) => x.id(),
1078 Self::Text(x) => x.id(),
1079 Self::Tree(x) => x.id(),
1080 Self::MovableList(x) => x.id(),
1081 #[cfg(feature = "counter")]
1082 Self::Counter(x) => x.id(),
1083 Self::Unknown(x) => x.id(),
1084 }
1085 }
1086
1087 pub(crate) fn container_idx(&self) -> ContainerIdx {
1088 match self {
1089 Self::Map(x) => x.idx(),
1090 Self::List(x) => x.idx(),
1091 Self::Text(x) => x.idx(),
1092 Self::Tree(x) => x.idx(),
1093 Self::MovableList(x) => x.idx(),
1094 #[cfg(feature = "counter")]
1095 Self::Counter(x) => x.idx(),
1096 Self::Unknown(x) => x.idx(),
1097 }
1098 }
1099
1100 pub fn c_type(&self) -> ContainerType {
1101 match self {
1102 Self::Map(_) => ContainerType::Map,
1103 Self::List(_) => ContainerType::List,
1104 Self::Text(_) => ContainerType::Text,
1105 Self::Tree(_) => ContainerType::Tree,
1106 Self::MovableList(_) => ContainerType::MovableList,
1107 #[cfg(feature = "counter")]
1108 Self::Counter(_) => ContainerType::Counter,
1109 Self::Unknown(x) => x.id().container_type(),
1110 }
1111 }
1112
1113 fn get_deep_value(&self) -> LoroValue {
1114 match self {
1115 Self::Map(x) => x.get_deep_value(),
1116 Self::List(x) => x.get_deep_value(),
1117 Self::MovableList(x) => x.get_deep_value(),
1118 Self::Text(x) => x.get_deep_value(),
1119 Self::Tree(x) => x.get_deep_value(),
1120 #[cfg(feature = "counter")]
1121 Self::Counter(x) => x.get_deep_value(),
1122 Self::Unknown(x) => x.get_deep_value(),
1123 }
1124 }
1125
1126 pub(crate) fn apply_diff(
1127 &self,
1128 diff: Diff,
1129 container_remap: &mut FxHashMap<ContainerID, ContainerID>,
1130 ) -> LoroResult<()> {
1131 let on_container_remap = &mut |old_id, new_id| {
1134 container_remap.insert(old_id, new_id);
1135 };
1136 match self {
1137 Self::Map(x) => {
1138 let diff = diff.into_map().unwrap();
1139 for (key, value) in diff.updated.into_iter() {
1140 match value.value {
1141 Some(ValueOrHandler::Handler(h)) => {
1142 let old_id = h.id();
1143 let new_h = x.insert_container(
1144 &key,
1145 Handler::new_unattached(old_id.container_type()),
1146 )?;
1147 let new_id = new_h.id();
1148 on_container_remap(old_id, new_id);
1149 }
1150 Some(ValueOrHandler::Value(LoroValue::Container(old_id))) => {
1151 let new_h = x.insert_container(
1152 &key,
1153 Handler::new_unattached(old_id.container_type()),
1154 )?;
1155 let new_id = new_h.id();
1156 on_container_remap(old_id, new_id);
1157 }
1158 Some(ValueOrHandler::Value(v)) => {
1159 x.insert_without_skipping(&key, v)?;
1160 }
1161 None => {
1162 x.delete(&key)?;
1163 }
1164 }
1165 }
1166 }
1167 Self::Text(x) => {
1168 let delta = diff.into_text().unwrap();
1169 x.apply_delta(&TextDelta::from_text_diff(delta.iter()))?;
1170 }
1171 Self::List(x) => {
1172 let delta = diff.into_list().unwrap();
1173 x.apply_delta(delta, on_container_remap)?;
1174 }
1175 Self::MovableList(x) => {
1176 let delta = diff.into_list().unwrap();
1177 x.apply_delta(delta, container_remap)?;
1178 }
1179 Self::Tree(x) => {
1180 fn remap_tree_id(
1181 id: &mut TreeID,
1182 container_remap: &FxHashMap<ContainerID, ContainerID>,
1183 ) {
1184 let mut remapped = false;
1185 let mut map_id = id.associated_meta_container();
1186 while let Some(rid) = container_remap.get(&map_id) {
1187 remapped = true;
1188 map_id = rid.clone();
1189 }
1190 if remapped {
1191 *id = TreeID::new(
1192 *map_id.as_normal().unwrap().0,
1193 *map_id.as_normal().unwrap().1,
1194 )
1195 }
1196 }
1197 for diff in diff.into_tree().unwrap().diff {
1198 let mut target = diff.target;
1199 match diff.action {
1200 TreeExternalDiff::Create {
1201 mut parent,
1202 index: _,
1203 position,
1204 } => {
1205 if let TreeParentId::Node(p) = &mut parent {
1206 remap_tree_id(p, container_remap)
1207 }
1208 remap_tree_id(&mut target, container_remap);
1209 if !x.is_node_unexist(&target) && !x.is_node_deleted(&target)? {
1210 x.move_at_with_target_for_apply_diff(parent, position, target)?;
1223 } else {
1224 let new_target = x.__internal__next_tree_id();
1225 if x.create_at_with_target_for_apply_diff(
1226 parent, position, new_target,
1227 )? {
1228 container_remap.insert(
1229 target.associated_meta_container(),
1230 new_target.associated_meta_container(),
1231 );
1232 }
1233 }
1234 }
1235 TreeExternalDiff::Move {
1236 mut parent,
1237 index: _,
1238 position,
1239 old_parent: _,
1240 old_index: _,
1241 } => {
1242 if let TreeParentId::Node(p) = &mut parent {
1243 remap_tree_id(p, container_remap)
1244 }
1245 remap_tree_id(&mut target, container_remap);
1246 if x.is_node_unexist(&target) || x.is_node_deleted(&target).unwrap() {
1248 let new_target = x.__internal__next_tree_id();
1250 if x.create_at_with_target_for_apply_diff(
1251 parent, position, new_target,
1252 )? {
1253 container_remap.insert(
1254 target.associated_meta_container(),
1255 new_target.associated_meta_container(),
1256 );
1257 }
1258 } else {
1259 x.move_at_with_target_for_apply_diff(parent, position, target)?;
1260 }
1261 }
1262 TreeExternalDiff::Delete { .. } => {
1263 remap_tree_id(&mut target, container_remap);
1264 if !x.is_node_deleted(&target).unwrap() {
1265 x.delete(target)?;
1266 }
1267 }
1268 }
1269 }
1270 }
1271 #[cfg(feature = "counter")]
1272 Self::Counter(x) => {
1273 let delta = diff.into_counter().unwrap();
1274 x.increment(delta)?;
1275 }
1276 Self::Unknown(_) => {
1277 }
1279 }
1280
1281 Ok(())
1282 }
1283
1284 pub fn clear(&self) -> LoroResult<()> {
1285 match self {
1286 Handler::Text(text_handler) => text_handler.clear(),
1287 Handler::Map(map_handler) => map_handler.clear(),
1288 Handler::List(list_handler) => list_handler.clear(),
1289 Handler::MovableList(movable_list_handler) => movable_list_handler.clear(),
1290 Handler::Tree(tree_handler) => tree_handler.clear(),
1291 #[cfg(feature = "counter")]
1292 Handler::Counter(counter_handler) => counter_handler.clear(),
1293 Handler::Unknown(_unknown_handler) => Ok(()),
1294 }
1295 }
1296}
1297
1298#[derive(Clone, EnumAsInner, Debug)]
1299pub enum ValueOrHandler {
1300 Value(LoroValue),
1301 Handler(Handler),
1302}
1303
1304impl ValueOrHandler {
1305 pub(crate) fn from_value(value: LoroValue, doc: &Arc<LoroDocInner>) -> Self {
1306 if let LoroValue::Container(c) = value {
1307 ValueOrHandler::Handler(Handler::new_attached(c, LoroDoc::from_inner(doc.clone())))
1308 } else {
1309 ValueOrHandler::Value(value)
1310 }
1311 }
1312
1313 pub(crate) fn to_value(&self) -> LoroValue {
1314 match self {
1315 Self::Value(v) => v.clone(),
1316 Self::Handler(h) => LoroValue::Container(h.id().clone()),
1317 }
1318 }
1319
1320 pub(crate) fn to_deep_value(&self) -> LoroValue {
1321 match self {
1322 Self::Value(v) => v.clone(),
1323 Self::Handler(h) => h.get_deep_value(),
1324 }
1325 }
1326}
1327
1328impl From<LoroValue> for ValueOrHandler {
1329 fn from(value: LoroValue) -> Self {
1330 ValueOrHandler::Value(value)
1331 }
1332}
1333
1334impl TextHandler {
1335 pub fn new_detached() -> Self {
1340 Self {
1341 inner: MaybeDetached::new_detached(RichtextState::default()),
1342 }
1343 }
1344
1345 pub fn version_id(&self) -> Option<usize> {
1349 match &self.inner {
1350 MaybeDetached::Detached(_) => None,
1351 MaybeDetached::Attached(a) => {
1352 Some(a.with_state(|state| state.as_richtext_state_mut().unwrap().get_version_id()))
1353 }
1354 }
1355 }
1356
1357 pub fn get_richtext_value(&self) -> LoroValue {
1358 match &self.inner {
1359 MaybeDetached::Detached(t) => {
1360 let t = t.lock().unwrap();
1361 t.value.get_richtext_value()
1362 }
1363 MaybeDetached::Attached(a) => {
1364 a.with_state(|state| state.as_richtext_state_mut().unwrap().get_richtext_value())
1365 }
1366 }
1367 }
1368
1369 pub fn is_empty(&self) -> bool {
1370 match &self.inner {
1371 MaybeDetached::Detached(t) => t.lock().unwrap().value.is_empty(),
1372 MaybeDetached::Attached(a) => {
1373 a.with_state(|state| state.as_richtext_state_mut().unwrap().is_empty())
1374 }
1375 }
1376 }
1377
1378 pub fn len_utf8(&self) -> usize {
1379 match &self.inner {
1380 MaybeDetached::Detached(t) => {
1381 let t = t.lock().unwrap();
1382 t.value.len_utf8()
1383 }
1384 MaybeDetached::Attached(a) => {
1385 a.with_state(|state| state.as_richtext_state_mut().unwrap().len_utf8())
1386 }
1387 }
1388 }
1389
1390 pub fn len_utf16(&self) -> usize {
1391 match &self.inner {
1392 MaybeDetached::Detached(t) => {
1393 let t = t.lock().unwrap();
1394 t.value.len_utf16()
1395 }
1396 MaybeDetached::Attached(a) => {
1397 a.with_state(|state| state.as_richtext_state_mut().unwrap().len_utf16())
1398 }
1399 }
1400 }
1401
1402 pub fn len_unicode(&self) -> usize {
1403 match &self.inner {
1404 MaybeDetached::Detached(t) => {
1405 let t = t.lock().unwrap();
1406 t.value.len_unicode()
1407 }
1408 MaybeDetached::Attached(a) => {
1409 a.with_state(|state| state.as_richtext_state_mut().unwrap().len_unicode())
1410 }
1411 }
1412 }
1413
1414 pub fn len_event(&self) -> usize {
1417 if cfg!(feature = "wasm") {
1418 self.len_utf16()
1419 } else {
1420 self.len_unicode()
1421 }
1422 }
1423
1424 pub fn diagnose(&self) {
1425 match &self.inner {
1426 MaybeDetached::Detached(t) => {
1427 let t = t.lock().unwrap();
1428 t.value.diagnose();
1429 }
1430 MaybeDetached::Attached(a) => {
1431 a.with_state(|state| state.as_richtext_state_mut().unwrap().diagnose());
1432 }
1433 }
1434 }
1435
1436 pub fn iter(&self, mut callback: impl FnMut(&str) -> bool) {
1437 match &self.inner {
1438 MaybeDetached::Detached(t) => {
1439 let t = t.lock().unwrap();
1440 for span in t.value.iter() {
1441 if !callback(span.text.as_str()) {
1442 return;
1443 }
1444 }
1445 }
1446 MaybeDetached::Attached(a) => {
1447 a.with_state(|state| {
1448 state.as_richtext_state_mut().unwrap().iter(callback);
1449 });
1450 }
1451 }
1452 }
1453
1454 pub fn char_at(&self, pos: usize) -> LoroResult<char> {
1459 if pos >= self.len_event() {
1460 return Err(LoroError::OutOfBound {
1461 pos,
1462 len: self.len_event(),
1463 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
1464 });
1465 }
1466 if let Ok(c) = match &self.inner {
1467 MaybeDetached::Detached(t) => {
1468 let t = t.lock().unwrap();
1469 t.value.get_char_by_event_index(pos)
1470 }
1471 MaybeDetached::Attached(a) => a.with_state(|state| {
1472 state
1473 .as_richtext_state_mut()
1474 .unwrap()
1475 .get_char_by_event_index(pos)
1476 }),
1477 } {
1478 Ok(c)
1479 } else {
1480 Err(LoroError::OutOfBound {
1481 pos,
1482 len: self.len_event(),
1483 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
1484 })
1485 }
1486 }
1487
1488 pub fn slice(&self, start_index: usize, end_index: usize) -> LoroResult<String> {
1494 if end_index < start_index {
1495 return Err(LoroError::EndIndexLessThanStartIndex {
1496 start: start_index,
1497 end: end_index,
1498 });
1499 }
1500 match &self.inner {
1501 MaybeDetached::Detached(t) => {
1502 let t = t.lock().unwrap();
1503 t.value
1504 .get_text_slice_by_event_index(start_index, end_index - start_index)
1505 }
1506 MaybeDetached::Attached(a) => a.with_state(|state| {
1507 state
1508 .as_richtext_state_mut()
1509 .unwrap()
1510 .get_text_slice_by_event_index(start_index, end_index - start_index)
1511 }),
1512 }
1513 }
1514
1515 pub fn splice(&self, pos: usize, len: usize, s: &str) -> LoroResult<String> {
1522 let x = self.slice(pos, pos + len)?;
1523 self.delete(pos, len)?;
1524 self.insert(pos, s)?;
1525 Ok(x)
1526 }
1527
1528 pub fn splice_utf8(&self, pos: usize, len: usize, s: &str) -> LoroResult<()> {
1529 self.delete_utf8(pos, len)?;
1531 self.insert_utf8(pos, s)?;
1532 Ok(())
1533 }
1534
1535 pub fn insert(&self, pos: usize, s: &str) -> LoroResult<()> {
1542 match &self.inner {
1543 MaybeDetached::Detached(t) => {
1544 let mut t = t.lock().unwrap();
1545 let (index, _) = t
1546 .value
1547 .get_entity_index_for_text_insert(pos, PosType::Event)
1548 .unwrap();
1549 t.value.insert_at_entity_index(
1550 index,
1551 BytesSlice::from_bytes(s.as_bytes()),
1552 IdFull::NONE_ID,
1553 );
1554 Ok(())
1555 }
1556 MaybeDetached::Attached(a) => a.with_txn(|txn| self.insert_with_txn(txn, pos, s)),
1557 }
1558 }
1559
1560 pub fn insert_utf8(&self, pos: usize, s: &str) -> LoroResult<()> {
1561 match &self.inner {
1562 MaybeDetached::Detached(t) => {
1563 let mut t = t.lock().unwrap();
1564 let (index, _) = t
1565 .value
1566 .get_entity_index_for_text_insert(pos, PosType::Bytes)
1567 .unwrap();
1568 t.value.insert_at_entity_index(
1569 index,
1570 BytesSlice::from_bytes(s.as_bytes()),
1571 IdFull::NONE_ID,
1572 );
1573 Ok(())
1574 }
1575 MaybeDetached::Attached(a) => a.with_txn(|txn| self.insert_with_txn_utf8(txn, pos, s)),
1576 }
1577 }
1578
1579 pub fn insert_unicode(&self, pos: usize, s: &str) -> LoroResult<()> {
1580 match &self.inner {
1581 MaybeDetached::Detached(t) => {
1582 let mut t = t.lock().unwrap();
1583 let (index, _) = t
1584 .value
1585 .get_entity_index_for_text_insert(pos, PosType::Unicode)
1586 .unwrap();
1587 t.value.insert_at_entity_index(
1588 index,
1589 BytesSlice::from_bytes(s.as_bytes()),
1590 IdFull::NONE_ID,
1591 );
1592 Ok(())
1593 }
1594 MaybeDetached::Attached(a) => a.with_txn(|txn| {
1595 self.insert_with_txn_and_attr(txn, pos, s, None, PosType::Unicode)?;
1596 Ok(())
1597 }),
1598 }
1599 }
1600
1601 pub fn insert_with_txn(&self, txn: &mut Transaction, pos: usize, s: &str) -> LoroResult<()> {
1606 self.insert_with_txn_and_attr(txn, pos, s, None, PosType::Event)?;
1607 Ok(())
1608 }
1609
1610 pub fn insert_with_txn_utf8(
1611 &self,
1612 txn: &mut Transaction,
1613 pos: usize,
1614 s: &str,
1615 ) -> LoroResult<()> {
1616 self.insert_with_txn_and_attr(txn, pos, s, None, PosType::Bytes)?;
1617 Ok(())
1618 }
1619
1620 pub fn delete(&self, pos: usize, len: usize) -> LoroResult<()> {
1627 match &self.inner {
1628 MaybeDetached::Detached(t) => {
1629 let mut t = t.lock().unwrap();
1630 let ranges = t
1631 .value
1632 .get_text_entity_ranges(pos, len, PosType::Event)
1633 .unwrap();
1634 for range in ranges.iter().rev() {
1635 t.value
1636 .drain_by_entity_index(range.entity_start, range.entity_len(), None);
1637 }
1638 Ok(())
1639 }
1640 MaybeDetached::Attached(a) => a.with_txn(|txn| self.delete_with_txn(txn, pos, len)),
1641 }
1642 }
1643
1644 pub fn delete_utf8(&self, pos: usize, len: usize) -> LoroResult<()> {
1645 match &self.inner {
1646 MaybeDetached::Detached(t) => {
1647 let mut t = t.lock().unwrap();
1648 let ranges = t.value.get_text_entity_ranges(pos, len, PosType::Bytes)?;
1649 for range in ranges.iter().rev() {
1650 t.value
1651 .drain_by_entity_index(range.entity_start, range.entity_len(), None);
1652 }
1653 Ok(())
1654 }
1655 MaybeDetached::Attached(a) => {
1656 a.with_txn(|txn| self.delete_with_txn_inline(txn, pos, len, PosType::Bytes))
1657 }
1658 }
1659 }
1660
1661 pub fn delete_unicode(&self, pos: usize, len: usize) -> LoroResult<()> {
1662 match &self.inner {
1663 MaybeDetached::Detached(t) => {
1664 let mut t = t.lock().unwrap();
1665 let ranges = t.value.get_text_entity_ranges(pos, len, PosType::Unicode)?;
1666 for range in ranges.iter().rev() {
1667 t.value
1668 .drain_by_entity_index(range.entity_start, range.entity_len(), None);
1669 }
1670 Ok(())
1671 }
1672 MaybeDetached::Attached(a) => {
1673 a.with_txn(|txn| self.delete_with_txn_inline(txn, pos, len, PosType::Unicode))
1674 }
1675 }
1676 }
1677
1678 fn insert_with_txn_and_attr(
1681 &self,
1682 txn: &mut Transaction,
1683 pos: usize,
1684 s: &str,
1685 attr: Option<&FxHashMap<String, LoroValue>>,
1686 pos_type: PosType,
1687 ) -> Result<Vec<(InternalString, LoroValue)>, LoroError> {
1688 if s.is_empty() {
1689 return Ok(Vec::new());
1690 }
1691
1692 match pos_type {
1693 PosType::Event => {
1694 if pos > self.len_event() {
1695 return Err(LoroError::OutOfBound {
1696 pos,
1697 len: self.len_event(),
1698 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
1699 });
1700 }
1701 }
1702 PosType::Bytes => {
1703 if pos > self.len_utf8() {
1704 return Err(LoroError::OutOfBound {
1705 pos,
1706 len: self.len_utf8(),
1707 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
1708 });
1709 }
1710 }
1711 PosType::Unicode => {
1712 if pos > self.len_unicode() {
1713 return Err(LoroError::OutOfBound {
1714 pos,
1715 len: self.len_unicode(),
1716 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
1717 });
1718 }
1719 }
1720 PosType::Entity => {}
1721 PosType::Utf16 => {
1722 if pos > self.len_utf16() {
1723 return Err(LoroError::OutOfBound {
1724 pos,
1725 len: self.len_utf16(),
1726 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
1727 });
1728 }
1729 }
1730 }
1731
1732 let inner = self.inner.try_attached_state()?;
1733 let (entity_index, event_index, styles) = inner.with_state(|state| {
1734 let richtext_state = state.as_richtext_state_mut().unwrap();
1735 let ret = richtext_state.get_entity_index_for_text_insert(pos, pos_type);
1736 let (entity_index, cursor) = match ret {
1737 Err(_) => match pos_type {
1738 PosType::Bytes => {
1739 return (
1740 Err(LoroError::UTF8InUnicodeCodePoint { pos }),
1741 0,
1742 StyleMeta::empty(),
1743 );
1744 }
1745 PosType::Utf16 | PosType::Event => {
1746 return (
1747 Err(LoroError::UTF16InUnicodeCodePoint { pos }),
1748 0,
1749 StyleMeta::empty(),
1750 );
1751 }
1752 _ => unreachable!(),
1753 },
1754 Ok(x) => x,
1755 };
1756 let event_index = if let Some(cursor) = cursor {
1757 if pos_type == PosType::Event {
1758 debug_assert_eq!(
1759 richtext_state.get_event_index_by_cursor(cursor),
1760 pos,
1761 "pos={} cursor={:?} state={:#?}",
1762 pos,
1763 cursor,
1764 &richtext_state
1765 );
1766 pos
1767 } else {
1768 richtext_state.get_event_index_by_cursor(cursor)
1769 }
1770 } else {
1771 assert_eq!(entity_index, 0);
1772 0
1773 };
1774 let styles = richtext_state.get_styles_at_entity_index(entity_index);
1775 (Ok(entity_index), event_index, styles)
1776 });
1777
1778 let entity_index = match entity_index {
1779 Err(x) => return Err(x),
1780 _ => entity_index.unwrap(),
1781 };
1782
1783 let mut override_styles = Vec::new();
1784 if let Some(attr) = attr {
1785 let map: FxHashMap<_, _> = styles.iter().map(|x| (x.0.clone(), x.1.data)).collect();
1787 for (key, style) in map.iter() {
1788 match attr.get(key.deref()) {
1789 Some(v) if v == style => {}
1790 new_style_value => {
1791 let new_style_value = new_style_value.cloned().unwrap_or(LoroValue::Null);
1793 override_styles.push((key.clone(), new_style_value));
1794 }
1795 }
1796 }
1797
1798 for (key, style) in attr.iter() {
1799 let key = key.as_str().into();
1800 if !map.contains_key(&key) {
1801 override_styles.push((key, style.clone()));
1802 }
1803 }
1804 }
1805
1806 let unicode_len = s.chars().count();
1807 let event_len = if cfg!(feature = "wasm") {
1808 count_utf16_len(s.as_bytes())
1809 } else {
1810 unicode_len
1811 };
1812
1813 txn.apply_local_op(
1814 inner.container_idx,
1815 crate::op::RawOpContent::List(crate::container::list::list_op::ListOp::Insert {
1816 slice: ListSlice::RawStr {
1817 str: Cow::Borrowed(s),
1818 unicode_len,
1819 },
1820 pos: entity_index,
1821 }),
1822 EventHint::InsertText {
1823 pos: event_index as u32,
1824 styles,
1825 unicode_len: unicode_len as u32,
1826 event_len: event_len as u32,
1827 },
1828 &inner.doc,
1829 )?;
1830
1831 Ok(override_styles)
1832 }
1833
1834 pub fn delete_with_txn(&self, txn: &mut Transaction, pos: usize, len: usize) -> LoroResult<()> {
1839 self.delete_with_txn_inline(txn, pos, len, PosType::Event)
1840 }
1841
1842 fn delete_with_txn_inline(
1843 &self,
1844 txn: &mut Transaction,
1845 pos: usize,
1846 len: usize,
1847 pos_type: PosType,
1848 ) -> LoroResult<()> {
1849 if len == 0 {
1850 return Ok(());
1851 }
1852
1853 match pos_type {
1854 PosType::Event => {
1855 if pos + len > self.len_event() {
1856 error!("pos={} len={} len_event={}", pos, len, self.len_event());
1857 return Err(LoroError::OutOfBound {
1858 pos: pos + len,
1859 len: self.len_event(),
1860 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
1861 });
1862 }
1863 }
1864 PosType::Bytes => {
1865 if pos + len > self.len_utf8() {
1866 error!("pos={} len={} len_bytes={}", pos, len, self.len_utf8());
1867 return Err(LoroError::OutOfBound {
1868 pos: pos + len,
1869 len: self.len_utf8(),
1870 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
1871 });
1872 }
1873 }
1874 _ => (),
1875 }
1876
1877 let inner = self.inner.try_attached_state()?;
1878 let s = tracing::span!(tracing::Level::INFO, "delete", "pos={} len={}", pos, len);
1879 let _e = s.enter();
1880 let mut event_pos = 0;
1881 let mut event_len = 0;
1882 let ranges = inner.with_state(|state| {
1883 let richtext_state = state.as_richtext_state_mut().unwrap();
1884 event_pos = richtext_state.index_to_event_index(pos, pos_type);
1885 let event_end = richtext_state.index_to_event_index(pos + len, pos_type);
1886 event_len = event_end - event_pos;
1887
1888 richtext_state.get_text_entity_ranges_in_event_index_range(event_pos, event_len)
1889 })?;
1890
1891 let pos = event_pos as isize;
1893 let len = event_len as isize;
1894 let mut event_end = pos + len;
1895 for range in ranges.iter().rev() {
1896 let event_start = event_end - range.event_len as isize;
1897 txn.apply_local_op(
1898 inner.container_idx,
1899 crate::op::RawOpContent::List(ListOp::Delete(DeleteSpanWithId::new(
1900 range.id_start,
1901 range.entity_start as isize,
1902 range.entity_len() as isize,
1903 ))),
1904 EventHint::DeleteText {
1905 span: DeleteSpan {
1906 pos: event_start,
1907 signed_len: range.event_len as isize,
1908 },
1909 unicode_len: range.entity_len(),
1910 },
1911 &inner.doc,
1912 )?;
1913 event_end = event_start;
1914 }
1915
1916 Ok(())
1917 }
1918
1919 pub fn mark(
1926 &self,
1927 start: usize,
1928 end: usize,
1929 key: impl Into<InternalString>,
1930 value: LoroValue,
1931 ) -> LoroResult<()> {
1932 match &self.inner {
1933 MaybeDetached::Detached(t) => {
1934 let mut g = t.lock().unwrap();
1935 self.mark_for_detached(&mut g.value, key, &value, start, end, false)
1936 }
1937 MaybeDetached::Attached(a) => {
1938 a.with_txn(|txn| self.mark_with_txn(txn, start, end, key, value, false))
1939 }
1940 }
1941 }
1942
1943 fn mark_for_detached(
1944 &self,
1945 state: &mut RichtextState,
1946 key: impl Into<InternalString>,
1947 value: &LoroValue,
1948 start: usize,
1949 end: usize,
1950 is_delete: bool,
1951 ) -> Result<(), LoroError> {
1952 let key: InternalString = key.into();
1953 let len = state.len_event();
1954 if start >= end {
1955 return Err(loro_common::LoroError::ArgErr(
1956 "Start must be less than end".to_string().into_boxed_str(),
1957 ));
1958 }
1959 if end > len {
1960 return Err(LoroError::OutOfBound {
1961 pos: end,
1962 len,
1963 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
1964 });
1965 }
1966 let (entity_range, styles) =
1967 state.get_entity_range_and_text_styles_at_range(start..end, PosType::Event);
1968 if let Some(styles) = styles {
1969 if styles.has_key_value(&key, value) {
1970 return Ok(());
1972 }
1973 }
1974
1975 let style_op = Arc::new(StyleOp {
1976 lamport: 0,
1977 peer: 0,
1978 cnt: 0,
1979 key,
1980 value: value.clone(),
1981 info: if is_delete {
1983 TextStyleInfoFlag::BOLD.to_delete()
1984 } else {
1985 TextStyleInfoFlag::BOLD
1986 },
1987 });
1988 state.mark_with_entity_index(entity_range, style_op);
1989 Ok(())
1990 }
1991
1992 pub fn unmark(
1999 &self,
2000 start: usize,
2001 end: usize,
2002 key: impl Into<InternalString>,
2003 ) -> LoroResult<()> {
2004 match &self.inner {
2005 MaybeDetached::Detached(t) => self.mark_for_detached(
2006 &mut t.lock().unwrap().value,
2007 key,
2008 &LoroValue::Null,
2009 start,
2010 end,
2011 true,
2012 ),
2013 MaybeDetached::Attached(a) => {
2014 a.with_txn(|txn| self.mark_with_txn(txn, start, end, key, LoroValue::Null, true))
2015 }
2016 }
2017 }
2018
2019 pub fn mark_with_txn(
2024 &self,
2025 txn: &mut Transaction,
2026 start: usize,
2027 end: usize,
2028 key: impl Into<InternalString>,
2029 value: LoroValue,
2030 is_delete: bool,
2031 ) -> LoroResult<()> {
2032 if start >= end {
2033 return Err(loro_common::LoroError::ArgErr(
2034 "Start must be less than end".to_string().into_boxed_str(),
2035 ));
2036 }
2037
2038 let len = self.len_event();
2039 if end > len {
2040 return Err(LoroError::OutOfBound {
2041 pos: end,
2042 len,
2043 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2044 });
2045 }
2046
2047 let inner = self.inner.try_attached_state()?;
2048 let key: InternalString = key.into();
2049
2050 let mut doc_state = inner.doc.state.lock().unwrap();
2051 let (entity_range, skip) = doc_state.with_state_mut(inner.container_idx, |state| {
2052 let (entity_range, styles) = state
2053 .as_richtext_state_mut()
2054 .unwrap()
2055 .get_entity_range_and_styles_at_range(start..end, PosType::Event);
2056
2057 let skip = match styles {
2058 Some(styles) if styles.has_key_value(&key, &value) => {
2059 true
2061 }
2062 _ => false,
2063 };
2064 (entity_range, skip)
2065 });
2066
2067 if skip {
2068 return Ok(());
2069 }
2070
2071 let entity_start = entity_range.start;
2072 let entity_end = entity_range.end;
2073 let style_config = doc_state.config.text_style_config.try_read().unwrap();
2074 let flag = if is_delete {
2075 style_config
2076 .get_style_flag_for_unmark(&key)
2077 .ok_or_else(|| LoroError::StyleConfigMissing(key.clone()))?
2078 } else {
2079 style_config
2080 .get_style_flag(&key)
2081 .ok_or_else(|| LoroError::StyleConfigMissing(key.clone()))?
2082 };
2083
2084 drop(style_config);
2085 drop(doc_state);
2086 txn.apply_local_op(
2087 inner.container_idx,
2088 crate::op::RawOpContent::List(ListOp::StyleStart {
2089 start: entity_start as u32,
2090 end: entity_end as u32,
2091 key: key.clone(),
2092 value: value.clone(),
2093 info: flag,
2094 }),
2095 EventHint::Mark {
2096 start: start as u32,
2097 end: end as u32,
2098 style: crate::container::richtext::Style { key, data: value },
2099 },
2100 &inner.doc,
2101 )?;
2102
2103 txn.apply_local_op(
2104 inner.container_idx,
2105 crate::op::RawOpContent::List(ListOp::StyleEnd),
2106 EventHint::MarkEnd,
2107 &inner.doc,
2108 )?;
2109
2110 Ok(())
2111 }
2112
2113 pub fn check(&self) {
2114 match &self.inner {
2115 MaybeDetached::Detached(t) => {
2116 let t = t.lock().unwrap();
2117 t.value.check_consistency_between_content_and_style_ranges();
2118 }
2119 MaybeDetached::Attached(a) => a.with_state(|state| {
2120 state
2121 .as_richtext_state_mut()
2122 .unwrap()
2123 .check_consistency_between_content_and_style_ranges();
2124 }),
2125 }
2126 }
2127
2128 pub fn apply_delta(&self, delta: &[TextDelta]) -> LoroResult<()> {
2129 match &self.inner {
2130 MaybeDetached::Detached(t) => {
2131 let _t = t.lock().unwrap();
2132 Err(LoroError::NotImplemented(
2134 "`apply_delta` on a detached text container",
2135 ))
2136 }
2137 MaybeDetached::Attached(a) => a.with_txn(|txn| self.apply_delta_with_txn(txn, delta)),
2138 }
2139 }
2140
2141 pub fn apply_delta_with_txn(
2142 &self,
2143 txn: &mut Transaction,
2144 delta: &[TextDelta],
2145 ) -> LoroResult<()> {
2146 let mut index = 0;
2147 struct PendingMark {
2148 start: usize,
2149 end: usize,
2150 attributes: FxHashMap<InternalString, LoroValue>,
2151 }
2152 let mut marks: Vec<PendingMark> = Vec::new();
2153 for d in delta {
2154 match d {
2155 TextDelta::Insert { insert, attributes } => {
2156 let end = index + event_len(insert.as_str());
2157 let override_styles = self.insert_with_txn_and_attr(
2158 txn,
2159 index,
2160 insert.as_str(),
2161 Some(attributes.as_ref().unwrap_or(&Default::default())),
2162 PosType::Event,
2163 )?;
2164
2165 let mut pending_mark = PendingMark {
2166 start: index,
2167 end,
2168 attributes: FxHashMap::default(),
2169 };
2170 for (key, value) in override_styles {
2171 pending_mark.attributes.insert(key, value);
2172 }
2173 marks.push(pending_mark);
2174 index = end;
2175 }
2176 TextDelta::Delete { delete } => {
2177 self.delete_with_txn(txn, index, *delete)?;
2178 }
2179 TextDelta::Retain { attributes, retain } => {
2180 let end = index + *retain;
2181 match attributes {
2182 Some(attr) if !attr.is_empty() => {
2183 let mut pending_mark = PendingMark {
2184 start: index,
2185 end,
2186 attributes: FxHashMap::default(),
2187 };
2188 for (key, value) in attr {
2189 pending_mark
2190 .attributes
2191 .insert(key.deref().into(), value.clone());
2192 }
2193 marks.push(pending_mark);
2194 }
2195 _ => {}
2196 }
2197 index = end;
2198 }
2199 }
2200 }
2201
2202 let mut len = self.len_event();
2203 for pending_mark in marks {
2204 if pending_mark.start >= len {
2205 self.insert_with_txn(txn, len, &"\n".repeat(pending_mark.start - len + 1))?;
2206 len = pending_mark.start;
2207 }
2208
2209 for (key, value) in pending_mark.attributes {
2210 self.mark_with_txn(
2211 txn,
2212 pending_mark.start,
2213 pending_mark.end,
2214 key.deref(),
2215 value,
2216 false,
2217 )?;
2218 }
2219 }
2220
2221 Ok(())
2222 }
2223
2224 pub fn update(&self, text: &str, options: UpdateOptions) -> Result<(), UpdateTimeoutError> {
2225 let old_str = self.to_string();
2226 let new = text.chars().map(|x| x as u32).collect::<Vec<u32>>();
2227 let old = old_str.chars().map(|x| x as u32).collect::<Vec<u32>>();
2228 diff(
2229 &mut OperateProxy::new(text_update::DiffHook::new(self, &new)),
2230 options,
2231 &old,
2232 &new,
2233 )?;
2234 Ok(())
2235 }
2236
2237 pub fn update_by_line(
2238 &self,
2239 text: &str,
2240 options: UpdateOptions,
2241 ) -> Result<(), UpdateTimeoutError> {
2242 let hook = text_update::DiffHookForLine::new(self, text);
2243 let old_lines = hook.get_old_arr().to_vec();
2244 let new_lines = hook.get_new_arr().to_vec();
2245 diff(
2246 &mut OperateProxy::new(hook),
2247 options,
2248 &old_lines,
2249 &new_lines,
2250 )
2251 }
2252
2253 #[allow(clippy::inherent_to_string)]
2254 pub fn to_string(&self) -> String {
2255 match &self.inner {
2256 MaybeDetached::Detached(t) => t.lock().unwrap().value.to_string(),
2257 MaybeDetached::Attached(a) => a.get_value().into_string().unwrap().unwrap(),
2258 }
2259 }
2260
2261 pub fn get_cursor(&self, event_index: usize, side: Side) -> Option<Cursor> {
2262 self.get_cursor_internal(event_index, side, true)
2263 }
2264
2265 pub(crate) fn get_cursor_internal(
2267 &self,
2268 index: usize,
2269 side: Side,
2270 get_by_event_index: bool,
2271 ) -> Option<Cursor> {
2272 match &self.inner {
2273 MaybeDetached::Detached(_) => None,
2274 MaybeDetached::Attached(a) => {
2275 let (id, len, origin_pos) = a.with_state(|s| {
2276 let s = s.as_richtext_state_mut().unwrap();
2277 (
2278 s.get_stable_position(index, get_by_event_index),
2279 if get_by_event_index {
2280 s.len_event()
2281 } else {
2282 s.len_unicode()
2283 },
2284 if get_by_event_index {
2285 s.event_index_to_unicode_index(index)
2286 } else {
2287 index
2288 },
2289 )
2290 });
2291
2292 if len == 0 {
2293 return Some(Cursor {
2294 id: None,
2295 container: self.id(),
2296 side: if side == Side::Middle {
2297 Side::Left
2298 } else {
2299 side
2300 },
2301 origin_pos: 0,
2302 });
2303 }
2304
2305 if len <= index {
2306 return Some(Cursor {
2307 id: None,
2308 container: self.id(),
2309 side: Side::Right,
2310 origin_pos: len,
2311 });
2312 }
2313
2314 let id = id?;
2315 Some(Cursor {
2316 id: Some(id),
2317 container: self.id(),
2318 side,
2319 origin_pos,
2320 })
2321 }
2322 }
2323 }
2324
2325 pub(crate) fn convert_entity_index_to_event_index(&self, entity_index: usize) -> usize {
2326 match &self.inner {
2327 MaybeDetached::Detached(s) => s
2328 .lock()
2329 .unwrap()
2330 .value
2331 .entity_index_to_event_index(entity_index),
2332 MaybeDetached::Attached(a) => {
2333 let mut pos = 0;
2334 a.with_state(|s| {
2335 let s = s.as_richtext_state_mut().unwrap();
2336 pos = s.entity_index_to_event_index(entity_index);
2337 });
2338 pos
2339 }
2340 }
2341 }
2342
2343 fn get_delta(&self) -> Vec<TextDelta> {
2344 self.with_state(|state| {
2345 let state = state.as_richtext_state_mut().unwrap();
2346 Ok(state.get_delta())
2347 })
2348 .unwrap()
2349 }
2350
2351 pub fn is_deleted(&self) -> bool {
2352 match &self.inner {
2353 MaybeDetached::Detached(_) => false,
2354 MaybeDetached::Attached(a) => a.is_deleted(),
2355 }
2356 }
2357
2358 pub fn push_str(&self, s: &str) -> LoroResult<()> {
2359 self.insert_utf8(self.len_utf8(), s)
2360 }
2361
2362 pub fn clear(&self) -> LoroResult<()> {
2363 match &self.inner {
2364 MaybeDetached::Detached(mutex) => {
2365 let mut t = mutex.lock().unwrap();
2366 let len = t.value.len_unicode();
2367 let ranges = t.value.get_text_entity_ranges(0, len, PosType::Unicode)?;
2368 for range in ranges.iter().rev() {
2369 t.value
2370 .drain_by_entity_index(range.entity_start, range.entity_len(), None);
2371 }
2372 Ok(())
2373 }
2374 MaybeDetached::Attached(a) => a.with_txn(|txn| {
2375 let len = a.with_state(|s| s.as_richtext_state_mut().unwrap().len_unicode());
2376 self.delete_with_txn_inline(txn, 0, len, PosType::Unicode)
2377 }),
2378 }
2379 }
2380}
2381
2382fn event_len(s: &str) -> usize {
2383 if cfg!(feature = "wasm") {
2384 count_utf16_len(s.as_bytes())
2385 } else {
2386 s.chars().count()
2387 }
2388}
2389
2390impl ListHandler {
2391 pub fn new_detached() -> Self {
2395 Self {
2396 inner: MaybeDetached::new_detached(Vec::new()),
2397 }
2398 }
2399
2400 pub fn insert(&self, pos: usize, v: impl Into<LoroValue>) -> LoroResult<()> {
2401 match &self.inner {
2402 MaybeDetached::Detached(l) => {
2403 let mut list = l.lock().unwrap();
2404 list.value.insert(pos, ValueOrHandler::Value(v.into()));
2405 Ok(())
2406 }
2407 MaybeDetached::Attached(a) => {
2408 a.with_txn(|txn| self.insert_with_txn(txn, pos, v.into()))
2409 }
2410 }
2411 }
2412
2413 pub fn insert_with_txn(
2414 &self,
2415 txn: &mut Transaction,
2416 pos: usize,
2417 v: LoroValue,
2418 ) -> LoroResult<()> {
2419 if pos > self.len() {
2420 return Err(LoroError::OutOfBound {
2421 pos,
2422 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2423 len: self.len(),
2424 });
2425 }
2426
2427 let inner = self.inner.try_attached_state()?;
2428 if let Some(_container) = v.as_container() {
2429 return Err(LoroError::ArgErr(
2430 INSERT_CONTAINER_VALUE_ARG_ERROR
2431 .to_string()
2432 .into_boxed_str(),
2433 ));
2434 }
2435
2436 txn.apply_local_op(
2437 inner.container_idx,
2438 crate::op::RawOpContent::List(crate::container::list::list_op::ListOp::Insert {
2439 slice: ListSlice::RawData(Cow::Owned(vec![v.clone()])),
2440 pos,
2441 }),
2442 EventHint::InsertList { len: 1, pos },
2443 &inner.doc,
2444 )
2445 }
2446
2447 pub fn push(&self, v: impl Into<LoroValue>) -> LoroResult<()> {
2448 match &self.inner {
2449 MaybeDetached::Detached(l) => {
2450 let mut list = l.lock().unwrap();
2451 list.value.push(ValueOrHandler::Value(v.into()));
2452 Ok(())
2453 }
2454 MaybeDetached::Attached(a) => a.with_txn(|txn| self.push_with_txn(txn, v.into())),
2455 }
2456 }
2457
2458 pub fn push_with_txn(&self, txn: &mut Transaction, v: LoroValue) -> LoroResult<()> {
2459 let pos = self.len();
2460 self.insert_with_txn(txn, pos, v)
2461 }
2462
2463 pub fn pop(&self) -> LoroResult<Option<LoroValue>> {
2464 match &self.inner {
2465 MaybeDetached::Detached(l) => {
2466 let mut list = l.lock().unwrap();
2467 Ok(list.value.pop().map(|v| v.to_value()))
2468 }
2469 MaybeDetached::Attached(a) => a.with_txn(|txn| self.pop_with_txn(txn)),
2470 }
2471 }
2472
2473 pub fn pop_with_txn(&self, txn: &mut Transaction) -> LoroResult<Option<LoroValue>> {
2474 let len = self.len();
2475 if len == 0 {
2476 return Ok(None);
2477 }
2478
2479 let v = self.get(len - 1);
2480 self.delete_with_txn(txn, len - 1, 1)?;
2481 Ok(v)
2482 }
2483
2484 pub fn insert_container<H: HandlerTrait>(&self, pos: usize, child: H) -> LoroResult<H> {
2485 match &self.inner {
2486 MaybeDetached::Detached(l) => {
2487 let mut list = l.lock().unwrap();
2488 list.value
2489 .insert(pos, ValueOrHandler::Handler(child.to_handler()));
2490 Ok(child)
2491 }
2492 MaybeDetached::Attached(a) => {
2493 a.with_txn(|txn| self.insert_container_with_txn(txn, pos, child))
2494 }
2495 }
2496 }
2497
2498 pub fn push_container<H: HandlerTrait>(&self, child: H) -> LoroResult<H> {
2499 self.insert_container(self.len(), child)
2500 }
2501
2502 pub fn insert_container_with_txn<H: HandlerTrait>(
2503 &self,
2504 txn: &mut Transaction,
2505 pos: usize,
2506 child: H,
2507 ) -> LoroResult<H> {
2508 if pos > self.len() {
2509 return Err(LoroError::OutOfBound {
2510 pos,
2511 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2512 len: self.len(),
2513 });
2514 }
2515
2516 let inner = self.inner.try_attached_state()?;
2517 let id = txn.next_id();
2518 let container_id = ContainerID::new_normal(id, child.kind());
2519 let v = LoroValue::Container(container_id.clone());
2520 txn.apply_local_op(
2521 inner.container_idx,
2522 crate::op::RawOpContent::List(crate::container::list::list_op::ListOp::Insert {
2523 slice: ListSlice::RawData(Cow::Owned(vec![v.clone()])),
2524 pos,
2525 }),
2526 EventHint::InsertList { len: 1, pos },
2527 &inner.doc,
2528 )?;
2529 let ans = child.attach(txn, inner, container_id)?;
2530 Ok(ans)
2531 }
2532
2533 pub fn delete(&self, pos: usize, len: usize) -> LoroResult<()> {
2534 match &self.inner {
2535 MaybeDetached::Detached(l) => {
2536 let mut list = l.lock().unwrap();
2537 list.value.drain(pos..pos + len);
2538 Ok(())
2539 }
2540 MaybeDetached::Attached(a) => a.with_txn(|txn| self.delete_with_txn(txn, pos, len)),
2541 }
2542 }
2543
2544 pub fn delete_with_txn(&self, txn: &mut Transaction, pos: usize, len: usize) -> LoroResult<()> {
2545 if len == 0 {
2546 return Ok(());
2547 }
2548
2549 if pos + len > self.len() {
2550 return Err(LoroError::OutOfBound {
2551 pos: pos + len,
2552 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2553 len: self.len(),
2554 });
2555 }
2556
2557 let inner = self.inner.try_attached_state()?;
2558 let ids: Vec<_> = inner.with_state(|state| {
2559 let list = state.as_list_state().unwrap();
2560 (pos..pos + len)
2561 .map(|i| list.get_id_at(i).unwrap())
2562 .collect()
2563 });
2564
2565 for id in ids.into_iter() {
2566 txn.apply_local_op(
2567 inner.container_idx,
2568 crate::op::RawOpContent::List(ListOp::Delete(DeleteSpanWithId::new(
2569 id.id(),
2570 pos as isize,
2571 1,
2572 ))),
2573 EventHint::DeleteList(DeleteSpan::new(pos as isize, 1)),
2574 &inner.doc,
2575 )?;
2576 }
2577
2578 Ok(())
2579 }
2580
2581 pub fn get_child_handler(&self, index: usize) -> LoroResult<Handler> {
2582 match &self.inner {
2583 MaybeDetached::Detached(l) => {
2584 let list = l.lock().unwrap();
2585 let value = list.value.get(index).ok_or(LoroError::OutOfBound {
2586 pos: index,
2587 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2588 len: list.value.len(),
2589 })?;
2590 match value {
2591 ValueOrHandler::Handler(h) => Ok(h.clone()),
2592 _ => Err(LoroError::ArgErr(
2593 format!(
2594 "Expected container at index {}, but found {:?}",
2595 index, value
2596 )
2597 .into_boxed_str(),
2598 )),
2599 }
2600 }
2601 MaybeDetached::Attached(a) => {
2602 let Some(value) = a.with_state(|state| {
2603 state.as_list_state().as_ref().unwrap().get(index).cloned()
2604 }) else {
2605 return Err(LoroError::OutOfBound {
2606 pos: index,
2607 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2608 len: a.with_state(|state| state.as_list_state().unwrap().len()),
2609 });
2610 };
2611 match value {
2612 LoroValue::Container(id) => Ok(create_handler(a, id)),
2613 _ => Err(LoroError::ArgErr(
2614 format!(
2615 "Expected container at index {}, but found {:?}",
2616 index, value
2617 )
2618 .into_boxed_str(),
2619 )),
2620 }
2621 }
2622 }
2623 }
2624
2625 pub fn len(&self) -> usize {
2626 match &self.inner {
2627 MaybeDetached::Detached(l) => l.lock().unwrap().value.len(),
2628 MaybeDetached::Attached(a) => {
2629 a.with_state(|state| state.as_list_state().unwrap().len())
2630 }
2631 }
2632 }
2633
2634 pub fn is_empty(&self) -> bool {
2635 self.len() == 0
2636 }
2637
2638 pub fn get_deep_value_with_id(&self) -> LoroResult<LoroValue> {
2639 let inner = self.inner.try_attached_state()?;
2640 Ok(inner.with_doc_state(|state| {
2641 state.get_container_deep_value_with_id(inner.container_idx, None)
2642 }))
2643 }
2644
2645 pub fn get(&self, index: usize) -> Option<LoroValue> {
2646 match &self.inner {
2647 MaybeDetached::Detached(l) => l.lock().unwrap().value.get(index).map(|x| x.to_value()),
2648 MaybeDetached::Attached(a) => a.with_state(|state| {
2649 let a = state.as_list_state().unwrap();
2650 a.get(index).cloned()
2651 }),
2652 }
2653 }
2654
2655 pub fn get_(&self, index: usize) -> Option<ValueOrHandler> {
2657 match &self.inner {
2658 MaybeDetached::Detached(l) => {
2659 let l = l.lock().unwrap();
2660 l.value.get(index).cloned()
2661 }
2662 MaybeDetached::Attached(inner) => {
2663 let value =
2664 inner.with_state(|state| state.as_list_state().unwrap().get(index).cloned());
2665 match value {
2666 Some(LoroValue::Container(container_id)) => Some(ValueOrHandler::Handler(
2667 create_handler(inner, container_id.clone()),
2668 )),
2669 Some(value) => Some(ValueOrHandler::Value(value.clone())),
2670 None => None,
2671 }
2672 }
2673 }
2674 }
2675
2676 pub fn for_each<I>(&self, mut f: I)
2677 where
2678 I: FnMut(ValueOrHandler),
2679 {
2680 match &self.inner {
2681 MaybeDetached::Detached(l) => {
2682 let l = l.lock().unwrap();
2683 for v in l.value.iter() {
2684 f(v.clone())
2685 }
2686 }
2687 MaybeDetached::Attached(inner) => {
2688 let mut temp = vec![];
2689 inner.with_state(|state| {
2690 let a = state.as_list_state().unwrap();
2691 for v in a.iter() {
2692 match v {
2693 LoroValue::Container(c) => {
2694 temp.push(ValueOrHandler::Handler(create_handler(
2695 inner,
2696 c.clone(),
2697 )));
2698 }
2699 value => {
2700 temp.push(ValueOrHandler::Value(value.clone()));
2701 }
2702 }
2703 }
2704 });
2705 for v in temp.into_iter() {
2706 f(v);
2707 }
2708 }
2709 }
2710 }
2711
2712 pub fn get_cursor(&self, pos: usize, side: Side) -> Option<Cursor> {
2713 match &self.inner {
2714 MaybeDetached::Detached(_) => None,
2715 MaybeDetached::Attached(a) => {
2716 let (id, len) = a.with_state(|s| {
2717 let l = s.as_list_state().unwrap();
2718 (l.get_id_at(pos), l.len())
2719 });
2720
2721 if len == 0 {
2722 return Some(Cursor {
2723 id: None,
2724 container: self.id(),
2725 side: if side == Side::Middle {
2726 Side::Left
2727 } else {
2728 side
2729 },
2730 origin_pos: 0,
2731 });
2732 }
2733
2734 if len <= pos {
2735 return Some(Cursor {
2736 id: None,
2737 container: self.id(),
2738 side: Side::Right,
2739 origin_pos: len,
2740 });
2741 }
2742
2743 let id = id?;
2744 Some(Cursor {
2745 id: Some(id.id()),
2746 container: self.id(),
2747 side,
2748 origin_pos: pos,
2749 })
2750 }
2751 }
2752 }
2753
2754 fn apply_delta(
2755 &self,
2756 delta: loro_delta::DeltaRope<
2757 loro_delta::array_vec::ArrayVec<ValueOrHandler, 8>,
2758 crate::event::ListDeltaMeta,
2759 >,
2760 on_container_remap: &mut dyn FnMut(ContainerID, ContainerID),
2761 ) -> LoroResult<()> {
2762 match &self.inner {
2763 MaybeDetached::Detached(_) => unimplemented!(),
2764 MaybeDetached::Attached(_) => {
2765 let mut index = 0;
2766 for item in delta.iter() {
2767 match item {
2768 loro_delta::DeltaItem::Retain { len, .. } => {
2769 index += len;
2770 }
2771 loro_delta::DeltaItem::Replace { value, delete, .. } => {
2772 if *delete > 0 {
2773 self.delete(index, *delete)?;
2774 }
2775
2776 for v in value.iter() {
2777 match v {
2778 ValueOrHandler::Value(LoroValue::Container(old_id)) => {
2779 let new_h = self.insert_container(
2780 index,
2781 Handler::new_unattached(old_id.container_type()),
2782 )?;
2783 let new_id = new_h.id();
2784 on_container_remap(old_id.clone(), new_id);
2785 }
2786 ValueOrHandler::Handler(h) => {
2787 let old_id = h.id();
2788 let new_h = self.insert_container(
2789 index,
2790 Handler::new_unattached(old_id.container_type()),
2791 )?;
2792 let new_id = new_h.id();
2793 on_container_remap(old_id, new_id);
2794 }
2795 ValueOrHandler::Value(v) => {
2796 self.insert(index, v.clone())?;
2797 }
2798 }
2799
2800 index += 1;
2801 }
2802 }
2803 }
2804 }
2805 }
2806 }
2807
2808 Ok(())
2809 }
2810
2811 pub fn is_deleted(&self) -> bool {
2812 match &self.inner {
2813 MaybeDetached::Detached(_) => false,
2814 MaybeDetached::Attached(a) => a.is_deleted(),
2815 }
2816 }
2817
2818 pub fn clear(&self) -> LoroResult<()> {
2819 match &self.inner {
2820 MaybeDetached::Detached(l) => {
2821 let mut l = l.lock().unwrap();
2822 l.value.clear();
2823 Ok(())
2824 }
2825 MaybeDetached::Attached(a) => a.with_txn(|txn| self.clear_with_txn(txn)),
2826 }
2827 }
2828
2829 pub fn clear_with_txn(&self, txn: &mut Transaction) -> LoroResult<()> {
2830 self.delete_with_txn(txn, 0, self.len())
2831 }
2832
2833 pub fn get_id_at(&self, pos: usize) -> Option<ID> {
2834 match &self.inner {
2835 MaybeDetached::Detached(_) => None,
2836 MaybeDetached::Attached(a) => a.with_state(|state| {
2837 state
2838 .as_list_state()
2839 .unwrap()
2840 .get_id_at(pos)
2841 .map(|x| x.id())
2842 }),
2843 }
2844 }
2845}
2846
2847impl MovableListHandler {
2848 pub fn insert(&self, pos: usize, v: impl Into<LoroValue>) -> LoroResult<()> {
2849 match &self.inner {
2850 MaybeDetached::Detached(d) => {
2851 let mut d = d.lock().unwrap();
2852 if pos > d.value.len() {
2853 return Err(LoroError::OutOfBound {
2854 pos,
2855 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2856 len: d.value.len(),
2857 });
2858 }
2859 d.value.insert(pos, ValueOrHandler::Value(v.into()));
2860 Ok(())
2861 }
2862 MaybeDetached::Attached(a) => {
2863 a.with_txn(|txn| self.insert_with_txn(txn, pos, v.into()))
2864 }
2865 }
2866 }
2867
2868 #[instrument(skip_all)]
2869 pub fn insert_with_txn(
2870 &self,
2871 txn: &mut Transaction,
2872 pos: usize,
2873 v: LoroValue,
2874 ) -> LoroResult<()> {
2875 if pos > self.len() {
2876 return Err(LoroError::OutOfBound {
2877 pos,
2878 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2879 len: self.len(),
2880 });
2881 }
2882
2883 if v.is_container() {
2884 return Err(LoroError::ArgErr(
2885 INSERT_CONTAINER_VALUE_ARG_ERROR
2886 .to_string()
2887 .into_boxed_str(),
2888 ));
2889 }
2890
2891 let op_index = self.with_state(|state| {
2892 let list = state.as_movable_list_state().unwrap();
2893 Ok(list
2894 .convert_index(pos, IndexType::ForUser, IndexType::ForOp)
2895 .unwrap())
2896 })?;
2897
2898 let inner = self.inner.try_attached_state()?;
2899 txn.apply_local_op(
2900 inner.container_idx,
2901 crate::op::RawOpContent::List(crate::container::list::list_op::ListOp::Insert {
2902 slice: ListSlice::RawData(Cow::Owned(vec![v.clone()])),
2903 pos: op_index,
2904 }),
2905 EventHint::InsertList { len: 1, pos },
2906 &inner.doc,
2907 )
2908 }
2909
2910 #[inline]
2911 pub fn mov(&self, from: usize, to: usize) -> LoroResult<()> {
2912 match &self.inner {
2913 MaybeDetached::Detached(d) => {
2914 let mut d = d.lock().unwrap();
2915 if from >= d.value.len() {
2916 return Err(LoroError::OutOfBound {
2917 pos: from,
2918 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2919 len: d.value.len(),
2920 });
2921 }
2922 if to >= d.value.len() {
2923 return Err(LoroError::OutOfBound {
2924 pos: to,
2925 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2926 len: d.value.len(),
2927 });
2928 }
2929 let v = d.value.remove(from);
2930 d.value.insert(to, v);
2931 Ok(())
2932 }
2933 MaybeDetached::Attached(a) => a.with_txn(|txn| self.move_with_txn(txn, from, to)),
2934 }
2935 }
2936
2937 #[instrument(skip_all)]
2939 pub fn move_with_txn(&self, txn: &mut Transaction, from: usize, to: usize) -> LoroResult<()> {
2940 if from == to {
2941 return Ok(());
2942 }
2943
2944 if from >= self.len() {
2945 return Err(LoroError::OutOfBound {
2946 pos: from,
2947 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2948 len: self.len(),
2949 });
2950 }
2951
2952 if to >= self.len() {
2953 return Err(LoroError::OutOfBound {
2954 pos: to,
2955 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2956 len: self.len(),
2957 });
2958 }
2959
2960 let (op_from, op_to, elem_id, value) = self.with_state(|state| {
2961 let list = state.as_movable_list_state().unwrap();
2962 let (elem_id, elem) = list
2963 .get_elem_at_given_pos(from, IndexType::ForUser)
2964 .unwrap();
2965 Ok((
2966 list.convert_index(from, IndexType::ForUser, IndexType::ForOp)
2967 .unwrap(),
2968 list.convert_index(to, IndexType::ForUser, IndexType::ForOp)
2969 .unwrap(),
2970 elem_id,
2971 elem.value().clone(),
2972 ))
2973 })?;
2974
2975 let inner = self.inner.try_attached_state()?;
2976 txn.apply_local_op(
2977 inner.container_idx,
2978 crate::op::RawOpContent::List(crate::container::list::list_op::ListOp::Move {
2979 from: op_from as u32,
2980 to: op_to as u32,
2981 elem_id: elem_id.to_id(),
2982 }),
2983 EventHint::Move {
2984 value,
2985 from: from as u32,
2986 to: to as u32,
2987 },
2988 &inner.doc,
2989 )
2990 }
2991
2992 pub fn push(&self, v: LoroValue) -> LoroResult<()> {
2993 match &self.inner {
2994 MaybeDetached::Detached(d) => {
2995 let mut d = d.lock().unwrap();
2996 d.value.push(v.into());
2997 Ok(())
2998 }
2999 MaybeDetached::Attached(a) => a.with_txn(|txn| self.push_with_txn(txn, v)),
3000 }
3001 }
3002
3003 pub fn push_with_txn(&self, txn: &mut Transaction, v: LoroValue) -> LoroResult<()> {
3004 let pos = self.len();
3005 self.insert_with_txn(txn, pos, v)
3006 }
3007
3008 pub fn pop_(&self) -> LoroResult<Option<ValueOrHandler>> {
3009 match &self.inner {
3010 MaybeDetached::Detached(d) => {
3011 let mut d = d.lock().unwrap();
3012 Ok(d.value.pop())
3013 }
3014 MaybeDetached::Attached(a) => {
3015 let last = self.len() - 1;
3016 let ans = self.get_(last);
3017 a.with_txn(|txn| self.pop_with_txn(txn))?;
3018 Ok(ans)
3019 }
3020 }
3021 }
3022
3023 pub fn pop(&self) -> LoroResult<Option<LoroValue>> {
3024 match &self.inner {
3025 MaybeDetached::Detached(a) => {
3026 let mut a = a.lock().unwrap();
3027 Ok(a.value.pop().map(|x| x.to_value()))
3028 }
3029 MaybeDetached::Attached(a) => a.with_txn(|txn| self.pop_with_txn(txn)),
3030 }
3031 }
3032
3033 pub fn pop_with_txn(&self, txn: &mut Transaction) -> LoroResult<Option<LoroValue>> {
3034 let len = self.len();
3035 if len == 0 {
3036 return Ok(None);
3037 }
3038
3039 let v = self.get(len - 1);
3040 self.delete_with_txn(txn, len - 1, 1)?;
3041 Ok(v)
3042 }
3043
3044 pub fn insert_container<H: HandlerTrait>(&self, pos: usize, child: H) -> LoroResult<H> {
3045 match &self.inner {
3046 MaybeDetached::Detached(d) => {
3047 let mut d = d.lock().unwrap();
3048 if pos > d.value.len() {
3049 return Err(LoroError::OutOfBound {
3050 pos,
3051 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
3052 len: d.value.len(),
3053 });
3054 }
3055 d.value
3056 .insert(pos, ValueOrHandler::Handler(child.to_handler()));
3057 Ok(child)
3058 }
3059 MaybeDetached::Attached(a) => {
3060 a.with_txn(|txn| self.insert_container_with_txn(txn, pos, child))
3061 }
3062 }
3063 }
3064
3065 pub fn push_container<H: HandlerTrait>(&self, child: H) -> LoroResult<H> {
3066 self.insert_container(self.len(), child)
3067 }
3068
3069 pub fn insert_container_with_txn<H: HandlerTrait>(
3070 &self,
3071 txn: &mut Transaction,
3072 pos: usize,
3073 child: H,
3074 ) -> LoroResult<H> {
3075 if pos > self.len() {
3076 return Err(LoroError::OutOfBound {
3077 pos,
3078 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
3079 len: self.len(),
3080 });
3081 }
3082
3083 let op_index = self.with_state(|state| {
3084 let list = state.as_movable_list_state().unwrap();
3085 Ok(list
3086 .convert_index(pos, IndexType::ForUser, IndexType::ForOp)
3087 .unwrap())
3088 })?;
3089
3090 let id = txn.next_id();
3091 let container_id = ContainerID::new_normal(id, child.kind());
3092 let v = LoroValue::Container(container_id.clone());
3093 let inner = self.inner.try_attached_state()?;
3094 txn.apply_local_op(
3095 inner.container_idx,
3096 crate::op::RawOpContent::List(crate::container::list::list_op::ListOp::Insert {
3097 slice: ListSlice::RawData(Cow::Owned(vec![v.clone()])),
3098 pos: op_index,
3099 }),
3100 EventHint::InsertList { len: 1, pos },
3101 &inner.doc,
3102 )?;
3103 child.attach(txn, inner, container_id)
3104 }
3105
3106 pub fn set(&self, index: usize, value: impl Into<LoroValue>) -> LoroResult<()> {
3107 match &self.inner {
3108 MaybeDetached::Detached(d) => {
3109 let mut d = d.lock().unwrap();
3110 if index >= d.value.len() {
3111 return Err(LoroError::OutOfBound {
3112 pos: index,
3113 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
3114 len: d.value.len(),
3115 });
3116 }
3117 d.value[index] = ValueOrHandler::Value(value.into());
3118 Ok(())
3119 }
3120 MaybeDetached::Attached(a) => {
3121 a.with_txn(|txn| self.set_with_txn(txn, index, value.into()))
3122 }
3123 }
3124 }
3125
3126 pub fn set_with_txn(
3127 &self,
3128 txn: &mut Transaction,
3129 index: usize,
3130 value: LoroValue,
3131 ) -> LoroResult<()> {
3132 if index >= self.len() {
3133 return Err(LoroError::OutOfBound {
3134 pos: index,
3135 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
3136 len: self.len(),
3137 });
3138 }
3139
3140 let inner = self.inner.try_attached_state()?;
3141 let Some(elem_id) = self.with_state(|state| {
3142 let list = state.as_movable_list_state().unwrap();
3143 Ok(list.get_elem_id_at(index, IndexType::ForUser))
3144 })?
3145 else {
3146 unreachable!()
3147 };
3148
3149 let op = crate::op::RawOpContent::List(crate::container::list::list_op::ListOp::Set {
3150 elem_id: elem_id.to_id(),
3151 value: value.clone(),
3152 });
3153
3154 let hint = EventHint::SetList { index, value };
3155 txn.apply_local_op(inner.container_idx, op, hint, &inner.doc)
3156 }
3157
3158 pub fn set_container<H: HandlerTrait>(&self, pos: usize, child: H) -> LoroResult<H> {
3159 match &self.inner {
3160 MaybeDetached::Detached(d) => {
3161 let mut d = d.lock().unwrap();
3162 d.value[pos] = ValueOrHandler::Handler(child.to_handler());
3163 Ok(child)
3164 }
3165 MaybeDetached::Attached(a) => {
3166 a.with_txn(|txn| self.set_container_with_txn(txn, pos, child))
3167 }
3168 }
3169 }
3170
3171 pub fn set_container_with_txn<H: HandlerTrait>(
3172 &self,
3173 txn: &mut Transaction,
3174 pos: usize,
3175 child: H,
3176 ) -> LoroResult<H> {
3177 let id = txn.next_id();
3178 let container_id = ContainerID::new_normal(id, child.kind());
3179 let v = LoroValue::Container(container_id.clone());
3180 let Some(elem_id) = self.with_state(|state| {
3181 let list = state.as_movable_list_state().unwrap();
3182 Ok(list.get_elem_id_at(pos, IndexType::ForUser))
3183 })?
3184 else {
3185 let len = self.len();
3186 if pos >= len {
3187 return Err(LoroError::OutOfBound {
3188 pos,
3189 len,
3190 info: "".into(),
3191 });
3192 } else {
3193 unreachable!()
3194 }
3195 };
3196 let inner = self.inner.try_attached_state()?;
3197 txn.apply_local_op(
3198 inner.container_idx,
3199 crate::op::RawOpContent::List(crate::container::list::list_op::ListOp::Set {
3200 elem_id: elem_id.to_id(),
3201 value: v.clone(),
3202 }),
3203 EventHint::SetList {
3204 index: pos,
3205 value: v,
3206 },
3207 &inner.doc,
3208 )?;
3209
3210 child.attach(txn, inner, container_id)
3211 }
3212
3213 pub fn delete(&self, pos: usize, len: usize) -> LoroResult<()> {
3214 match &self.inner {
3215 MaybeDetached::Detached(d) => {
3216 let mut d = d.lock().unwrap();
3217 d.value.drain(pos..pos + len);
3218 Ok(())
3219 }
3220 MaybeDetached::Attached(a) => a.with_txn(|txn| self.delete_with_txn(txn, pos, len)),
3221 }
3222 }
3223
3224 #[instrument(skip_all)]
3225 pub fn delete_with_txn(&self, txn: &mut Transaction, pos: usize, len: usize) -> LoroResult<()> {
3226 if len == 0 {
3227 return Ok(());
3228 }
3229
3230 if pos + len > self.len() {
3231 return Err(LoroError::OutOfBound {
3232 pos: pos + len,
3233 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
3234 len: self.len(),
3235 });
3236 }
3237
3238 let (ids, new_poses) = self.with_state(|state| {
3239 let list = state.as_movable_list_state().unwrap();
3240 let ids: Vec<_> = (pos..pos + len)
3241 .map(|i| list.get_list_id_at(i, IndexType::ForUser).unwrap())
3242 .collect();
3243 let poses: Vec<_> = (pos..pos + len)
3244 .map(|user_index| {
3246 let op_index = list
3247 .convert_index(user_index, IndexType::ForUser, IndexType::ForOp)
3248 .unwrap();
3249 assert!(op_index >= user_index);
3250 op_index - (user_index - pos)
3251 })
3252 .collect();
3253 Ok((ids, poses))
3254 })?;
3255
3256 loro_common::info!(?pos, ?len, ?ids, ?new_poses, "delete_with_txn");
3257 let user_pos = pos;
3258 let inner = self.inner.try_attached_state()?;
3259 for (id, op_pos) in ids.into_iter().zip(new_poses.into_iter()) {
3260 txn.apply_local_op(
3261 inner.container_idx,
3262 crate::op::RawOpContent::List(ListOp::Delete(DeleteSpanWithId::new(
3263 id,
3264 op_pos as isize,
3265 1,
3266 ))),
3267 EventHint::DeleteList(DeleteSpan::new(user_pos as isize, 1)),
3268 &inner.doc,
3269 )?;
3270 }
3271
3272 Ok(())
3273 }
3274
3275 pub fn get_child_handler(&self, index: usize) -> LoroResult<Handler> {
3276 match &self.inner {
3277 MaybeDetached::Detached(l) => {
3278 let list = l.lock().unwrap();
3279 let value = list.value.get(index).ok_or(LoroError::OutOfBound {
3280 pos: index,
3281 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
3282 len: list.value.len(),
3283 })?;
3284 match value {
3285 ValueOrHandler::Handler(h) => Ok(h.clone()),
3286 _ => Err(LoroError::ArgErr(
3287 format!(
3288 "Expected container at index {}, but found {:?}",
3289 index, value
3290 )
3291 .into_boxed_str(),
3292 )),
3293 }
3294 }
3295 MaybeDetached::Attached(a) => {
3296 let Some(value) = a.with_state(|state| {
3297 state
3298 .as_movable_list_state()
3299 .as_ref()
3300 .unwrap()
3301 .get(index, IndexType::ForUser)
3302 .cloned()
3303 }) else {
3304 return Err(LoroError::OutOfBound {
3305 pos: index,
3306 info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
3307 len: a.with_state(|state| state.as_list_state().unwrap().len()),
3308 });
3309 };
3310 match value {
3311 LoroValue::Container(id) => Ok(create_handler(a, id)),
3312 _ => Err(LoroError::ArgErr(
3313 format!(
3314 "Expected container at index {}, but found {:?}",
3315 index, value
3316 )
3317 .into_boxed_str(),
3318 )),
3319 }
3320 }
3321 }
3322 }
3323
3324 pub fn len(&self) -> usize {
3325 match &self.inner {
3326 MaybeDetached::Detached(d) => {
3327 let d = d.lock().unwrap();
3328 d.value.len()
3329 }
3330 MaybeDetached::Attached(a) => {
3331 a.with_state(|state| state.as_movable_list_state().unwrap().len())
3332 }
3333 }
3334 }
3335
3336 pub fn is_empty(&self) -> bool {
3337 self.len() == 0
3338 }
3339
3340 pub fn get_deep_value_with_id(&self) -> LoroValue {
3341 let inner = self.inner.try_attached_state().unwrap();
3342 inner
3343 .doc
3344 .state
3345 .lock()
3346 .unwrap()
3347 .get_container_deep_value_with_id(inner.container_idx, None)
3348 }
3349
3350 pub fn get(&self, index: usize) -> Option<LoroValue> {
3351 match &self.inner {
3352 MaybeDetached::Detached(d) => {
3353 let d = d.lock().unwrap();
3354 d.value.get(index).map(|v| v.to_value())
3355 }
3356 MaybeDetached::Attached(a) => a.with_state(|state| {
3357 let a = state.as_movable_list_state().unwrap();
3358 a.get(index, IndexType::ForUser).cloned()
3359 }),
3360 }
3361 }
3362
3363 pub fn get_(&self, index: usize) -> Option<ValueOrHandler> {
3365 match &self.inner {
3366 MaybeDetached::Detached(d) => {
3367 let d = d.lock().unwrap();
3368 d.value.get(index).cloned()
3369 }
3370 MaybeDetached::Attached(m) => m.with_state(|state| {
3371 let a = state.as_movable_list_state().unwrap();
3372 match a.get(index, IndexType::ForUser) {
3373 Some(v) => {
3374 if let LoroValue::Container(c) = v {
3375 Some(ValueOrHandler::Handler(create_handler(m, c.clone())))
3376 } else {
3377 Some(ValueOrHandler::Value(v.clone()))
3378 }
3379 }
3380 None => None,
3381 }
3382 }),
3383 }
3384 }
3385
3386 pub fn for_each<I>(&self, mut f: I)
3387 where
3388 I: FnMut(ValueOrHandler),
3389 {
3390 match &self.inner {
3391 MaybeDetached::Detached(d) => {
3392 let d = d.lock().unwrap();
3393 for v in d.value.iter() {
3394 f(v.clone());
3395 }
3396 }
3397 MaybeDetached::Attached(m) => {
3398 let mut temp = vec![];
3399 m.with_state(|state| {
3400 let a = state.as_movable_list_state().unwrap();
3401 for v in a.iter() {
3402 match v {
3403 LoroValue::Container(c) => {
3404 temp.push(ValueOrHandler::Handler(create_handler(m, c.clone())));
3405 }
3406 value => {
3407 temp.push(ValueOrHandler::Value(value.clone()));
3408 }
3409 }
3410 }
3411 });
3412
3413 for v in temp.into_iter() {
3414 f(v);
3415 }
3416 }
3417 }
3418 }
3419
3420 pub fn log_internal_state(&self) -> String {
3421 match &self.inner {
3422 MaybeDetached::Detached(d) => {
3423 let d = d.lock().unwrap();
3424 format!("{:#?}", &d.value)
3425 }
3426 MaybeDetached::Attached(a) => a.with_state(|state| {
3427 let a = state.as_movable_list_state().unwrap();
3428 format!("{a:#?}")
3429 }),
3430 }
3431 }
3432
3433 pub fn new_detached() -> MovableListHandler {
3434 MovableListHandler {
3435 inner: MaybeDetached::new_detached(Default::default()),
3436 }
3437 }
3438
3439 pub fn get_cursor(&self, pos: usize, side: Side) -> Option<Cursor> {
3440 match &self.inner {
3441 MaybeDetached::Detached(_) => None,
3442 MaybeDetached::Attached(inner) => {
3443 let (id, len) = inner.with_state(|s| {
3444 let l = s.as_movable_list_state().unwrap();
3445 (l.get_list_item_id_at(pos), l.len())
3446 });
3447
3448 if len == 0 {
3449 return Some(Cursor {
3450 id: None,
3451 container: self.id(),
3452 side: if side == Side::Middle {
3453 Side::Left
3454 } else {
3455 side
3456 },
3457 origin_pos: 0,
3458 });
3459 }
3460
3461 if len <= pos {
3462 return Some(Cursor {
3463 id: None,
3464 container: self.id(),
3465 side: Side::Right,
3466 origin_pos: len,
3467 });
3468 }
3469
3470 let id = id?;
3471 Some(Cursor {
3472 id: Some(id.id()),
3473 container: self.id(),
3474 side,
3475 origin_pos: pos,
3476 })
3477 }
3478 }
3479 }
3480
3481 pub(crate) fn op_pos_to_user_pos(&self, new_pos: usize) -> usize {
3482 match &self.inner {
3483 MaybeDetached::Detached(_) => new_pos,
3484 MaybeDetached::Attached(inner) => {
3485 let mut pos = new_pos;
3486 inner.with_state(|s| {
3487 let l = s.as_movable_list_state().unwrap();
3488 pos = l
3489 .convert_index(new_pos, IndexType::ForOp, IndexType::ForUser)
3490 .unwrap_or(l.len());
3491 });
3492 pos
3493 }
3494 }
3495 }
3496
3497 pub fn is_deleted(&self) -> bool {
3498 match &self.inner {
3499 MaybeDetached::Detached(_) => false,
3500 MaybeDetached::Attached(a) => a.is_deleted(),
3501 }
3502 }
3503
3504 pub fn clear(&self) -> LoroResult<()> {
3505 match &self.inner {
3506 MaybeDetached::Detached(d) => {
3507 let mut d = d.lock().unwrap();
3508 d.value.clear();
3509 Ok(())
3510 }
3511 MaybeDetached::Attached(a) => a.with_txn(|txn| self.clear_with_txn(txn)),
3512 }
3513 }
3514
3515 pub fn clear_with_txn(&self, txn: &mut Transaction) -> LoroResult<()> {
3516 self.delete_with_txn(txn, 0, self.len())
3517 }
3518
3519 pub fn get_creator_at(&self, pos: usize) -> Option<PeerID> {
3520 match &self.inner {
3521 MaybeDetached::Detached(_) => None,
3522 MaybeDetached::Attached(a) => {
3523 a.with_state(|state| state.as_movable_list_state().unwrap().get_creator_at(pos))
3524 }
3525 }
3526 }
3527
3528 pub fn get_last_mover_at(&self, pos: usize) -> Option<PeerID> {
3529 match &self.inner {
3530 MaybeDetached::Detached(_) => None,
3531 MaybeDetached::Attached(a) => a.with_state(|state| {
3532 state
3533 .as_movable_list_state()
3534 .unwrap()
3535 .get_last_mover_at(pos)
3536 }),
3537 }
3538 }
3539
3540 pub fn get_last_editor_at(&self, pos: usize) -> Option<PeerID> {
3541 match &self.inner {
3542 MaybeDetached::Detached(_) => None,
3543 MaybeDetached::Attached(a) => a.with_state(|state| {
3544 state
3545 .as_movable_list_state()
3546 .unwrap()
3547 .get_last_editor_at(pos)
3548 }),
3549 }
3550 }
3551}
3552
3553impl MapHandler {
3554 pub fn new_detached() -> Self {
3558 Self {
3559 inner: MaybeDetached::new_detached(Default::default()),
3560 }
3561 }
3562
3563 pub fn insert(&self, key: &str, value: impl Into<LoroValue>) -> LoroResult<()> {
3564 match &self.inner {
3565 MaybeDetached::Detached(m) => {
3566 let mut m = m.lock().unwrap();
3567 m.value
3568 .insert(key.into(), ValueOrHandler::Value(value.into()));
3569 Ok(())
3570 }
3571 MaybeDetached::Attached(a) => {
3572 a.with_txn(|txn| self.insert_with_txn(txn, key, value.into()))
3573 }
3574 }
3575 }
3576
3577 fn insert_without_skipping(&self, key: &str, value: impl Into<LoroValue>) -> LoroResult<()> {
3579 match &self.inner {
3580 MaybeDetached::Detached(m) => {
3581 let mut m = m.lock().unwrap();
3582 m.value
3583 .insert(key.into(), ValueOrHandler::Value(value.into()));
3584 Ok(())
3585 }
3586 MaybeDetached::Attached(a) => a.with_txn(|txn| {
3587 let this = &self;
3588 let value = value.into();
3589 if let Some(_value) = value.as_container() {
3590 return Err(LoroError::ArgErr(
3591 INSERT_CONTAINER_VALUE_ARG_ERROR
3592 .to_string()
3593 .into_boxed_str(),
3594 ));
3595 }
3596
3597 let inner = this.inner.try_attached_state()?;
3598 txn.apply_local_op(
3599 inner.container_idx,
3600 crate::op::RawOpContent::Map(crate::container::map::MapSet {
3601 key: key.into(),
3602 value: Some(value.clone()),
3603 }),
3604 EventHint::Map {
3605 key: key.into(),
3606 value: Some(value.clone()),
3607 },
3608 &inner.doc,
3609 )
3610 }),
3611 }
3612 }
3613
3614 pub fn insert_with_txn(
3615 &self,
3616 txn: &mut Transaction,
3617 key: &str,
3618 value: LoroValue,
3619 ) -> LoroResult<()> {
3620 if let Some(_value) = value.as_container() {
3621 return Err(LoroError::ArgErr(
3622 INSERT_CONTAINER_VALUE_ARG_ERROR
3623 .to_string()
3624 .into_boxed_str(),
3625 ));
3626 }
3627
3628 if self.get(key).map(|x| x == value).unwrap_or(false) {
3629 return Ok(());
3631 }
3632
3633 let inner = self.inner.try_attached_state()?;
3634 txn.apply_local_op(
3635 inner.container_idx,
3636 crate::op::RawOpContent::Map(crate::container::map::MapSet {
3637 key: key.into(),
3638 value: Some(value.clone()),
3639 }),
3640 EventHint::Map {
3641 key: key.into(),
3642 value: Some(value.clone()),
3643 },
3644 &inner.doc,
3645 )
3646 }
3647
3648 pub fn insert_container<T: HandlerTrait>(&self, key: &str, handler: T) -> LoroResult<T> {
3649 match &self.inner {
3650 MaybeDetached::Detached(m) => {
3651 let mut m = m.lock().unwrap();
3652 let to_insert = handler.to_handler();
3653 m.value
3654 .insert(key.into(), ValueOrHandler::Handler(to_insert.clone()));
3655 Ok(handler)
3656 }
3657 MaybeDetached::Attached(a) => {
3658 a.with_txn(|txn| self.insert_container_with_txn(txn, key, handler))
3659 }
3660 }
3661 }
3662
3663 pub fn insert_container_with_txn<H: HandlerTrait>(
3664 &self,
3665 txn: &mut Transaction,
3666 key: &str,
3667 child: H,
3668 ) -> LoroResult<H> {
3669 let inner = self.inner.try_attached_state()?;
3670 let id = txn.next_id();
3671 let container_id = ContainerID::new_normal(id, child.kind());
3672 txn.apply_local_op(
3673 inner.container_idx,
3674 crate::op::RawOpContent::Map(crate::container::map::MapSet {
3675 key: key.into(),
3676 value: Some(LoroValue::Container(container_id.clone())),
3677 }),
3678 EventHint::Map {
3679 key: key.into(),
3680 value: Some(LoroValue::Container(container_id.clone())),
3681 },
3682 &inner.doc,
3683 )?;
3684
3685 child.attach(txn, inner, container_id)
3686 }
3687
3688 pub fn delete(&self, key: &str) -> LoroResult<()> {
3689 match &self.inner {
3690 MaybeDetached::Detached(m) => {
3691 let mut m = m.lock().unwrap();
3692 m.value.remove(key);
3693 Ok(())
3694 }
3695 MaybeDetached::Attached(a) => a.with_txn(|txn| self.delete_with_txn(txn, key)),
3696 }
3697 }
3698
3699 pub fn delete_with_txn(&self, txn: &mut Transaction, key: &str) -> LoroResult<()> {
3700 let inner = self.inner.try_attached_state()?;
3701 txn.apply_local_op(
3702 inner.container_idx,
3703 crate::op::RawOpContent::Map(crate::container::map::MapSet {
3704 key: key.into(),
3705 value: None,
3706 }),
3707 EventHint::Map {
3708 key: key.into(),
3709 value: None,
3710 },
3711 &inner.doc,
3712 )
3713 }
3714
3715 pub fn for_each<I>(&self, mut f: I)
3716 where
3717 I: FnMut(&str, ValueOrHandler),
3718 {
3719 match &self.inner {
3720 MaybeDetached::Detached(m) => {
3721 let m = m.lock().unwrap();
3722 for (k, v) in m.value.iter() {
3723 f(k, v.clone());
3724 }
3725 }
3726 MaybeDetached::Attached(inner) => {
3727 let mut temp = vec![];
3728 inner.with_state(|state| {
3729 let a = state.as_map_state().unwrap();
3730 for (k, v) in a.iter() {
3731 if let Some(v) = &v.value {
3732 match v {
3733 LoroValue::Container(c) => {
3734 temp.push((
3735 k.to_string(),
3736 ValueOrHandler::Handler(create_handler(inner, c.clone())),
3737 ));
3738 }
3739 value => {
3740 temp.push((k.to_string(), ValueOrHandler::Value(value.clone())))
3741 }
3742 }
3743 }
3744 }
3745 });
3746
3747 for (k, v) in temp.into_iter() {
3748 f(&k, v.clone());
3749 }
3750 }
3751 }
3752 }
3753
3754 pub fn get_child_handler(&self, key: &str) -> LoroResult<Handler> {
3755 match &self.inner {
3756 MaybeDetached::Detached(m) => {
3757 let m = m.lock().unwrap();
3758 let value = m.value.get(key).unwrap();
3759 match value {
3760 ValueOrHandler::Value(v) => Err(LoroError::ArgErr(
3761 format!("Expected Handler but found {:?}", v).into_boxed_str(),
3762 )),
3763 ValueOrHandler::Handler(h) => Ok(h.clone()),
3764 }
3765 }
3766 MaybeDetached::Attached(inner) => {
3767 let container_id = inner.with_state(|state| {
3768 state
3769 .as_map_state()
3770 .as_ref()
3771 .unwrap()
3772 .get(key)
3773 .unwrap()
3774 .as_container()
3775 .unwrap()
3776 .clone()
3777 });
3778 Ok(create_handler(inner, container_id))
3779 }
3780 }
3781 }
3782
3783 pub fn get_deep_value_with_id(&self) -> LoroResult<LoroValue> {
3784 match &self.inner {
3785 MaybeDetached::Detached(_) => Err(LoroError::MisuseDetachedContainer {
3786 method: "get_deep_value_with_id",
3787 }),
3788 MaybeDetached::Attached(inner) => Ok(inner.with_doc_state(|state| {
3789 state.get_container_deep_value_with_id(inner.container_idx, None)
3790 })),
3791 }
3792 }
3793
3794 pub fn get(&self, key: &str) -> Option<LoroValue> {
3795 match &self.inner {
3796 MaybeDetached::Detached(m) => {
3797 let m = m.lock().unwrap();
3798 m.value.get(key).map(|v| v.to_value())
3799 }
3800 MaybeDetached::Attached(inner) => {
3801 inner.with_state(|state| state.as_map_state().unwrap().get(key).cloned())
3802 }
3803 }
3804 }
3805
3806 pub fn get_(&self, key: &str) -> Option<ValueOrHandler> {
3808 match &self.inner {
3809 MaybeDetached::Detached(m) => {
3810 let m = m.lock().unwrap();
3811 m.value.get(key).cloned()
3812 }
3813 MaybeDetached::Attached(inner) => {
3814 let value =
3815 inner.with_state(|state| state.as_map_state().unwrap().get(key).cloned());
3816 match value {
3817 Some(LoroValue::Container(container_id)) => Some(ValueOrHandler::Handler(
3818 create_handler(inner, container_id.clone()),
3819 )),
3820 Some(value) => Some(ValueOrHandler::Value(value.clone())),
3821 None => None,
3822 }
3823 }
3824 }
3825 }
3826
3827 pub fn get_or_create_container<C: HandlerTrait>(&self, key: &str, child: C) -> LoroResult<C> {
3828 if let Some(ans) = self.get_(key) {
3829 if let ValueOrHandler::Handler(h) = ans {
3830 let kind = h.kind();
3831 return C::from_handler(h).ok_or_else(move || {
3832 LoroError::ArgErr(
3833 format!("Expected value type {} but found {:?}", child.kind(), kind)
3834 .into_boxed_str(),
3835 )
3836 });
3837 } else if let ValueOrHandler::Value(LoroValue::Null) = ans {
3838 } else {
3840 return Err(LoroError::ArgErr(
3841 format!("Expected value type {} but found {:?}", child.kind(), ans)
3842 .into_boxed_str(),
3843 ));
3844 }
3845 }
3846
3847 self.insert_container(key, child)
3848 }
3849
3850 pub fn contains_key(&self, key: &str) -> bool {
3851 self.get(key).is_some()
3852 }
3853
3854 pub fn len(&self) -> usize {
3855 match &self.inner {
3856 MaybeDetached::Detached(m) => m.lock().unwrap().value.len(),
3857 MaybeDetached::Attached(a) => a.with_state(|state| state.as_map_state().unwrap().len()),
3858 }
3859 }
3860
3861 pub fn is_empty(&self) -> bool {
3862 self.len() == 0
3863 }
3864
3865 pub fn is_deleted(&self) -> bool {
3866 match &self.inner {
3867 MaybeDetached::Detached(_) => false,
3868 MaybeDetached::Attached(a) => a.is_deleted(),
3869 }
3870 }
3871
3872 pub fn clear(&self) -> LoroResult<()> {
3873 match &self.inner {
3874 MaybeDetached::Detached(m) => {
3875 let mut m = m.lock().unwrap();
3876 m.value.clear();
3877 Ok(())
3878 }
3879 MaybeDetached::Attached(a) => a.with_txn(|txn| self.clear_with_txn(txn)),
3880 }
3881 }
3882
3883 pub fn clear_with_txn(&self, txn: &mut Transaction) -> LoroResult<()> {
3884 let keys: Vec<InternalString> = self.inner.try_attached_state()?.with_state(|state| {
3885 state
3886 .as_map_state()
3887 .unwrap()
3888 .iter()
3889 .map(|(k, _)| k.clone())
3890 .collect()
3891 });
3892
3893 for key in keys {
3894 self.delete_with_txn(txn, &key)?;
3895 }
3896
3897 Ok(())
3898 }
3899
3900 pub fn keys(&self) -> impl Iterator<Item = InternalString> + '_ {
3901 let mut keys: Vec<InternalString> = Vec::with_capacity(self.len());
3902 match &self.inner {
3903 MaybeDetached::Detached(m) => {
3904 let m = m.lock().unwrap();
3905 keys = m.value.keys().map(|x| x.as_str().into()).collect();
3906 }
3907 MaybeDetached::Attached(a) => {
3908 a.with_state(|state| {
3909 for (k, v) in state.as_map_state().unwrap().iter() {
3910 if v.value.is_some() {
3911 keys.push(k.clone());
3912 }
3913 }
3914 });
3915 }
3916 }
3917
3918 keys.into_iter()
3919 }
3920
3921 pub fn values(&self) -> impl Iterator<Item = ValueOrHandler> + '_ {
3922 let mut values: Vec<ValueOrHandler> = Vec::with_capacity(self.len());
3923 match &self.inner {
3924 MaybeDetached::Detached(m) => {
3925 let m = m.lock().unwrap();
3926 values = m.value.values().cloned().collect();
3927 }
3928 MaybeDetached::Attached(a) => {
3929 a.with_state(|state| {
3930 for (_, v) in state.as_map_state().unwrap().iter() {
3931 let value = match &v.value {
3932 Some(LoroValue::Container(container_id)) => {
3933 ValueOrHandler::Handler(create_handler(a, container_id.clone()))
3934 }
3935 Some(value) => ValueOrHandler::Value(value.clone()),
3936 None => continue,
3937 };
3938 values.push(value);
3939 }
3940 });
3941 }
3942 }
3943
3944 values.into_iter()
3945 }
3946
3947 pub fn get_last_editor(&self, key: &str) -> Option<PeerID> {
3948 match &self.inner {
3949 MaybeDetached::Detached(_) => None,
3950 MaybeDetached::Attached(a) => a.with_state(|state| {
3951 let m = state.as_map_state().unwrap();
3952 m.get_last_edit_peer(key)
3953 }),
3954 }
3955 }
3956}
3957
3958fn with_txn<R>(doc: &LoroDoc, f: impl FnOnce(&mut Transaction) -> LoroResult<R>) -> LoroResult<R> {
3959 let txn = &doc.txn;
3960 let mut txn = txn.lock().unwrap();
3961 loop {
3962 if let Some(txn) = &mut *txn {
3963 return f(txn);
3964 } else if cfg!(target_arch = "wasm32") || !doc.can_edit() {
3965 return Err(LoroError::AutoCommitNotStarted);
3966 } else {
3967 drop(txn);
3968 #[cfg(loom)]
3969 loom::thread::yield_now();
3970 doc.start_auto_commit();
3971 txn = doc.txn.lock().unwrap();
3972 }
3973 }
3974}
3975
3976#[cfg(feature = "counter")]
3977pub mod counter {
3978
3979 use loro_common::LoroResult;
3980
3981 use crate::{
3982 txn::{EventHint, Transaction},
3983 HandlerTrait,
3984 };
3985
3986 use super::{create_handler, Handler, MaybeDetached};
3987
3988 #[derive(Clone)]
3989 pub struct CounterHandler {
3990 pub(super) inner: MaybeDetached<f64>,
3991 }
3992
3993 impl CounterHandler {
3994 pub fn new_detached() -> Self {
3995 Self {
3996 inner: MaybeDetached::new_detached(0.),
3997 }
3998 }
3999
4000 pub fn increment(&self, n: f64) -> LoroResult<()> {
4001 match &self.inner {
4002 MaybeDetached::Detached(d) => {
4003 let d = &mut d.lock().unwrap().value;
4004 *d += n;
4005 Ok(())
4006 }
4007 MaybeDetached::Attached(a) => a.with_txn(|txn| self.increment_with_txn(txn, n)),
4008 }
4009 }
4010
4011 pub fn decrement(&self, n: f64) -> LoroResult<()> {
4012 match &self.inner {
4013 MaybeDetached::Detached(d) => {
4014 let d = &mut d.lock().unwrap().value;
4015 *d -= n;
4016 Ok(())
4017 }
4018 MaybeDetached::Attached(a) => a.with_txn(|txn| self.increment_with_txn(txn, -n)),
4019 }
4020 }
4021
4022 fn increment_with_txn(&self, txn: &mut Transaction, n: f64) -> LoroResult<()> {
4023 let inner = self.inner.try_attached_state()?;
4024 txn.apply_local_op(
4025 inner.container_idx,
4026 crate::op::RawOpContent::Counter(n),
4027 EventHint::Counter(n),
4028 &inner.doc,
4029 )
4030 }
4031
4032 pub fn is_deleted(&self) -> bool {
4033 match &self.inner {
4034 MaybeDetached::Detached(_) => false,
4035 MaybeDetached::Attached(a) => a.is_deleted(),
4036 }
4037 }
4038
4039 pub fn clear(&self) -> LoroResult<()> {
4040 self.decrement(self.get_value().into_double().unwrap())
4041 }
4042 }
4043
4044 impl std::fmt::Debug for CounterHandler {
4045 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4046 match &self.inner {
4047 MaybeDetached::Detached(_) => write!(f, "CounterHandler Detached"),
4048 MaybeDetached::Attached(a) => write!(f, "CounterHandler {}", a.id),
4049 }
4050 }
4051 }
4052
4053 impl HandlerTrait for CounterHandler {
4054 fn is_attached(&self) -> bool {
4055 matches!(&self.inner, MaybeDetached::Attached(..))
4056 }
4057
4058 fn attached_handler(&self) -> Option<&crate::BasicHandler> {
4059 self.inner.attached_handler()
4060 }
4061
4062 fn get_value(&self) -> loro_common::LoroValue {
4063 match &self.inner {
4064 MaybeDetached::Detached(t) => {
4065 let t = t.lock().unwrap();
4066 t.value.into()
4067 }
4068 MaybeDetached::Attached(a) => a.get_value(),
4069 }
4070 }
4071
4072 fn get_deep_value(&self) -> loro_common::LoroValue {
4073 self.get_value()
4074 }
4075
4076 fn kind(&self) -> loro_common::ContainerType {
4077 loro_common::ContainerType::Counter
4078 }
4079
4080 fn to_handler(&self) -> super::Handler {
4081 Handler::Counter(self.clone())
4082 }
4083
4084 fn from_handler(h: super::Handler) -> Option<Self> {
4085 match h {
4086 Handler::Counter(x) => Some(x),
4087 _ => None,
4088 }
4089 }
4090
4091 fn attach(
4092 &self,
4093 txn: &mut crate::txn::Transaction,
4094 parent: &crate::BasicHandler,
4095 self_id: loro_common::ContainerID,
4096 ) -> loro_common::LoroResult<Self> {
4097 match &self.inner {
4098 MaybeDetached::Detached(v) => {
4099 let mut v = v.lock().unwrap();
4100 let inner = create_handler(parent, self_id);
4101 let c = inner.into_counter().unwrap();
4102
4103 c.increment_with_txn(txn, v.value)?;
4104
4105 v.attached = c.attached_handler().cloned();
4106 Ok(c)
4107 }
4108 MaybeDetached::Attached(a) => {
4109 let new_inner = create_handler(a, self_id);
4110 let ans = new_inner.into_counter().unwrap();
4111 let delta = *self.get_value().as_double().unwrap();
4112 ans.increment_with_txn(txn, delta)?;
4113 Ok(ans)
4114 }
4115 }
4116 }
4117
4118 fn get_attached(&self) -> Option<Self> {
4119 match &self.inner {
4120 MaybeDetached::Attached(a) => Some(Self {
4121 inner: MaybeDetached::Attached(a.clone()),
4122 }),
4123 MaybeDetached::Detached(_) => None,
4124 }
4125 }
4126
4127 fn doc(&self) -> Option<crate::LoroDoc> {
4128 match &self.inner {
4129 MaybeDetached::Detached(_) => None,
4130 MaybeDetached::Attached(a) => Some(a.doc()),
4131 }
4132 }
4133 }
4134}
4135
4136#[cfg(test)]
4137mod test {
4138
4139 use super::{HandlerTrait, TextDelta};
4140 use crate::state::TreeParentId;
4141 use crate::version::Frontiers;
4142 use crate::LoroDoc;
4143 use crate::{fx_map, ToJson};
4144 use loro_common::ID;
4145 use serde_json::json;
4146
4147 #[test]
4148 fn import() {
4149 let loro = LoroDoc::new();
4150 loro.set_peer_id(1).unwrap();
4151 let loro2 = LoroDoc::new();
4152 loro2.set_peer_id(2).unwrap();
4153
4154 let mut txn = loro.txn().unwrap();
4155 let text = txn.get_text("hello");
4156 text.insert_with_txn(&mut txn, 0, "hello").unwrap();
4157 txn.commit().unwrap();
4158 let exported = loro.export_from(&Default::default());
4159 loro2.import(&exported).unwrap();
4160 let mut txn = loro2.txn().unwrap();
4161 let text = txn.get_text("hello");
4162 assert_eq!(&**text.get_value().as_string().unwrap(), "hello");
4163 text.insert_with_txn(&mut txn, 5, " world").unwrap();
4164 assert_eq!(&**text.get_value().as_string().unwrap(), "hello world");
4165 txn.commit().unwrap();
4166 loro.import(&loro2.export_from(&Default::default()))
4167 .unwrap();
4168 let txn = loro.txn().unwrap();
4169 let text = txn.get_text("hello");
4170 assert_eq!(&**text.get_value().as_string().unwrap(), "hello world");
4171 }
4172
4173 #[test]
4174 fn richtext_handler() {
4175 let loro = LoroDoc::new();
4176 loro.set_peer_id(1).unwrap();
4177 let loro2 = LoroDoc::new();
4178 loro2.set_peer_id(2).unwrap();
4179
4180 let mut txn = loro.txn().unwrap();
4181 let text = txn.get_text("hello");
4182 text.insert_with_txn(&mut txn, 0, "hello").unwrap();
4183 txn.commit().unwrap();
4184 let exported = loro.export_from(&Default::default());
4185
4186 loro2.import(&exported).unwrap();
4187 let mut txn = loro2.txn().unwrap();
4188 let text = txn.get_text("hello");
4189 assert_eq!(&**text.get_value().as_string().unwrap(), "hello");
4190 text.insert_with_txn(&mut txn, 5, " world").unwrap();
4191 assert_eq!(&**text.get_value().as_string().unwrap(), "hello world");
4192 txn.commit().unwrap();
4193
4194 loro.import(&loro2.export_from(&Default::default()))
4195 .unwrap();
4196 let txn = loro.txn().unwrap();
4197 let text = txn.get_text("hello");
4198 assert_eq!(&**text.get_value().as_string().unwrap(), "hello world");
4199 txn.commit().unwrap();
4200
4201 loro.checkout(&Frontiers::from_id(ID::new(2, 1))).unwrap();
4203 assert_eq!(&**text.get_value().as_string().unwrap(), "hello w");
4204 }
4205
4206 #[test]
4207 fn richtext_handler_concurrent() {
4208 let loro = LoroDoc::new();
4209 let mut txn = loro.txn().unwrap();
4210 let handler = loro.get_text("richtext");
4211 handler.insert_with_txn(&mut txn, 0, "hello").unwrap();
4212 txn.commit().unwrap();
4213 for i in 0..100 {
4214 let new_loro = LoroDoc::new();
4215 new_loro
4216 .import(&loro.export_from(&Default::default()))
4217 .unwrap();
4218 let mut txn = new_loro.txn().unwrap();
4219 let handler = new_loro.get_text("richtext");
4220 handler
4221 .insert_with_txn(&mut txn, i % 5, &i.to_string())
4222 .unwrap();
4223 txn.commit().unwrap();
4224 loro.import(&new_loro.export_from(&loro.oplog_vv()))
4225 .unwrap();
4226 }
4227 }
4228
4229 #[test]
4230 fn richtext_handler_mark() {
4231 let loro = LoroDoc::new_auto_commit();
4232 let handler = loro.get_text("richtext");
4233 handler.insert(0, "hello world").unwrap();
4234 handler.mark(0, 5, "bold", true.into()).unwrap();
4235 loro.commit_then_renew();
4236
4237 let value = handler.get_richtext_value();
4239 assert_eq!(value[0]["insert"], "hello".into());
4240 let meta = value[0]["attributes"].as_map().unwrap();
4241 assert_eq!(meta.len(), 1);
4242 meta.get("bold").unwrap();
4243
4244 let loro2 = LoroDoc::new_auto_commit();
4245 loro2
4246 .import(&loro.export_from(&Default::default()))
4247 .unwrap();
4248 let handler2 = loro2.get_text("richtext");
4249 assert_eq!(&**handler2.get_value().as_string().unwrap(), "hello world");
4250
4251 let value = handler2.get_richtext_value();
4253 assert_eq!(value[0]["insert"], "hello".into());
4254 let meta = value[0]["attributes"].as_map().unwrap();
4255 assert_eq!(meta.len(), 1);
4256 meta.get("bold").unwrap();
4257
4258 {
4260 handler2.insert(5, " new").unwrap();
4261 let value = handler2.get_richtext_value();
4262 assert_eq!(
4263 value.to_json_value(),
4264 serde_json::json!([
4265 {"insert": "hello new", "attributes": {"bold": true}},
4266 {"insert": " world"}
4267 ])
4268 );
4269 }
4270 }
4271
4272 #[test]
4273 fn richtext_snapshot() {
4274 let loro = LoroDoc::new();
4275 let mut txn = loro.txn().unwrap();
4276 let handler = loro.get_text("richtext");
4277 handler.insert_with_txn(&mut txn, 0, "hello world").unwrap();
4278 handler
4279 .mark_with_txn(&mut txn, 0, 5, "bold", true.into(), false)
4280 .unwrap();
4281 txn.commit().unwrap();
4282
4283 let loro2 = LoroDoc::new();
4284 loro2.import(&loro.export_snapshot().unwrap()).unwrap();
4285 let handler2 = loro2.get_text("richtext");
4286 assert_eq!(
4287 handler2.get_richtext_value().to_json_value(),
4288 serde_json::json!([
4289 {"insert": "hello", "attributes": {"bold": true}},
4290 {"insert": " world"}
4291 ])
4292 );
4293 }
4294
4295 #[test]
4296 fn tree_meta() {
4297 let loro = LoroDoc::new_auto_commit();
4298 loro.set_peer_id(1).unwrap();
4299 let tree = loro.get_tree("root");
4300 let id = tree.create(TreeParentId::Root).unwrap();
4301 let meta = tree.get_meta(id).unwrap();
4302 meta.insert("a", 123).unwrap();
4303 loro.commit_then_renew();
4304 let meta = tree.get_meta(id).unwrap();
4305 assert_eq!(meta.get("a").unwrap(), 123.into());
4306 assert_eq!(
4307 json!([{"parent":null,"meta":{"a":123},"id":"0@1","index":0,"children":[],"fractional_index":"80"}]),
4308 tree.get_deep_value().to_json_value()
4309 );
4310 let bytes = loro.export_snapshot().unwrap();
4311 let loro2 = LoroDoc::new();
4312 loro2.import(&bytes).unwrap();
4313 }
4314
4315 #[test]
4316 fn tree_meta_event() {
4317 use std::sync::Arc;
4318 let loro = LoroDoc::new_auto_commit();
4319 let tree = loro.get_tree("root");
4320 let text = loro.get_text("text");
4321
4322 let id = tree.create(TreeParentId::Root).unwrap();
4323 let meta = tree.get_meta(id).unwrap();
4324 meta.insert("a", 1).unwrap();
4325 text.insert(0, "abc").unwrap();
4326 let _id2 = tree.create(TreeParentId::Root).unwrap();
4327 meta.insert("b", 2).unwrap();
4328
4329 let loro2 = LoroDoc::new_auto_commit();
4330 let _g = loro2.subscribe_root(Arc::new(|e| {
4331 println!("{} {:?} ", e.event_meta.by, e.event_meta.diff)
4332 }));
4333 loro2.import(&loro.export_from(&loro2.oplog_vv())).unwrap();
4334 assert_eq!(loro.get_deep_value(), loro2.get_deep_value());
4335 }
4336
4337 #[test]
4338 fn richtext_apply_delta() {
4339 let loro = LoroDoc::new_auto_commit();
4340 let text = loro.get_text("text");
4341 text.apply_delta(&[TextDelta::Insert {
4342 insert: "Hello World!".into(),
4343 attributes: None,
4344 }])
4345 .unwrap();
4346 dbg!(text.get_richtext_value());
4347 text.apply_delta(&[
4348 TextDelta::Retain {
4349 retain: 6,
4350 attributes: Some(fx_map!("italic".into() => loro_common::LoroValue::Bool(true))),
4351 },
4352 TextDelta::Insert {
4353 insert: "New ".into(),
4354 attributes: Some(fx_map!("bold".into() => loro_common::LoroValue::Bool(true))),
4355 },
4356 ])
4357 .unwrap();
4358 dbg!(text.get_richtext_value());
4359 loro.commit_then_renew();
4360 assert_eq!(
4361 text.get_richtext_value().to_json_value(),
4362 json!([
4363 {"insert": "Hello ", "attributes": {"italic": true}},
4364 {"insert": "New ", "attributes": {"bold": true}},
4365 {"insert": "World!"}
4366
4367 ])
4368 )
4369 }
4370}