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