loro_internal/
handler.rs

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