loro_internal/
handler.rs

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