loro_internal/
handler.rs

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