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    fn len(&self, pos_type: PosType) -> usize {
1425        match &self.inner {
1426            MaybeDetached::Detached(t) => t.lock().unwrap().value.len(pos_type),
1427            MaybeDetached::Attached(a) => {
1428                a.with_state(|state| state.as_richtext_state_mut().unwrap().len(pos_type))
1429            }
1430        }
1431    }
1432
1433    pub fn diagnose(&self) {
1434        match &self.inner {
1435            MaybeDetached::Detached(t) => {
1436                let t = t.lock().unwrap();
1437                t.value.diagnose();
1438            }
1439            MaybeDetached::Attached(a) => {
1440                a.with_state(|state| state.as_richtext_state_mut().unwrap().diagnose());
1441            }
1442        }
1443    }
1444
1445    pub fn iter(&self, mut callback: impl FnMut(&str) -> bool) {
1446        match &self.inner {
1447            MaybeDetached::Detached(t) => {
1448                let t = t.lock().unwrap();
1449                for span in t.value.iter() {
1450                    if !callback(span.text.as_str()) {
1451                        return;
1452                    }
1453                }
1454            }
1455            MaybeDetached::Attached(a) => {
1456                a.with_state(|state| {
1457                    state.as_richtext_state_mut().unwrap().iter(callback);
1458                });
1459            }
1460        }
1461    }
1462
1463    /// Get a character at `pos` in the coordinate system specified by `pos_type`.
1464    pub fn char_at(&self, pos: usize, pos_type: PosType) -> LoroResult<char> {
1465        let len = self.len(pos_type);
1466        if pos >= len {
1467            return Err(LoroError::OutOfBound {
1468                pos,
1469                len,
1470                info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
1471            });
1472        }
1473        if let Ok(c) = match &self.inner {
1474            MaybeDetached::Detached(t) => {
1475                let t = t.lock().unwrap();
1476                let event_pos = match pos_type {
1477                    PosType::Event => pos,
1478                    _ => t.value.index_to_event_index(pos, pos_type),
1479                };
1480                t.value.get_char_by_event_index(event_pos)
1481            }
1482            MaybeDetached::Attached(a) => a.with_state(|state| {
1483                let state = state.as_richtext_state_mut().unwrap();
1484                let event_pos = match pos_type {
1485                    PosType::Event => pos,
1486                    _ => state.index_to_event_index(pos, pos_type),
1487                };
1488                state.get_char_by_event_index(event_pos)
1489            }),
1490        } {
1491            Ok(c)
1492        } else {
1493            Err(LoroError::OutOfBound {
1494                pos,
1495                len,
1496                info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
1497            })
1498        }
1499    }
1500
1501    /// `start_index` and `end_index` are Event Index:
1502    ///
1503    /// - if feature="wasm", pos is a UTF-16 index
1504    /// - if feature!="wasm", pos is a Unicode index
1505    ///
1506    pub fn slice(
1507        &self,
1508        start_index: usize,
1509        end_index: usize,
1510        pos_type: PosType,
1511    ) -> LoroResult<String> {
1512        self.slice_with_pos_type(start_index, end_index, pos_type)
1513    }
1514
1515    pub fn slice_utf16(&self, start_index: usize, end_index: usize) -> LoroResult<String> {
1516        self.slice(start_index, end_index, PosType::Utf16)
1517    }
1518
1519    fn slice_with_pos_type(
1520        &self,
1521        start_index: usize,
1522        end_index: usize,
1523        pos_type: PosType,
1524    ) -> LoroResult<String> {
1525        if end_index < start_index {
1526            return Err(LoroError::EndIndexLessThanStartIndex {
1527                start: start_index,
1528                end: end_index,
1529            });
1530        }
1531        if start_index == end_index {
1532            return Ok(String::new());
1533        }
1534
1535        let info = || format!("Position: {}:{}", file!(), line!()).into_boxed_str();
1536        match &self.inner {
1537            MaybeDetached::Detached(t) => {
1538                let t = t.lock().unwrap();
1539                let len = t.value.len(pos_type);
1540                if end_index > len {
1541                    return Err(LoroError::OutOfBound {
1542                        pos: end_index,
1543                        len,
1544                        info: info(),
1545                    });
1546                }
1547                let (start, end) = match pos_type {
1548                    PosType::Event => (start_index, end_index),
1549                    _ => (
1550                        t.value.index_to_event_index(start_index, pos_type),
1551                        t.value.index_to_event_index(end_index, pos_type),
1552                    ),
1553                };
1554                t.value.get_text_slice_by_event_index(start, end - start)
1555            }
1556            MaybeDetached::Attached(a) => a.with_state(|state| {
1557                let state = state.as_richtext_state_mut().unwrap();
1558                let len = state.len(pos_type);
1559                if end_index > len {
1560                    return Err(LoroError::OutOfBound {
1561                        pos: end_index,
1562                        len,
1563                        info: info(),
1564                    });
1565                }
1566                let (start, end) = match pos_type {
1567                    PosType::Event => (start_index, end_index),
1568                    _ => (
1569                        state.index_to_event_index(start_index, pos_type),
1570                        state.index_to_event_index(end_index, pos_type),
1571                    ),
1572                };
1573                state.get_text_slice_by_event_index(start, end - start)
1574            }),
1575        }
1576    }
1577
1578    pub fn slice_delta(
1579        &self,
1580        start_index: usize,
1581        end_index: usize,
1582        pos_type: PosType,
1583    ) -> LoroResult<Vec<TextDelta>> {
1584        match &self.inner {
1585            MaybeDetached::Detached(t) => {
1586                let t = t.lock().unwrap();
1587                let ans = t.value.slice_delta(start_index, end_index, pos_type)?;
1588                Ok(ans
1589                    .into_iter()
1590                    .map(|(s, a)| TextDelta::Insert {
1591                        insert: s,
1592                        attributes: a.to_option_map(),
1593                    })
1594                    .collect())
1595            }
1596            MaybeDetached::Attached(a) => a.with_state(|state| {
1597                let ans = state.as_richtext_state_mut().unwrap().slice_delta(
1598                    start_index,
1599                    end_index,
1600                    pos_type,
1601                )?;
1602                Ok(ans
1603                    .into_iter()
1604                    .map(|(s, a)| TextDelta::Insert {
1605                        insert: s,
1606                        attributes: a.to_option_map(),
1607                    })
1608                    .collect())
1609            }),
1610        }
1611    }
1612
1613    /// `pos` is a Event Index:
1614    ///
1615    /// - if feature="wasm", pos is a UTF-16 index
1616    /// - if feature!="wasm", pos is a Unicode index
1617    ///
1618    /// This method requires auto_commit to be enabled.
1619    pub fn splice(&self, pos: usize, len: usize, s: &str, pos_type: PosType) -> LoroResult<String> {
1620        let x = self.slice(pos, pos + len, pos_type)?;
1621        self.delete(pos, len, pos_type)?;
1622        self.insert(pos, s, pos_type)?;
1623        Ok(x)
1624    }
1625
1626    pub fn splice_utf8(&self, pos: usize, len: usize, s: &str) -> LoroResult<()> {
1627        // let x = self.slice(pos, pos + len)?;
1628        self.delete_utf8(pos, len)?;
1629        self.insert_utf8(pos, s)?;
1630        Ok(())
1631    }
1632
1633    pub fn splice_utf16(&self, pos: usize, len: usize, s: &str) -> LoroResult<()> {
1634        self.delete(pos, len, PosType::Utf16)?;
1635        self.insert(pos, s, PosType::Utf16)?;
1636        Ok(())
1637    }
1638
1639    /// Insert text at `pos` using the given `pos_type` coordinate system.
1640    ///
1641    /// This method requires auto_commit to be enabled.
1642    pub fn insert(&self, pos: usize, s: &str, pos_type: PosType) -> LoroResult<()> {
1643        match &self.inner {
1644            MaybeDetached::Detached(t) => {
1645                let mut t = t.lock().unwrap();
1646                let (index, _) = t
1647                    .value
1648                    .get_entity_index_for_text_insert(pos, pos_type)
1649                    .unwrap();
1650                t.value.insert_at_entity_index(
1651                    index,
1652                    BytesSlice::from_bytes(s.as_bytes()),
1653                    IdFull::NONE_ID,
1654                );
1655                Ok(())
1656            }
1657            MaybeDetached::Attached(a) => {
1658                a.with_txn(|txn| self.insert_with_txn(txn, pos, s, pos_type))
1659            }
1660        }
1661    }
1662
1663    pub fn insert_utf8(&self, pos: usize, s: &str) -> LoroResult<()> {
1664        self.insert(pos, s, PosType::Bytes)
1665    }
1666
1667    pub fn insert_utf16(&self, pos: usize, s: &str) -> LoroResult<()> {
1668        self.insert(pos, s, PosType::Utf16)
1669    }
1670
1671    pub fn insert_unicode(&self, pos: usize, s: &str) -> LoroResult<()> {
1672        self.insert(pos, s, PosType::Unicode)
1673    }
1674
1675    /// Insert text within an existing transaction using the provided `pos_type`.
1676    pub fn insert_with_txn(
1677        &self,
1678        txn: &mut Transaction,
1679        pos: usize,
1680        s: &str,
1681        pos_type: PosType,
1682    ) -> LoroResult<()> {
1683        self.insert_with_txn_and_attr(txn, pos, s, None, pos_type)?;
1684        Ok(())
1685    }
1686
1687    pub fn insert_with_txn_utf8(
1688        &self,
1689        txn: &mut Transaction,
1690        pos: usize,
1691        s: &str,
1692    ) -> LoroResult<()> {
1693        self.insert_with_txn(txn, pos, s, PosType::Bytes)
1694    }
1695
1696    /// Delete a span using the coordinate system described by `pos_type`.
1697    ///
1698    /// This method requires auto_commit to be enabled.
1699    pub fn delete(&self, pos: usize, len: usize, pos_type: PosType) -> LoroResult<()> {
1700        match &self.inner {
1701            MaybeDetached::Detached(t) => {
1702                let mut t = t.lock().unwrap();
1703                let ranges = t.value.get_text_entity_ranges(pos, len, pos_type)?;
1704                for range in ranges.iter().rev() {
1705                    t.value
1706                        .drain_by_entity_index(range.entity_start, range.entity_len(), None);
1707                }
1708                Ok(())
1709            }
1710            MaybeDetached::Attached(a) => {
1711                a.with_txn(|txn| self.delete_with_txn(txn, pos, len, pos_type))
1712            }
1713        }
1714    }
1715
1716    pub fn delete_utf8(&self, pos: usize, len: usize) -> LoroResult<()> {
1717        self.delete(pos, len, PosType::Bytes)
1718    }
1719
1720    pub fn delete_utf16(&self, pos: usize, len: usize) -> LoroResult<()> {
1721        self.delete(pos, len, PosType::Utf16)
1722    }
1723
1724    pub fn delete_unicode(&self, pos: usize, len: usize) -> LoroResult<()> {
1725        self.delete(pos, len, PosType::Unicode)
1726    }
1727
1728    /// If attr is specified, it will be used as the attribute of the inserted text.
1729    /// It will override the existing attribute of the text.
1730    fn insert_with_txn_and_attr(
1731        &self,
1732        txn: &mut Transaction,
1733        pos: usize,
1734        s: &str,
1735        attr: Option<&FxHashMap<String, LoroValue>>,
1736        pos_type: PosType,
1737    ) -> Result<Vec<(InternalString, LoroValue)>, LoroError> {
1738        if s.is_empty() {
1739            return Ok(Vec::new());
1740        }
1741
1742        match pos_type {
1743            PosType::Event => {
1744                if pos > self.len_event() {
1745                    return Err(LoroError::OutOfBound {
1746                        pos,
1747                        len: self.len_event(),
1748                        info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
1749                    });
1750                }
1751            }
1752            PosType::Bytes => {
1753                if pos > self.len_utf8() {
1754                    return Err(LoroError::OutOfBound {
1755                        pos,
1756                        len: self.len_utf8(),
1757                        info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
1758                    });
1759                }
1760            }
1761            PosType::Unicode => {
1762                if pos > self.len_unicode() {
1763                    return Err(LoroError::OutOfBound {
1764                        pos,
1765                        len: self.len_unicode(),
1766                        info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
1767                    });
1768                }
1769            }
1770            PosType::Entity => {}
1771            PosType::Utf16 => {
1772                if pos > self.len_utf16() {
1773                    return Err(LoroError::OutOfBound {
1774                        pos,
1775                        len: self.len_utf16(),
1776                        info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
1777                    });
1778                }
1779            }
1780        }
1781
1782        let inner = self.inner.try_attached_state()?;
1783        let (entity_index, event_index, styles) = inner.with_state(|state| {
1784            let richtext_state = state.as_richtext_state_mut().unwrap();
1785            let ret = richtext_state.get_entity_index_for_text_insert(pos, pos_type);
1786            let (entity_index, cursor) = match ret {
1787                Err(_) => match pos_type {
1788                    PosType::Bytes => {
1789                        return (
1790                            Err(LoroError::UTF8InUnicodeCodePoint { pos }),
1791                            0,
1792                            StyleMeta::empty(),
1793                        );
1794                    }
1795                    PosType::Utf16 | PosType::Event => {
1796                        return (
1797                            Err(LoroError::UTF16InUnicodeCodePoint { pos }),
1798                            0,
1799                            StyleMeta::empty(),
1800                        );
1801                    }
1802                    _ => unreachable!(),
1803                },
1804                Ok(x) => x,
1805            };
1806            let event_index = if let Some(cursor) = cursor {
1807                if pos_type == PosType::Event {
1808                    debug_assert_eq!(
1809                        richtext_state.get_event_index_by_cursor(cursor),
1810                        pos,
1811                        "pos={} cursor={:?} state={:#?}",
1812                        pos,
1813                        cursor,
1814                        &richtext_state
1815                    );
1816                    pos
1817                } else {
1818                    richtext_state.get_event_index_by_cursor(cursor)
1819                }
1820            } else {
1821                assert_eq!(entity_index, 0);
1822                0
1823            };
1824            let styles = richtext_state.get_styles_at_entity_index(entity_index);
1825            (Ok(entity_index), event_index, styles)
1826        });
1827
1828        let entity_index = match entity_index {
1829            Err(x) => return Err(x),
1830            _ => entity_index.unwrap(),
1831        };
1832
1833        let mut override_styles = Vec::new();
1834        if let Some(attr) = attr {
1835            // current styles
1836            let map: FxHashMap<_, _> = styles.iter().map(|x| (x.0.clone(), x.1.data)).collect();
1837            for (key, style) in map.iter() {
1838                match attr.get(key.deref()) {
1839                    Some(v) if v == style => {}
1840                    new_style_value => {
1841                        // need to override
1842                        let new_style_value = new_style_value.cloned().unwrap_or(LoroValue::Null);
1843                        override_styles.push((key.clone(), new_style_value));
1844                    }
1845                }
1846            }
1847
1848            for (key, style) in attr.iter() {
1849                let key = key.as_str().into();
1850                if !map.contains_key(&key) {
1851                    override_styles.push((key, style.clone()));
1852                }
1853            }
1854        }
1855
1856        let unicode_len = s.chars().count();
1857        let event_len = if cfg!(feature = "wasm") {
1858            count_utf16_len(s.as_bytes())
1859        } else {
1860            unicode_len
1861        };
1862
1863        txn.apply_local_op(
1864            inner.container_idx,
1865            crate::op::RawOpContent::List(crate::container::list::list_op::ListOp::Insert {
1866                slice: ListSlice::RawStr {
1867                    str: Cow::Borrowed(s),
1868                    unicode_len,
1869                },
1870                pos: entity_index,
1871            }),
1872            EventHint::InsertText {
1873                pos: event_index as u32,
1874                styles,
1875                unicode_len: unicode_len as u32,
1876                event_len: event_len as u32,
1877            },
1878            &inner.doc,
1879        )?;
1880
1881        Ok(override_styles)
1882    }
1883
1884    /// Delete text within a transaction using the specified `pos_type`.
1885    pub fn delete_with_txn(
1886        &self,
1887        txn: &mut Transaction,
1888        pos: usize,
1889        len: usize,
1890        pos_type: PosType,
1891    ) -> LoroResult<()> {
1892        self.delete_with_txn_inline(txn, pos, len, pos_type)
1893    }
1894
1895    fn delete_with_txn_inline(
1896        &self,
1897        txn: &mut Transaction,
1898        pos: usize,
1899        len: usize,
1900        pos_type: PosType,
1901    ) -> LoroResult<()> {
1902        if len == 0 {
1903            return Ok(());
1904        }
1905
1906        if pos + len > self.len(pos_type) {
1907            error!("pos={} len={} len_event={}", pos, len, self.len_event());
1908            return Err(LoroError::OutOfBound {
1909                pos: pos + len,
1910                len: self.len_event(),
1911                info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
1912            });
1913        }
1914
1915        let inner = self.inner.try_attached_state()?;
1916        let s = tracing::span!(tracing::Level::INFO, "delete", "pos={} len={}", pos, len);
1917        let _e = s.enter();
1918        let mut event_pos = 0;
1919        let mut event_len = 0;
1920        let ranges = inner.with_state(|state| {
1921            let richtext_state = state.as_richtext_state_mut().unwrap();
1922            event_pos = richtext_state.index_to_event_index(pos, pos_type);
1923            let event_end = richtext_state.index_to_event_index(pos + len, pos_type);
1924            event_len = event_end - event_pos;
1925
1926            richtext_state.get_text_entity_ranges_in_event_index_range(event_pos, event_len)
1927        })?;
1928
1929        //debug_assert_eq!(ranges.iter().map(|x| x.event_len).sum::<usize>(), len);
1930        let pos = event_pos as isize;
1931        let len = event_len as isize;
1932        let mut event_end = pos + len;
1933        for range in ranges.iter().rev() {
1934            let event_start = event_end - range.event_len as isize;
1935            txn.apply_local_op(
1936                inner.container_idx,
1937                crate::op::RawOpContent::List(ListOp::Delete(DeleteSpanWithId::new(
1938                    range.id_start,
1939                    range.entity_start as isize,
1940                    range.entity_len() as isize,
1941                ))),
1942                EventHint::DeleteText {
1943                    span: DeleteSpan {
1944                        pos: event_start,
1945                        signed_len: range.event_len as isize,
1946                    },
1947                    unicode_len: range.entity_len(),
1948                },
1949                &inner.doc,
1950            )?;
1951            event_end = event_start;
1952        }
1953
1954        Ok(())
1955    }
1956
1957    /// `start` and `end` are interpreted using `pos_type`.
1958    ///
1959    /// This method requires auto_commit to be enabled.
1960    pub fn mark(
1961        &self,
1962        start: usize,
1963        end: usize,
1964        key: impl Into<InternalString>,
1965        value: LoroValue,
1966        pos_type: PosType,
1967    ) -> LoroResult<()> {
1968        match &self.inner {
1969            MaybeDetached::Detached(t) => {
1970                let mut g = t.lock().unwrap();
1971                self.mark_for_detached(&mut g.value, key, &value, start, end, pos_type, false)
1972            }
1973            MaybeDetached::Attached(a) => {
1974                a.with_txn(|txn| self.mark_with_txn(txn, start, end, key, value, pos_type, false))
1975            }
1976        }
1977    }
1978
1979    fn mark_for_detached(
1980        &self,
1981        state: &mut RichtextState,
1982        key: impl Into<InternalString>,
1983        value: &LoroValue,
1984        start: usize,
1985        end: usize,
1986        pos_type: PosType,
1987        is_delete: bool,
1988    ) -> Result<(), LoroError> {
1989        let key: InternalString = key.into();
1990        if start >= end {
1991            return Err(loro_common::LoroError::ArgErr(
1992                "Start must be less than end".to_string().into_boxed_str(),
1993            ));
1994        }
1995
1996        let len = state.len(pos_type);
1997        if end > len {
1998            return Err(LoroError::OutOfBound {
1999                pos: end,
2000                len,
2001                info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2002            });
2003        }
2004        let (entity_range, styles) =
2005            state.get_entity_range_and_text_styles_at_range(start..end, pos_type);
2006        if let Some(styles) = styles {
2007            if styles.has_key_value(&key, value) {
2008                // already has the same style, skip
2009                return Ok(());
2010            }
2011        }
2012
2013        let style_op = Arc::new(StyleOp {
2014            lamport: 0,
2015            peer: 0,
2016            cnt: 0,
2017            key,
2018            value: value.clone(),
2019            // TODO: describe this behavior in the document
2020            info: if is_delete {
2021                TextStyleInfoFlag::BOLD.to_delete()
2022            } else {
2023                TextStyleInfoFlag::BOLD
2024            },
2025        });
2026        state.mark_with_entity_index(entity_range, style_op);
2027        Ok(())
2028    }
2029
2030    /// `start` and `end` are interpreted using `pos_type`.
2031    pub fn unmark(
2032        &self,
2033        start: usize,
2034        end: usize,
2035        key: impl Into<InternalString>,
2036        pos_type: PosType,
2037    ) -> LoroResult<()> {
2038        match &self.inner {
2039            MaybeDetached::Detached(t) => self.mark_for_detached(
2040                &mut t.lock().unwrap().value,
2041                key,
2042                &LoroValue::Null,
2043                start,
2044                end,
2045                pos_type,
2046                true,
2047            ),
2048            MaybeDetached::Attached(a) => a.with_txn(|txn| {
2049                self.mark_with_txn(txn, start, end, key, LoroValue::Null, pos_type, true)
2050            }),
2051        }
2052    }
2053
2054    /// `start` and `end` are interpreted using `pos_type`.
2055    pub fn mark_with_txn(
2056        &self,
2057        txn: &mut Transaction,
2058        start: usize,
2059        end: usize,
2060        key: impl Into<InternalString>,
2061        value: LoroValue,
2062        pos_type: PosType,
2063        is_delete: bool,
2064    ) -> LoroResult<()> {
2065        if start >= end {
2066            return Err(loro_common::LoroError::ArgErr(
2067                "Start must be less than end".to_string().into_boxed_str(),
2068            ));
2069        }
2070
2071        let inner = self.inner.try_attached_state()?;
2072        let key: InternalString = key.into();
2073
2074        let mut doc_state = inner.doc.state.lock().unwrap();
2075        let len = doc_state.with_state_mut(inner.container_idx, |state| {
2076            state.as_richtext_state_mut().unwrap().len(pos_type)
2077        });
2078
2079        if end > len {
2080            return Err(LoroError::OutOfBound {
2081                pos: end,
2082                len,
2083                info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2084            });
2085        }
2086
2087        let (entity_range, skip, event_start, event_end) =
2088            doc_state.with_state_mut(inner.container_idx, |state| {
2089                let state = state.as_richtext_state_mut().unwrap();
2090                let event_start = state.index_to_event_index(start, pos_type);
2091                let event_end = state.index_to_event_index(end, pos_type);
2092                let (entity_range, styles) =
2093                    state.get_entity_range_and_styles_at_range(start..end, pos_type);
2094
2095                let skip = match styles {
2096                    Some(styles) if styles.has_key_value(&key, &value) => {
2097                        // already has the same style, skip
2098                        true
2099                    }
2100                    _ => false,
2101                };
2102
2103                (entity_range, skip, event_start, event_end)
2104            });
2105
2106        if skip {
2107            return Ok(());
2108        }
2109
2110        let entity_start = entity_range.start;
2111        let entity_end = entity_range.end;
2112        let style_config = doc_state.config.text_style_config.try_read().unwrap();
2113        let flag = if is_delete {
2114            style_config
2115                .get_style_flag_for_unmark(&key)
2116                .ok_or_else(|| LoroError::StyleConfigMissing(key.clone()))?
2117        } else {
2118            style_config
2119                .get_style_flag(&key)
2120                .ok_or_else(|| LoroError::StyleConfigMissing(key.clone()))?
2121        };
2122
2123        drop(style_config);
2124        drop(doc_state);
2125        txn.apply_local_op(
2126            inner.container_idx,
2127            crate::op::RawOpContent::List(ListOp::StyleStart {
2128                start: entity_start as u32,
2129                end: entity_end as u32,
2130                key: key.clone(),
2131                value: value.clone(),
2132                info: flag,
2133            }),
2134            EventHint::Mark {
2135                start: event_start as u32,
2136                end: event_end as u32,
2137                style: crate::container::richtext::Style { key, data: value },
2138            },
2139            &inner.doc,
2140        )?;
2141
2142        txn.apply_local_op(
2143            inner.container_idx,
2144            crate::op::RawOpContent::List(ListOp::StyleEnd),
2145            EventHint::MarkEnd,
2146            &inner.doc,
2147        )?;
2148
2149        Ok(())
2150    }
2151
2152    pub fn check(&self) {
2153        match &self.inner {
2154            MaybeDetached::Detached(t) => {
2155                let t = t.lock().unwrap();
2156                t.value.check_consistency_between_content_and_style_ranges();
2157            }
2158            MaybeDetached::Attached(a) => a.with_state(|state| {
2159                state
2160                    .as_richtext_state_mut()
2161                    .unwrap()
2162                    .check_consistency_between_content_and_style_ranges();
2163            }),
2164        }
2165    }
2166
2167    pub fn apply_delta(&self, delta: &[TextDelta]) -> LoroResult<()> {
2168        match &self.inner {
2169            MaybeDetached::Detached(t) => {
2170                let _t = t.lock().unwrap();
2171                // TODO: implement
2172                Err(LoroError::NotImplemented(
2173                    "`apply_delta` on a detached text container",
2174                ))
2175            }
2176            MaybeDetached::Attached(a) => a.with_txn(|txn| self.apply_delta_with_txn(txn, delta)),
2177        }
2178    }
2179
2180    pub fn apply_delta_with_txn(
2181        &self,
2182        txn: &mut Transaction,
2183        delta: &[TextDelta],
2184    ) -> LoroResult<()> {
2185        let mut index = 0;
2186        struct PendingMark {
2187            start: usize,
2188            end: usize,
2189            attributes: FxHashMap<InternalString, LoroValue>,
2190        }
2191        let mut marks: Vec<PendingMark> = Vec::new();
2192        for d in delta {
2193            match d {
2194                TextDelta::Insert { insert, attributes } => {
2195                    let insert_len = event_len(insert.as_str());
2196                    if insert_len == 0 {
2197                        continue;
2198                    }
2199
2200                    let mut empty_attr = None;
2201                    let attr_ref = attributes.as_ref().unwrap_or_else(|| {
2202                        empty_attr = Some(FxHashMap::default());
2203                        empty_attr.as_ref().unwrap()
2204                    });
2205
2206                    let end = index + insert_len;
2207                    let override_styles = self.insert_with_txn_and_attr(
2208                        txn,
2209                        index,
2210                        insert.as_str(),
2211                        Some(attr_ref),
2212                        PosType::Event,
2213                    )?;
2214
2215                    let mut pending_mark = PendingMark {
2216                        start: index,
2217                        end,
2218                        attributes: FxHashMap::default(),
2219                    };
2220                    for (key, value) in override_styles {
2221                        pending_mark.attributes.insert(key, value);
2222                    }
2223                    marks.push(pending_mark);
2224                    index = end;
2225                }
2226                TextDelta::Delete { delete } => {
2227                    self.delete_with_txn(txn, index, *delete, PosType::Event)?;
2228                }
2229                TextDelta::Retain { attributes, retain } => {
2230                    let end = index + *retain;
2231                    match attributes {
2232                        Some(attr) if !attr.is_empty() => {
2233                            let mut pending_mark = PendingMark {
2234                                start: index,
2235                                end,
2236                                attributes: FxHashMap::default(),
2237                            };
2238                            for (key, value) in attr {
2239                                pending_mark
2240                                    .attributes
2241                                    .insert(key.deref().into(), value.clone());
2242                            }
2243                            marks.push(pending_mark);
2244                        }
2245                        _ => {}
2246                    }
2247                    index = end;
2248                }
2249            }
2250        }
2251
2252        let mut len = self.len_event();
2253        for pending_mark in marks {
2254            if pending_mark.start >= len {
2255                self.insert_with_txn(
2256                    txn,
2257                    len,
2258                    &"\n".repeat(pending_mark.start - len + 1),
2259                    PosType::Event,
2260                )?;
2261                len = pending_mark.start;
2262            }
2263
2264            for (key, value) in pending_mark.attributes {
2265                self.mark_with_txn(
2266                    txn,
2267                    pending_mark.start,
2268                    pending_mark.end,
2269                    key.deref(),
2270                    value,
2271                    PosType::Event,
2272                    false,
2273                )?;
2274            }
2275        }
2276
2277        Ok(())
2278    }
2279
2280    pub fn update(&self, text: &str, options: UpdateOptions) -> Result<(), UpdateTimeoutError> {
2281        let old_str = self.to_string();
2282        let new = text.chars().map(|x| x as u32).collect::<Vec<u32>>();
2283        let old = old_str.chars().map(|x| x as u32).collect::<Vec<u32>>();
2284        diff(
2285            &mut OperateProxy::new(text_update::DiffHook::new(self, &new)),
2286            options,
2287            &old,
2288            &new,
2289        )?;
2290        Ok(())
2291    }
2292
2293    pub fn update_by_line(
2294        &self,
2295        text: &str,
2296        options: UpdateOptions,
2297    ) -> Result<(), UpdateTimeoutError> {
2298        let hook = text_update::DiffHookForLine::new(self, text);
2299        let old_lines = hook.get_old_arr().to_vec();
2300        let new_lines = hook.get_new_arr().to_vec();
2301        diff(
2302            &mut OperateProxy::new(hook),
2303            options,
2304            &old_lines,
2305            &new_lines,
2306        )
2307    }
2308
2309    #[allow(clippy::inherent_to_string)]
2310    pub fn to_string(&self) -> String {
2311        match &self.inner {
2312            MaybeDetached::Detached(t) => t.lock().unwrap().value.to_string(),
2313            MaybeDetached::Attached(a) => a.get_value().into_string().unwrap().unwrap(),
2314        }
2315    }
2316
2317    pub fn get_cursor(&self, event_index: usize, side: Side) -> Option<Cursor> {
2318        self.get_cursor_internal(event_index, side, true)
2319    }
2320
2321    /// Get the stable position representation for the target pos
2322    pub(crate) fn get_cursor_internal(
2323        &self,
2324        index: usize,
2325        side: Side,
2326        get_by_event_index: bool,
2327    ) -> Option<Cursor> {
2328        match &self.inner {
2329            MaybeDetached::Detached(_) => None,
2330            MaybeDetached::Attached(a) => {
2331                let (id, len, origin_pos) = a.with_state(|s| {
2332                    let s = s.as_richtext_state_mut().unwrap();
2333                    (
2334                        s.get_stable_position(index, get_by_event_index),
2335                        if get_by_event_index {
2336                            s.len_event()
2337                        } else {
2338                            s.len_unicode()
2339                        },
2340                        if get_by_event_index {
2341                            s.event_index_to_unicode_index(index)
2342                        } else {
2343                            index
2344                        },
2345                    )
2346                });
2347
2348                if len == 0 {
2349                    return Some(Cursor {
2350                        id: None,
2351                        container: self.id(),
2352                        side: if side == Side::Middle {
2353                            Side::Left
2354                        } else {
2355                            side
2356                        },
2357                        origin_pos: 0,
2358                    });
2359                }
2360
2361                if len <= index {
2362                    return Some(Cursor {
2363                        id: None,
2364                        container: self.id(),
2365                        side: Side::Right,
2366                        origin_pos: len,
2367                    });
2368                }
2369
2370                let id = id?;
2371                Some(Cursor {
2372                    id: Some(id),
2373                    container: self.id(),
2374                    side,
2375                    origin_pos,
2376                })
2377            }
2378        }
2379    }
2380
2381    pub(crate) fn convert_entity_index_to_event_index(&self, entity_index: usize) -> usize {
2382        match &self.inner {
2383            MaybeDetached::Detached(s) => s
2384                .lock()
2385                .unwrap()
2386                .value
2387                .entity_index_to_event_index(entity_index),
2388            MaybeDetached::Attached(a) => {
2389                let mut pos = 0;
2390                a.with_state(|s| {
2391                    let s = s.as_richtext_state_mut().unwrap();
2392                    pos = s.entity_index_to_event_index(entity_index);
2393                });
2394                pos
2395            }
2396        }
2397    }
2398
2399    pub fn get_delta(&self) -> Vec<TextDelta> {
2400        match &self.inner {
2401            MaybeDetached::Detached(s) => {
2402                let mut delta = Vec::new();
2403                for span in s.lock().unwrap().value.iter() {
2404                    if span.text.as_str().is_empty() {
2405                        continue;
2406                    }
2407
2408                    let next_attr = span.attributes.to_option_map();
2409                    match delta.last_mut() {
2410                        Some(TextDelta::Insert { insert, attributes })
2411                            if &next_attr == attributes =>
2412                        {
2413                            insert.push_str(span.text.as_str());
2414                            continue;
2415                        }
2416                        _ => {}
2417                    }
2418
2419                    delta.push(TextDelta::Insert {
2420                        insert: span.text.as_str().to_string(),
2421                        attributes: next_attr,
2422                    })
2423                }
2424                delta
2425            }
2426            MaybeDetached::Attached(_a) => self
2427                .with_state(|state| {
2428                    let state = state.as_richtext_state_mut().unwrap();
2429                    Ok(state.get_delta())
2430                })
2431                .unwrap(),
2432        }
2433    }
2434
2435    pub fn is_deleted(&self) -> bool {
2436        match &self.inner {
2437            MaybeDetached::Detached(_) => false,
2438            MaybeDetached::Attached(a) => a.is_deleted(),
2439        }
2440    }
2441
2442    pub fn push_str(&self, s: &str) -> LoroResult<()> {
2443        self.insert_utf8(self.len_utf8(), s)
2444    }
2445
2446    pub fn clear(&self) -> LoroResult<()> {
2447        match &self.inner {
2448            MaybeDetached::Detached(mutex) => {
2449                let mut t = mutex.lock().unwrap();
2450                let len = t.value.len_unicode();
2451                let ranges = t.value.get_text_entity_ranges(0, len, PosType::Unicode)?;
2452                for range in ranges.iter().rev() {
2453                    t.value
2454                        .drain_by_entity_index(range.entity_start, range.entity_len(), None);
2455                }
2456                Ok(())
2457            }
2458            MaybeDetached::Attached(a) => a.with_txn(|txn| {
2459                let len = a.with_state(|s| s.as_richtext_state_mut().unwrap().len_unicode());
2460                self.delete_with_txn_inline(txn, 0, len, PosType::Unicode)
2461            }),
2462        }
2463    }
2464
2465    /// Convert a position `index` from one coordinate system to another.
2466    ///
2467    /// Supported `PosType` conversions: `Event`, `Unicode`, `Utf16`, and `Bytes`.
2468    /// Returns `None` if the index is out of bounds or the conversion is unsupported.
2469    pub fn convert_pos(&self, index: usize, from: PosType, to: PosType) -> Option<usize> {
2470        if from == to {
2471            return Some(index);
2472        }
2473
2474        if matches!(from, PosType::Entity) || matches!(to, PosType::Entity) {
2475            return None;
2476        }
2477
2478        // Normalize to event + unicode indices for the given position.
2479        let (event_index, unicode_index) = match &self.inner {
2480            MaybeDetached::Detached(t) => {
2481                let t = t.lock().unwrap();
2482                if index > t.value.len(from) {
2483                    return None;
2484                }
2485                let event_index = if from == PosType::Event {
2486                    index
2487                } else {
2488                    t.value.index_to_event_index(index, from)
2489                };
2490                let unicode_index = if from == PosType::Unicode {
2491                    index
2492                } else {
2493                    t.value.event_index_to_unicode_index(event_index)
2494                };
2495                (event_index, unicode_index)
2496            }
2497            MaybeDetached::Attached(a) => {
2498                let res: Option<(usize, usize)> = a.with_state(|state| {
2499                    let state = state.as_richtext_state_mut().unwrap();
2500                    if index > state.len(from) {
2501                        return None;
2502                    }
2503
2504                    let event_index = if from == PosType::Event {
2505                        index
2506                    } else {
2507                        state.index_to_event_index(index, from)
2508                    };
2509                    let unicode_index = if from == PosType::Unicode {
2510                        index
2511                    } else {
2512                        state.event_index_to_unicode_index(event_index)
2513                    };
2514                    Some((event_index, unicode_index))
2515                });
2516
2517                match res {
2518                    Some(v) => v,
2519                    None => return None,
2520                }
2521            }
2522        };
2523
2524        let result = match to {
2525            PosType::Unicode => Some(unicode_index),
2526            PosType::Event => Some(event_index),
2527            PosType::Bytes | PosType::Utf16 => {
2528                // Use the prefix text to compute target offset.
2529                let prefix = match &self.inner {
2530                    MaybeDetached::Detached(t) => {
2531                        let t = t.lock().unwrap();
2532                        if event_index > t.value.len_event() {
2533                            return None;
2534                        }
2535                        t.value.get_text_slice_by_event_index(0, event_index).ok()?
2536                    }
2537                    MaybeDetached::Attached(a) => {
2538                        let res: Result<String, ()> = a.with_state(|state| {
2539                            let state = state.as_richtext_state_mut().unwrap();
2540                            if event_index > state.len_event() {
2541                                return Err(());
2542                            }
2543                            state
2544                                .get_text_slice_by_event_index(0, event_index)
2545                                .map_err(|_| ())
2546                        });
2547
2548                        match res {
2549                            Ok(v) => v,
2550                            Err(_) => return None,
2551                        }
2552                    }
2553                };
2554
2555                Some(match to {
2556                    PosType::Bytes => prefix.len(),
2557                    PosType::Utf16 => count_utf16_len(prefix.as_bytes()),
2558                    _ => unreachable!(),
2559                })
2560            }
2561            PosType::Entity => None,
2562        };
2563        result
2564    }
2565}
2566
2567fn event_len(s: &str) -> usize {
2568    if cfg!(feature = "wasm") {
2569        count_utf16_len(s.as_bytes())
2570    } else {
2571        s.chars().count()
2572    }
2573}
2574
2575impl ListHandler {
2576    /// Create a new container that is detached from the document.
2577    /// The edits on a detached container will not be persisted.
2578    /// To attach the container to the document, please insert it into an attached container.
2579    pub fn new_detached() -> Self {
2580        Self {
2581            inner: MaybeDetached::new_detached(Vec::new()),
2582        }
2583    }
2584
2585    pub fn insert(&self, pos: usize, v: impl Into<LoroValue>) -> LoroResult<()> {
2586        match &self.inner {
2587            MaybeDetached::Detached(l) => {
2588                let mut list = l.lock().unwrap();
2589                list.value.insert(pos, ValueOrHandler::Value(v.into()));
2590                Ok(())
2591            }
2592            MaybeDetached::Attached(a) => {
2593                a.with_txn(|txn| self.insert_with_txn(txn, pos, v.into()))
2594            }
2595        }
2596    }
2597
2598    pub fn insert_with_txn(
2599        &self,
2600        txn: &mut Transaction,
2601        pos: usize,
2602        v: LoroValue,
2603    ) -> LoroResult<()> {
2604        if pos > self.len() {
2605            return Err(LoroError::OutOfBound {
2606                pos,
2607                info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2608                len: self.len(),
2609            });
2610        }
2611
2612        let inner = self.inner.try_attached_state()?;
2613        if let Some(_container) = v.as_container() {
2614            return Err(LoroError::ArgErr(
2615                INSERT_CONTAINER_VALUE_ARG_ERROR
2616                    .to_string()
2617                    .into_boxed_str(),
2618            ));
2619        }
2620
2621        txn.apply_local_op(
2622            inner.container_idx,
2623            crate::op::RawOpContent::List(crate::container::list::list_op::ListOp::Insert {
2624                slice: ListSlice::RawData(Cow::Owned(vec![v.clone()])),
2625                pos,
2626            }),
2627            EventHint::InsertList { len: 1, pos },
2628            &inner.doc,
2629        )
2630    }
2631
2632    pub fn push(&self, v: impl Into<LoroValue>) -> LoroResult<()> {
2633        match &self.inner {
2634            MaybeDetached::Detached(l) => {
2635                let mut list = l.lock().unwrap();
2636                list.value.push(ValueOrHandler::Value(v.into()));
2637                Ok(())
2638            }
2639            MaybeDetached::Attached(a) => a.with_txn(|txn| self.push_with_txn(txn, v.into())),
2640        }
2641    }
2642
2643    pub fn push_with_txn(&self, txn: &mut Transaction, v: LoroValue) -> LoroResult<()> {
2644        let pos = self.len();
2645        self.insert_with_txn(txn, pos, v)
2646    }
2647
2648    pub fn pop(&self) -> LoroResult<Option<LoroValue>> {
2649        match &self.inner {
2650            MaybeDetached::Detached(l) => {
2651                let mut list = l.lock().unwrap();
2652                Ok(list.value.pop().map(|v| v.to_value()))
2653            }
2654            MaybeDetached::Attached(a) => a.with_txn(|txn| self.pop_with_txn(txn)),
2655        }
2656    }
2657
2658    pub fn pop_with_txn(&self, txn: &mut Transaction) -> LoroResult<Option<LoroValue>> {
2659        let len = self.len();
2660        if len == 0 {
2661            return Ok(None);
2662        }
2663
2664        let v = self.get(len - 1);
2665        self.delete_with_txn(txn, len - 1, 1)?;
2666        Ok(v)
2667    }
2668
2669    pub fn insert_container<H: HandlerTrait>(&self, pos: usize, child: H) -> LoroResult<H> {
2670        match &self.inner {
2671            MaybeDetached::Detached(l) => {
2672                let mut list = l.lock().unwrap();
2673                list.value
2674                    .insert(pos, ValueOrHandler::Handler(child.to_handler()));
2675                Ok(child)
2676            }
2677            MaybeDetached::Attached(a) => {
2678                a.with_txn(|txn| self.insert_container_with_txn(txn, pos, child))
2679            }
2680        }
2681    }
2682
2683    pub fn push_container<H: HandlerTrait>(&self, child: H) -> LoroResult<H> {
2684        self.insert_container(self.len(), child)
2685    }
2686
2687    pub fn insert_container_with_txn<H: HandlerTrait>(
2688        &self,
2689        txn: &mut Transaction,
2690        pos: usize,
2691        child: H,
2692    ) -> LoroResult<H> {
2693        if pos > self.len() {
2694            return Err(LoroError::OutOfBound {
2695                pos,
2696                info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2697                len: self.len(),
2698            });
2699        }
2700
2701        let inner = self.inner.try_attached_state()?;
2702        let id = txn.next_id();
2703        let container_id = ContainerID::new_normal(id, child.kind());
2704        let v = LoroValue::Container(container_id.clone());
2705        txn.apply_local_op(
2706            inner.container_idx,
2707            crate::op::RawOpContent::List(crate::container::list::list_op::ListOp::Insert {
2708                slice: ListSlice::RawData(Cow::Owned(vec![v.clone()])),
2709                pos,
2710            }),
2711            EventHint::InsertList { len: 1, pos },
2712            &inner.doc,
2713        )?;
2714        let ans = child.attach(txn, inner, container_id)?;
2715        Ok(ans)
2716    }
2717
2718    pub fn delete(&self, pos: usize, len: usize) -> LoroResult<()> {
2719        match &self.inner {
2720            MaybeDetached::Detached(l) => {
2721                let mut list = l.lock().unwrap();
2722                list.value.drain(pos..pos + len);
2723                Ok(())
2724            }
2725            MaybeDetached::Attached(a) => a.with_txn(|txn| self.delete_with_txn(txn, pos, len)),
2726        }
2727    }
2728
2729    pub fn delete_with_txn(&self, txn: &mut Transaction, pos: usize, len: usize) -> LoroResult<()> {
2730        if len == 0 {
2731            return Ok(());
2732        }
2733
2734        if pos + len > self.len() {
2735            return Err(LoroError::OutOfBound {
2736                pos: pos + len,
2737                info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2738                len: self.len(),
2739            });
2740        }
2741
2742        let inner = self.inner.try_attached_state()?;
2743        let ids: Vec<_> = inner.with_state(|state| {
2744            let list = state.as_list_state().unwrap();
2745            (pos..pos + len)
2746                .map(|i| list.get_id_at(i).unwrap())
2747                .collect()
2748        });
2749
2750        for id in ids.into_iter() {
2751            txn.apply_local_op(
2752                inner.container_idx,
2753                crate::op::RawOpContent::List(ListOp::Delete(DeleteSpanWithId::new(
2754                    id.id(),
2755                    pos as isize,
2756                    1,
2757                ))),
2758                EventHint::DeleteList(DeleteSpan::new(pos as isize, 1)),
2759                &inner.doc,
2760            )?;
2761        }
2762
2763        Ok(())
2764    }
2765
2766    pub fn get_child_handler(&self, index: usize) -> LoroResult<Handler> {
2767        match &self.inner {
2768            MaybeDetached::Detached(l) => {
2769                let list = l.lock().unwrap();
2770                let value = list.value.get(index).ok_or(LoroError::OutOfBound {
2771                    pos: index,
2772                    info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2773                    len: list.value.len(),
2774                })?;
2775                match value {
2776                    ValueOrHandler::Handler(h) => Ok(h.clone()),
2777                    _ => Err(LoroError::ArgErr(
2778                        format!(
2779                            "Expected container at index {}, but found {:?}",
2780                            index, value
2781                        )
2782                        .into_boxed_str(),
2783                    )),
2784                }
2785            }
2786            MaybeDetached::Attached(a) => {
2787                let Some(value) = a.with_state(|state| {
2788                    state.as_list_state().as_ref().unwrap().get(index).cloned()
2789                }) else {
2790                    return Err(LoroError::OutOfBound {
2791                        pos: index,
2792                        info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
2793                        len: a.with_state(|state| state.as_list_state().unwrap().len()),
2794                    });
2795                };
2796                match value {
2797                    LoroValue::Container(id) => Ok(create_handler(a, id)),
2798                    _ => Err(LoroError::ArgErr(
2799                        format!(
2800                            "Expected container at index {}, but found {:?}",
2801                            index, value
2802                        )
2803                        .into_boxed_str(),
2804                    )),
2805                }
2806            }
2807        }
2808    }
2809
2810    pub fn len(&self) -> usize {
2811        match &self.inner {
2812            MaybeDetached::Detached(l) => l.lock().unwrap().value.len(),
2813            MaybeDetached::Attached(a) => {
2814                a.with_state(|state| state.as_list_state().unwrap().len())
2815            }
2816        }
2817    }
2818
2819    pub fn is_empty(&self) -> bool {
2820        self.len() == 0
2821    }
2822
2823    pub fn get_deep_value_with_id(&self) -> LoroResult<LoroValue> {
2824        let inner = self.inner.try_attached_state()?;
2825        Ok(inner.with_doc_state(|state| {
2826            state.get_container_deep_value_with_id(inner.container_idx, None)
2827        }))
2828    }
2829
2830    pub fn get(&self, index: usize) -> Option<LoroValue> {
2831        match &self.inner {
2832            MaybeDetached::Detached(l) => l.lock().unwrap().value.get(index).map(|x| x.to_value()),
2833            MaybeDetached::Attached(a) => a.with_state(|state| {
2834                let a = state.as_list_state().unwrap();
2835                a.get(index).cloned()
2836            }),
2837        }
2838    }
2839
2840    /// Get value at given index, if it's a container, return a handler to the container
2841    pub fn get_(&self, index: usize) -> Option<ValueOrHandler> {
2842        match &self.inner {
2843            MaybeDetached::Detached(l) => {
2844                let l = l.lock().unwrap();
2845                l.value.get(index).cloned()
2846            }
2847            MaybeDetached::Attached(inner) => {
2848                let value =
2849                    inner.with_state(|state| state.as_list_state().unwrap().get(index).cloned());
2850                match value {
2851                    Some(LoroValue::Container(container_id)) => Some(ValueOrHandler::Handler(
2852                        create_handler(inner, container_id.clone()),
2853                    )),
2854                    Some(value) => Some(ValueOrHandler::Value(value.clone())),
2855                    None => None,
2856                }
2857            }
2858        }
2859    }
2860
2861    pub fn for_each<I>(&self, mut f: I)
2862    where
2863        I: FnMut(ValueOrHandler),
2864    {
2865        match &self.inner {
2866            MaybeDetached::Detached(l) => {
2867                let l = l.lock().unwrap();
2868                for v in l.value.iter() {
2869                    f(v.clone())
2870                }
2871            }
2872            MaybeDetached::Attached(inner) => {
2873                let mut temp = vec![];
2874                inner.with_state(|state| {
2875                    let a = state.as_list_state().unwrap();
2876                    for v in a.iter() {
2877                        match v {
2878                            LoroValue::Container(c) => {
2879                                temp.push(ValueOrHandler::Handler(create_handler(
2880                                    inner,
2881                                    c.clone(),
2882                                )));
2883                            }
2884                            value => {
2885                                temp.push(ValueOrHandler::Value(value.clone()));
2886                            }
2887                        }
2888                    }
2889                });
2890                for v in temp.into_iter() {
2891                    f(v);
2892                }
2893            }
2894        }
2895    }
2896
2897    pub fn get_cursor(&self, pos: usize, side: Side) -> Option<Cursor> {
2898        match &self.inner {
2899            MaybeDetached::Detached(_) => None,
2900            MaybeDetached::Attached(a) => {
2901                let (id, len) = a.with_state(|s| {
2902                    let l = s.as_list_state().unwrap();
2903                    (l.get_id_at(pos), l.len())
2904                });
2905
2906                if len == 0 {
2907                    return Some(Cursor {
2908                        id: None,
2909                        container: self.id(),
2910                        side: if side == Side::Middle {
2911                            Side::Left
2912                        } else {
2913                            side
2914                        },
2915                        origin_pos: 0,
2916                    });
2917                }
2918
2919                if len <= pos {
2920                    return Some(Cursor {
2921                        id: None,
2922                        container: self.id(),
2923                        side: Side::Right,
2924                        origin_pos: len,
2925                    });
2926                }
2927
2928                let id = id?;
2929                Some(Cursor {
2930                    id: Some(id.id()),
2931                    container: self.id(),
2932                    side,
2933                    origin_pos: pos,
2934                })
2935            }
2936        }
2937    }
2938
2939    fn apply_delta(
2940        &self,
2941        delta: loro_delta::DeltaRope<
2942            loro_delta::array_vec::ArrayVec<ValueOrHandler, 8>,
2943            crate::event::ListDeltaMeta,
2944        >,
2945        on_container_remap: &mut dyn FnMut(ContainerID, ContainerID),
2946    ) -> LoroResult<()> {
2947        match &self.inner {
2948            MaybeDetached::Detached(_) => unimplemented!(),
2949            MaybeDetached::Attached(_) => {
2950                let mut index = 0;
2951                for item in delta.iter() {
2952                    match item {
2953                        loro_delta::DeltaItem::Retain { len, .. } => {
2954                            index += len;
2955                        }
2956                        loro_delta::DeltaItem::Replace { value, delete, .. } => {
2957                            if *delete > 0 {
2958                                self.delete(index, *delete)?;
2959                            }
2960
2961                            for v in value.iter() {
2962                                match v {
2963                                    ValueOrHandler::Value(LoroValue::Container(old_id)) => {
2964                                        let new_h = self.insert_container(
2965                                            index,
2966                                            Handler::new_unattached(old_id.container_type()),
2967                                        )?;
2968                                        let new_id = new_h.id();
2969                                        on_container_remap(old_id.clone(), new_id);
2970                                    }
2971                                    ValueOrHandler::Handler(h) => {
2972                                        let old_id = h.id();
2973                                        let new_h = self.insert_container(
2974                                            index,
2975                                            Handler::new_unattached(old_id.container_type()),
2976                                        )?;
2977                                        let new_id = new_h.id();
2978                                        on_container_remap(old_id, new_id);
2979                                    }
2980                                    ValueOrHandler::Value(v) => {
2981                                        self.insert(index, v.clone())?;
2982                                    }
2983                                }
2984
2985                                index += 1;
2986                            }
2987                        }
2988                    }
2989                }
2990            }
2991        }
2992
2993        Ok(())
2994    }
2995
2996    pub fn is_deleted(&self) -> bool {
2997        match &self.inner {
2998            MaybeDetached::Detached(_) => false,
2999            MaybeDetached::Attached(a) => a.is_deleted(),
3000        }
3001    }
3002
3003    pub fn clear(&self) -> LoroResult<()> {
3004        match &self.inner {
3005            MaybeDetached::Detached(l) => {
3006                let mut l = l.lock().unwrap();
3007                l.value.clear();
3008                Ok(())
3009            }
3010            MaybeDetached::Attached(a) => a.with_txn(|txn| self.clear_with_txn(txn)),
3011        }
3012    }
3013
3014    pub fn clear_with_txn(&self, txn: &mut Transaction) -> LoroResult<()> {
3015        self.delete_with_txn(txn, 0, self.len())
3016    }
3017
3018    pub fn get_id_at(&self, pos: usize) -> Option<ID> {
3019        match &self.inner {
3020            MaybeDetached::Detached(_) => None,
3021            MaybeDetached::Attached(a) => a.with_state(|state| {
3022                state
3023                    .as_list_state()
3024                    .unwrap()
3025                    .get_id_at(pos)
3026                    .map(|x| x.id())
3027            }),
3028        }
3029    }
3030}
3031
3032impl MovableListHandler {
3033    pub fn insert(&self, pos: usize, v: impl Into<LoroValue>) -> LoroResult<()> {
3034        match &self.inner {
3035            MaybeDetached::Detached(d) => {
3036                let mut d = d.lock().unwrap();
3037                if pos > d.value.len() {
3038                    return Err(LoroError::OutOfBound {
3039                        pos,
3040                        info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
3041                        len: d.value.len(),
3042                    });
3043                }
3044                d.value.insert(pos, ValueOrHandler::Value(v.into()));
3045                Ok(())
3046            }
3047            MaybeDetached::Attached(a) => {
3048                a.with_txn(|txn| self.insert_with_txn(txn, pos, v.into()))
3049            }
3050        }
3051    }
3052
3053    #[instrument(skip_all)]
3054    pub fn insert_with_txn(
3055        &self,
3056        txn: &mut Transaction,
3057        pos: usize,
3058        v: LoroValue,
3059    ) -> LoroResult<()> {
3060        if pos > self.len() {
3061            return Err(LoroError::OutOfBound {
3062                pos,
3063                info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
3064                len: self.len(),
3065            });
3066        }
3067
3068        if v.is_container() {
3069            return Err(LoroError::ArgErr(
3070                INSERT_CONTAINER_VALUE_ARG_ERROR
3071                    .to_string()
3072                    .into_boxed_str(),
3073            ));
3074        }
3075
3076        let op_index = self.with_state(|state| {
3077            let list = state.as_movable_list_state().unwrap();
3078            Ok(list
3079                .convert_index(pos, IndexType::ForUser, IndexType::ForOp)
3080                .unwrap())
3081        })?;
3082
3083        let inner = self.inner.try_attached_state()?;
3084        txn.apply_local_op(
3085            inner.container_idx,
3086            crate::op::RawOpContent::List(crate::container::list::list_op::ListOp::Insert {
3087                slice: ListSlice::RawData(Cow::Owned(vec![v.clone()])),
3088                pos: op_index,
3089            }),
3090            EventHint::InsertList { len: 1, pos },
3091            &inner.doc,
3092        )
3093    }
3094
3095    #[inline]
3096    pub fn mov(&self, from: usize, to: usize) -> LoroResult<()> {
3097        match &self.inner {
3098            MaybeDetached::Detached(d) => {
3099                let mut d = d.lock().unwrap();
3100                if from >= d.value.len() {
3101                    return Err(LoroError::OutOfBound {
3102                        pos: from,
3103                        info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
3104                        len: d.value.len(),
3105                    });
3106                }
3107                if to >= d.value.len() {
3108                    return Err(LoroError::OutOfBound {
3109                        pos: to,
3110                        info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
3111                        len: d.value.len(),
3112                    });
3113                }
3114                let v = d.value.remove(from);
3115                d.value.insert(to, v);
3116                Ok(())
3117            }
3118            MaybeDetached::Attached(a) => a.with_txn(|txn| self.move_with_txn(txn, from, to)),
3119        }
3120    }
3121
3122    /// Move element from `from` to `to`. After this op, elem will be at pos `to`.
3123    #[instrument(skip_all)]
3124    pub fn move_with_txn(&self, txn: &mut Transaction, from: usize, to: usize) -> LoroResult<()> {
3125        if from == to {
3126            return Ok(());
3127        }
3128
3129        if from >= self.len() {
3130            return Err(LoroError::OutOfBound {
3131                pos: from,
3132                info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
3133                len: self.len(),
3134            });
3135        }
3136
3137        if to >= self.len() {
3138            return Err(LoroError::OutOfBound {
3139                pos: to,
3140                info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
3141                len: self.len(),
3142            });
3143        }
3144
3145        let (op_from, op_to, elem_id, value) = self.with_state(|state| {
3146            let list = state.as_movable_list_state().unwrap();
3147            let (elem_id, elem) = list
3148                .get_elem_at_given_pos(from, IndexType::ForUser)
3149                .unwrap();
3150            Ok((
3151                list.convert_index(from, IndexType::ForUser, IndexType::ForOp)
3152                    .unwrap(),
3153                list.convert_index(to, IndexType::ForUser, IndexType::ForOp)
3154                    .unwrap(),
3155                elem_id,
3156                elem.value().clone(),
3157            ))
3158        })?;
3159
3160        let inner = self.inner.try_attached_state()?;
3161        txn.apply_local_op(
3162            inner.container_idx,
3163            crate::op::RawOpContent::List(crate::container::list::list_op::ListOp::Move {
3164                from: op_from as u32,
3165                to: op_to as u32,
3166                elem_id: elem_id.to_id(),
3167            }),
3168            EventHint::Move {
3169                value,
3170                from: from as u32,
3171                to: to as u32,
3172            },
3173            &inner.doc,
3174        )
3175    }
3176
3177    pub fn push(&self, v: LoroValue) -> LoroResult<()> {
3178        match &self.inner {
3179            MaybeDetached::Detached(d) => {
3180                let mut d = d.lock().unwrap();
3181                d.value.push(v.into());
3182                Ok(())
3183            }
3184            MaybeDetached::Attached(a) => a.with_txn(|txn| self.push_with_txn(txn, v)),
3185        }
3186    }
3187
3188    pub fn push_with_txn(&self, txn: &mut Transaction, v: LoroValue) -> LoroResult<()> {
3189        let pos = self.len();
3190        self.insert_with_txn(txn, pos, v)
3191    }
3192
3193    pub fn pop_(&self) -> LoroResult<Option<ValueOrHandler>> {
3194        match &self.inner {
3195            MaybeDetached::Detached(d) => {
3196                let mut d = d.lock().unwrap();
3197                Ok(d.value.pop())
3198            }
3199            MaybeDetached::Attached(a) => {
3200                let last = self.len() - 1;
3201                let ans = self.get_(last);
3202                a.with_txn(|txn| self.pop_with_txn(txn))?;
3203                Ok(ans)
3204            }
3205        }
3206    }
3207
3208    pub fn pop(&self) -> LoroResult<Option<LoroValue>> {
3209        match &self.inner {
3210            MaybeDetached::Detached(a) => {
3211                let mut a = a.lock().unwrap();
3212                Ok(a.value.pop().map(|x| x.to_value()))
3213            }
3214            MaybeDetached::Attached(a) => a.with_txn(|txn| self.pop_with_txn(txn)),
3215        }
3216    }
3217
3218    pub fn pop_with_txn(&self, txn: &mut Transaction) -> LoroResult<Option<LoroValue>> {
3219        let len = self.len();
3220        if len == 0 {
3221            return Ok(None);
3222        }
3223
3224        let v = self.get(len - 1);
3225        self.delete_with_txn(txn, len - 1, 1)?;
3226        Ok(v)
3227    }
3228
3229    pub fn insert_container<H: HandlerTrait>(&self, pos: usize, child: H) -> LoroResult<H> {
3230        match &self.inner {
3231            MaybeDetached::Detached(d) => {
3232                let mut d = d.lock().unwrap();
3233                if pos > d.value.len() {
3234                    return Err(LoroError::OutOfBound {
3235                        pos,
3236                        info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
3237                        len: d.value.len(),
3238                    });
3239                }
3240                d.value
3241                    .insert(pos, ValueOrHandler::Handler(child.to_handler()));
3242                Ok(child)
3243            }
3244            MaybeDetached::Attached(a) => {
3245                a.with_txn(|txn| self.insert_container_with_txn(txn, pos, child))
3246            }
3247        }
3248    }
3249
3250    pub fn push_container<H: HandlerTrait>(&self, child: H) -> LoroResult<H> {
3251        self.insert_container(self.len(), child)
3252    }
3253
3254    pub fn insert_container_with_txn<H: HandlerTrait>(
3255        &self,
3256        txn: &mut Transaction,
3257        pos: usize,
3258        child: H,
3259    ) -> LoroResult<H> {
3260        if pos > self.len() {
3261            return Err(LoroError::OutOfBound {
3262                pos,
3263                info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
3264                len: self.len(),
3265            });
3266        }
3267
3268        let op_index = self.with_state(|state| {
3269            let list = state.as_movable_list_state().unwrap();
3270            Ok(list
3271                .convert_index(pos, IndexType::ForUser, IndexType::ForOp)
3272                .unwrap())
3273        })?;
3274
3275        let id = txn.next_id();
3276        let container_id = ContainerID::new_normal(id, child.kind());
3277        let v = LoroValue::Container(container_id.clone());
3278        let inner = self.inner.try_attached_state()?;
3279        txn.apply_local_op(
3280            inner.container_idx,
3281            crate::op::RawOpContent::List(crate::container::list::list_op::ListOp::Insert {
3282                slice: ListSlice::RawData(Cow::Owned(vec![v.clone()])),
3283                pos: op_index,
3284            }),
3285            EventHint::InsertList { len: 1, pos },
3286            &inner.doc,
3287        )?;
3288        child.attach(txn, inner, container_id)
3289    }
3290
3291    pub fn set(&self, index: usize, value: impl Into<LoroValue>) -> LoroResult<()> {
3292        match &self.inner {
3293            MaybeDetached::Detached(d) => {
3294                let mut d = d.lock().unwrap();
3295                if index >= d.value.len() {
3296                    return Err(LoroError::OutOfBound {
3297                        pos: index,
3298                        info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
3299                        len: d.value.len(),
3300                    });
3301                }
3302                d.value[index] = ValueOrHandler::Value(value.into());
3303                Ok(())
3304            }
3305            MaybeDetached::Attached(a) => {
3306                a.with_txn(|txn| self.set_with_txn(txn, index, value.into()))
3307            }
3308        }
3309    }
3310
3311    pub fn set_with_txn(
3312        &self,
3313        txn: &mut Transaction,
3314        index: usize,
3315        value: LoroValue,
3316    ) -> LoroResult<()> {
3317        if index >= self.len() {
3318            return Err(LoroError::OutOfBound {
3319                pos: index,
3320                info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
3321                len: self.len(),
3322            });
3323        }
3324
3325        let inner = self.inner.try_attached_state()?;
3326        let Some(elem_id) = self.with_state(|state| {
3327            let list = state.as_movable_list_state().unwrap();
3328            Ok(list.get_elem_id_at(index, IndexType::ForUser))
3329        })?
3330        else {
3331            unreachable!()
3332        };
3333
3334        let op = crate::op::RawOpContent::List(crate::container::list::list_op::ListOp::Set {
3335            elem_id: elem_id.to_id(),
3336            value: value.clone(),
3337        });
3338
3339        let hint = EventHint::SetList { index, value };
3340        txn.apply_local_op(inner.container_idx, op, hint, &inner.doc)
3341    }
3342
3343    pub fn set_container<H: HandlerTrait>(&self, pos: usize, child: H) -> LoroResult<H> {
3344        match &self.inner {
3345            MaybeDetached::Detached(d) => {
3346                let mut d = d.lock().unwrap();
3347                d.value[pos] = ValueOrHandler::Handler(child.to_handler());
3348                Ok(child)
3349            }
3350            MaybeDetached::Attached(a) => {
3351                a.with_txn(|txn| self.set_container_with_txn(txn, pos, child))
3352            }
3353        }
3354    }
3355
3356    pub fn set_container_with_txn<H: HandlerTrait>(
3357        &self,
3358        txn: &mut Transaction,
3359        pos: usize,
3360        child: H,
3361    ) -> LoroResult<H> {
3362        let id = txn.next_id();
3363        let container_id = ContainerID::new_normal(id, child.kind());
3364        let v = LoroValue::Container(container_id.clone());
3365        let Some(elem_id) = self.with_state(|state| {
3366            let list = state.as_movable_list_state().unwrap();
3367            Ok(list.get_elem_id_at(pos, IndexType::ForUser))
3368        })?
3369        else {
3370            let len = self.len();
3371            if pos >= len {
3372                return Err(LoroError::OutOfBound {
3373                    pos,
3374                    len,
3375                    info: "".into(),
3376                });
3377            } else {
3378                unreachable!()
3379            }
3380        };
3381        let inner = self.inner.try_attached_state()?;
3382        txn.apply_local_op(
3383            inner.container_idx,
3384            crate::op::RawOpContent::List(crate::container::list::list_op::ListOp::Set {
3385                elem_id: elem_id.to_id(),
3386                value: v.clone(),
3387            }),
3388            EventHint::SetList {
3389                index: pos,
3390                value: v,
3391            },
3392            &inner.doc,
3393        )?;
3394
3395        child.attach(txn, inner, container_id)
3396    }
3397
3398    pub fn delete(&self, pos: usize, len: usize) -> LoroResult<()> {
3399        match &self.inner {
3400            MaybeDetached::Detached(d) => {
3401                let mut d = d.lock().unwrap();
3402                d.value.drain(pos..pos + len);
3403                Ok(())
3404            }
3405            MaybeDetached::Attached(a) => a.with_txn(|txn| self.delete_with_txn(txn, pos, len)),
3406        }
3407    }
3408
3409    #[instrument(skip_all)]
3410    pub fn delete_with_txn(&self, txn: &mut Transaction, pos: usize, len: usize) -> LoroResult<()> {
3411        if len == 0 {
3412            return Ok(());
3413        }
3414
3415        if pos + len > self.len() {
3416            return Err(LoroError::OutOfBound {
3417                pos: pos + len,
3418                info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
3419                len: self.len(),
3420            });
3421        }
3422
3423        let (ids, new_poses) = self.with_state(|state| {
3424            let list = state.as_movable_list_state().unwrap();
3425            let ids: Vec<_> = (pos..pos + len)
3426                .map(|i| list.get_list_id_at(i, IndexType::ForUser).unwrap())
3427                .collect();
3428            let poses: Vec<_> = (pos..pos + len)
3429                // need to -i because we delete the previous ones
3430                .map(|user_index| {
3431                    let op_index = list
3432                        .convert_index(user_index, IndexType::ForUser, IndexType::ForOp)
3433                        .unwrap();
3434                    assert!(op_index >= user_index);
3435                    op_index - (user_index - pos)
3436                })
3437                .collect();
3438            Ok((ids, poses))
3439        })?;
3440
3441        loro_common::info!(?pos, ?len, ?ids, ?new_poses, "delete_with_txn");
3442        let user_pos = pos;
3443        let inner = self.inner.try_attached_state()?;
3444        for (id, op_pos) in ids.into_iter().zip(new_poses.into_iter()) {
3445            txn.apply_local_op(
3446                inner.container_idx,
3447                crate::op::RawOpContent::List(ListOp::Delete(DeleteSpanWithId::new(
3448                    id,
3449                    op_pos as isize,
3450                    1,
3451                ))),
3452                EventHint::DeleteList(DeleteSpan::new(user_pos as isize, 1)),
3453                &inner.doc,
3454            )?;
3455        }
3456
3457        Ok(())
3458    }
3459
3460    pub fn get_child_handler(&self, index: usize) -> LoroResult<Handler> {
3461        match &self.inner {
3462            MaybeDetached::Detached(l) => {
3463                let list = l.lock().unwrap();
3464                let value = list.value.get(index).ok_or(LoroError::OutOfBound {
3465                    pos: index,
3466                    info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
3467                    len: list.value.len(),
3468                })?;
3469                match value {
3470                    ValueOrHandler::Handler(h) => Ok(h.clone()),
3471                    _ => Err(LoroError::ArgErr(
3472                        format!(
3473                            "Expected container at index {}, but found {:?}",
3474                            index, value
3475                        )
3476                        .into_boxed_str(),
3477                    )),
3478                }
3479            }
3480            MaybeDetached::Attached(a) => {
3481                let Some(value) = a.with_state(|state| {
3482                    state
3483                        .as_movable_list_state()
3484                        .as_ref()
3485                        .unwrap()
3486                        .get(index, IndexType::ForUser)
3487                        .cloned()
3488                }) else {
3489                    return Err(LoroError::OutOfBound {
3490                        pos: index,
3491                        info: format!("Position: {}:{}", file!(), line!()).into_boxed_str(),
3492                        len: a.with_state(|state| state.as_list_state().unwrap().len()),
3493                    });
3494                };
3495                match value {
3496                    LoroValue::Container(id) => Ok(create_handler(a, id)),
3497                    _ => Err(LoroError::ArgErr(
3498                        format!(
3499                            "Expected container at index {}, but found {:?}",
3500                            index, value
3501                        )
3502                        .into_boxed_str(),
3503                    )),
3504                }
3505            }
3506        }
3507    }
3508
3509    pub fn len(&self) -> usize {
3510        match &self.inner {
3511            MaybeDetached::Detached(d) => {
3512                let d = d.lock().unwrap();
3513                d.value.len()
3514            }
3515            MaybeDetached::Attached(a) => {
3516                a.with_state(|state| state.as_movable_list_state().unwrap().len())
3517            }
3518        }
3519    }
3520
3521    pub fn is_empty(&self) -> bool {
3522        self.len() == 0
3523    }
3524
3525    pub fn get_deep_value_with_id(&self) -> LoroValue {
3526        let inner = self.inner.try_attached_state().unwrap();
3527        inner
3528            .doc
3529            .state
3530            .lock()
3531            .unwrap()
3532            .get_container_deep_value_with_id(inner.container_idx, None)
3533    }
3534
3535    pub fn get(&self, index: usize) -> Option<LoroValue> {
3536        match &self.inner {
3537            MaybeDetached::Detached(d) => {
3538                let d = d.lock().unwrap();
3539                d.value.get(index).map(|v| v.to_value())
3540            }
3541            MaybeDetached::Attached(a) => a.with_state(|state| {
3542                let a = state.as_movable_list_state().unwrap();
3543                a.get(index, IndexType::ForUser).cloned()
3544            }),
3545        }
3546    }
3547
3548    /// Get value at given index, if it's a container, return a handler to the container
3549    pub fn get_(&self, index: usize) -> Option<ValueOrHandler> {
3550        match &self.inner {
3551            MaybeDetached::Detached(d) => {
3552                let d = d.lock().unwrap();
3553                d.value.get(index).cloned()
3554            }
3555            MaybeDetached::Attached(m) => m.with_state(|state| {
3556                let a = state.as_movable_list_state().unwrap();
3557                match a.get(index, IndexType::ForUser) {
3558                    Some(v) => {
3559                        if let LoroValue::Container(c) = v {
3560                            Some(ValueOrHandler::Handler(create_handler(m, c.clone())))
3561                        } else {
3562                            Some(ValueOrHandler::Value(v.clone()))
3563                        }
3564                    }
3565                    None => None,
3566                }
3567            }),
3568        }
3569    }
3570
3571    pub fn for_each<I>(&self, mut f: I)
3572    where
3573        I: FnMut(ValueOrHandler),
3574    {
3575        match &self.inner {
3576            MaybeDetached::Detached(d) => {
3577                let d = d.lock().unwrap();
3578                for v in d.value.iter() {
3579                    f(v.clone());
3580                }
3581            }
3582            MaybeDetached::Attached(m) => {
3583                let mut temp = vec![];
3584                m.with_state(|state| {
3585                    let a = state.as_movable_list_state().unwrap();
3586                    for v in a.iter() {
3587                        match v {
3588                            LoroValue::Container(c) => {
3589                                temp.push(ValueOrHandler::Handler(create_handler(m, c.clone())));
3590                            }
3591                            value => {
3592                                temp.push(ValueOrHandler::Value(value.clone()));
3593                            }
3594                        }
3595                    }
3596                });
3597
3598                for v in temp.into_iter() {
3599                    f(v);
3600                }
3601            }
3602        }
3603    }
3604
3605    pub fn log_internal_state(&self) -> String {
3606        match &self.inner {
3607            MaybeDetached::Detached(d) => {
3608                let d = d.lock().unwrap();
3609                format!("{:#?}", &d.value)
3610            }
3611            MaybeDetached::Attached(a) => a.with_state(|state| {
3612                let a = state.as_movable_list_state().unwrap();
3613                format!("{a:#?}")
3614            }),
3615        }
3616    }
3617
3618    pub fn new_detached() -> MovableListHandler {
3619        MovableListHandler {
3620            inner: MaybeDetached::new_detached(Default::default()),
3621        }
3622    }
3623
3624    pub fn get_cursor(&self, pos: usize, side: Side) -> Option<Cursor> {
3625        match &self.inner {
3626            MaybeDetached::Detached(_) => None,
3627            MaybeDetached::Attached(inner) => {
3628                let (id, len) = inner.with_state(|s| {
3629                    let l = s.as_movable_list_state().unwrap();
3630                    (l.get_list_item_id_at(pos), l.len())
3631                });
3632
3633                if len == 0 {
3634                    return Some(Cursor {
3635                        id: None,
3636                        container: self.id(),
3637                        side: if side == Side::Middle {
3638                            Side::Left
3639                        } else {
3640                            side
3641                        },
3642                        origin_pos: 0,
3643                    });
3644                }
3645
3646                if len <= pos {
3647                    return Some(Cursor {
3648                        id: None,
3649                        container: self.id(),
3650                        side: Side::Right,
3651                        origin_pos: len,
3652                    });
3653                }
3654
3655                let id = id?;
3656                Some(Cursor {
3657                    id: Some(id.id()),
3658                    container: self.id(),
3659                    side,
3660                    origin_pos: pos,
3661                })
3662            }
3663        }
3664    }
3665
3666    pub(crate) fn op_pos_to_user_pos(&self, new_pos: usize) -> usize {
3667        match &self.inner {
3668            MaybeDetached::Detached(_) => new_pos,
3669            MaybeDetached::Attached(inner) => {
3670                let mut pos = new_pos;
3671                inner.with_state(|s| {
3672                    let l = s.as_movable_list_state().unwrap();
3673                    pos = l
3674                        .convert_index(new_pos, IndexType::ForOp, IndexType::ForUser)
3675                        .unwrap_or(l.len());
3676                });
3677                pos
3678            }
3679        }
3680    }
3681
3682    pub fn is_deleted(&self) -> bool {
3683        match &self.inner {
3684            MaybeDetached::Detached(_) => false,
3685            MaybeDetached::Attached(a) => a.is_deleted(),
3686        }
3687    }
3688
3689    pub fn clear(&self) -> LoroResult<()> {
3690        match &self.inner {
3691            MaybeDetached::Detached(d) => {
3692                let mut d = d.lock().unwrap();
3693                d.value.clear();
3694                Ok(())
3695            }
3696            MaybeDetached::Attached(a) => a.with_txn(|txn| self.clear_with_txn(txn)),
3697        }
3698    }
3699
3700    pub fn clear_with_txn(&self, txn: &mut Transaction) -> LoroResult<()> {
3701        self.delete_with_txn(txn, 0, self.len())
3702    }
3703
3704    pub fn get_creator_at(&self, pos: usize) -> Option<PeerID> {
3705        match &self.inner {
3706            MaybeDetached::Detached(_) => None,
3707            MaybeDetached::Attached(a) => {
3708                a.with_state(|state| state.as_movable_list_state().unwrap().get_creator_at(pos))
3709            }
3710        }
3711    }
3712
3713    pub fn get_last_mover_at(&self, pos: usize) -> Option<PeerID> {
3714        match &self.inner {
3715            MaybeDetached::Detached(_) => None,
3716            MaybeDetached::Attached(a) => a.with_state(|state| {
3717                state
3718                    .as_movable_list_state()
3719                    .unwrap()
3720                    .get_last_mover_at(pos)
3721            }),
3722        }
3723    }
3724
3725    pub fn get_last_editor_at(&self, pos: usize) -> Option<PeerID> {
3726        match &self.inner {
3727            MaybeDetached::Detached(_) => None,
3728            MaybeDetached::Attached(a) => a.with_state(|state| {
3729                state
3730                    .as_movable_list_state()
3731                    .unwrap()
3732                    .get_last_editor_at(pos)
3733            }),
3734        }
3735    }
3736}
3737
3738impl MapHandler {
3739    /// Create a new container that is detached from the document.
3740    /// The edits on a detached container will not be persisted.
3741    /// To attach the container to the document, please insert it into an attached container.
3742    pub fn new_detached() -> Self {
3743        Self {
3744            inner: MaybeDetached::new_detached(Default::default()),
3745        }
3746    }
3747
3748    pub fn insert(&self, key: &str, value: impl Into<LoroValue>) -> LoroResult<()> {
3749        match &self.inner {
3750            MaybeDetached::Detached(m) => {
3751                let mut m = m.lock().unwrap();
3752                m.value
3753                    .insert(key.into(), ValueOrHandler::Value(value.into()));
3754                Ok(())
3755            }
3756            MaybeDetached::Attached(a) => {
3757                a.with_txn(|txn| self.insert_with_txn(txn, key, value.into()))
3758            }
3759        }
3760    }
3761
3762    /// This method will insert the value even if the same value is already in the given entry.
3763    fn insert_without_skipping(&self, key: &str, value: impl Into<LoroValue>) -> LoroResult<()> {
3764        match &self.inner {
3765            MaybeDetached::Detached(m) => {
3766                let mut m = m.lock().unwrap();
3767                m.value
3768                    .insert(key.into(), ValueOrHandler::Value(value.into()));
3769                Ok(())
3770            }
3771            MaybeDetached::Attached(a) => a.with_txn(|txn| {
3772                let this = &self;
3773                let value = value.into();
3774                if let Some(_value) = value.as_container() {
3775                    return Err(LoroError::ArgErr(
3776                        INSERT_CONTAINER_VALUE_ARG_ERROR
3777                            .to_string()
3778                            .into_boxed_str(),
3779                    ));
3780                }
3781
3782                let inner = this.inner.try_attached_state()?;
3783                txn.apply_local_op(
3784                    inner.container_idx,
3785                    crate::op::RawOpContent::Map(crate::container::map::MapSet {
3786                        key: key.into(),
3787                        value: Some(value.clone()),
3788                    }),
3789                    EventHint::Map {
3790                        key: key.into(),
3791                        value: Some(value.clone()),
3792                    },
3793                    &inner.doc,
3794                )
3795            }),
3796        }
3797    }
3798
3799    pub fn insert_with_txn(
3800        &self,
3801        txn: &mut Transaction,
3802        key: &str,
3803        value: LoroValue,
3804    ) -> LoroResult<()> {
3805        if let Some(_value) = value.as_container() {
3806            return Err(LoroError::ArgErr(
3807                INSERT_CONTAINER_VALUE_ARG_ERROR
3808                    .to_string()
3809                    .into_boxed_str(),
3810            ));
3811        }
3812
3813        if self.get(key).map(|x| x == value).unwrap_or(false) {
3814            // skip if the value is already set
3815            return Ok(());
3816        }
3817
3818        let inner = self.inner.try_attached_state()?;
3819        txn.apply_local_op(
3820            inner.container_idx,
3821            crate::op::RawOpContent::Map(crate::container::map::MapSet {
3822                key: key.into(),
3823                value: Some(value.clone()),
3824            }),
3825            EventHint::Map {
3826                key: key.into(),
3827                value: Some(value.clone()),
3828            },
3829            &inner.doc,
3830        )
3831    }
3832
3833    pub fn insert_container<T: HandlerTrait>(&self, key: &str, handler: T) -> LoroResult<T> {
3834        match &self.inner {
3835            MaybeDetached::Detached(m) => {
3836                let mut m = m.lock().unwrap();
3837                let to_insert = handler.to_handler();
3838                m.value
3839                    .insert(key.into(), ValueOrHandler::Handler(to_insert.clone()));
3840                Ok(handler)
3841            }
3842            MaybeDetached::Attached(a) => {
3843                a.with_txn(|txn| self.insert_container_with_txn(txn, key, handler))
3844            }
3845        }
3846    }
3847
3848    pub fn insert_container_with_txn<H: HandlerTrait>(
3849        &self,
3850        txn: &mut Transaction,
3851        key: &str,
3852        child: H,
3853    ) -> LoroResult<H> {
3854        let inner = self.inner.try_attached_state()?;
3855        let id = txn.next_id();
3856        let container_id = ContainerID::new_normal(id, child.kind());
3857        txn.apply_local_op(
3858            inner.container_idx,
3859            crate::op::RawOpContent::Map(crate::container::map::MapSet {
3860                key: key.into(),
3861                value: Some(LoroValue::Container(container_id.clone())),
3862            }),
3863            EventHint::Map {
3864                key: key.into(),
3865                value: Some(LoroValue::Container(container_id.clone())),
3866            },
3867            &inner.doc,
3868        )?;
3869
3870        child.attach(txn, inner, container_id)
3871    }
3872
3873    pub fn delete(&self, key: &str) -> LoroResult<()> {
3874        match &self.inner {
3875            MaybeDetached::Detached(m) => {
3876                let mut m = m.lock().unwrap();
3877                m.value.remove(key);
3878                Ok(())
3879            }
3880            MaybeDetached::Attached(a) => a.with_txn(|txn| self.delete_with_txn(txn, key)),
3881        }
3882    }
3883
3884    pub fn delete_with_txn(&self, txn: &mut Transaction, key: &str) -> LoroResult<()> {
3885        let inner = self.inner.try_attached_state()?;
3886        txn.apply_local_op(
3887            inner.container_idx,
3888            crate::op::RawOpContent::Map(crate::container::map::MapSet {
3889                key: key.into(),
3890                value: None,
3891            }),
3892            EventHint::Map {
3893                key: key.into(),
3894                value: None,
3895            },
3896            &inner.doc,
3897        )
3898    }
3899
3900    pub fn for_each<I>(&self, mut f: I)
3901    where
3902        I: FnMut(&str, ValueOrHandler),
3903    {
3904        match &self.inner {
3905            MaybeDetached::Detached(m) => {
3906                let m = m.lock().unwrap();
3907                for (k, v) in m.value.iter() {
3908                    f(k, v.clone());
3909                }
3910            }
3911            MaybeDetached::Attached(inner) => {
3912                let mut temp = vec![];
3913                inner.with_state(|state| {
3914                    let a = state.as_map_state().unwrap();
3915                    for (k, v) in a.iter() {
3916                        if let Some(v) = &v.value {
3917                            match v {
3918                                LoroValue::Container(c) => {
3919                                    temp.push((
3920                                        k.to_string(),
3921                                        ValueOrHandler::Handler(create_handler(inner, c.clone())),
3922                                    ));
3923                                }
3924                                value => {
3925                                    temp.push((k.to_string(), ValueOrHandler::Value(value.clone())))
3926                                }
3927                            }
3928                        }
3929                    }
3930                });
3931
3932                for (k, v) in temp.into_iter() {
3933                    f(&k, v.clone());
3934                }
3935            }
3936        }
3937    }
3938
3939    pub fn get_child_handler(&self, key: &str) -> LoroResult<Handler> {
3940        match &self.inner {
3941            MaybeDetached::Detached(m) => {
3942                let m = m.lock().unwrap();
3943                let value = m.value.get(key).unwrap();
3944                match value {
3945                    ValueOrHandler::Value(v) => Err(LoroError::ArgErr(
3946                        format!("Expected Handler but found {:?}", v).into_boxed_str(),
3947                    )),
3948                    ValueOrHandler::Handler(h) => Ok(h.clone()),
3949                }
3950            }
3951            MaybeDetached::Attached(inner) => {
3952                let container_id = inner.with_state(|state| {
3953                    state
3954                        .as_map_state()
3955                        .as_ref()
3956                        .unwrap()
3957                        .get(key)
3958                        .unwrap()
3959                        .as_container()
3960                        .unwrap()
3961                        .clone()
3962                });
3963                Ok(create_handler(inner, container_id))
3964            }
3965        }
3966    }
3967
3968    pub fn get_deep_value_with_id(&self) -> LoroResult<LoroValue> {
3969        match &self.inner {
3970            MaybeDetached::Detached(_) => Err(LoroError::MisuseDetachedContainer {
3971                method: "get_deep_value_with_id",
3972            }),
3973            MaybeDetached::Attached(inner) => Ok(inner.with_doc_state(|state| {
3974                state.get_container_deep_value_with_id(inner.container_idx, None)
3975            })),
3976        }
3977    }
3978
3979    pub fn get(&self, key: &str) -> Option<LoroValue> {
3980        match &self.inner {
3981            MaybeDetached::Detached(m) => {
3982                let m = m.lock().unwrap();
3983                m.value.get(key).map(|v| v.to_value())
3984            }
3985            MaybeDetached::Attached(inner) => {
3986                inner.with_state(|state| state.as_map_state().unwrap().get(key).cloned())
3987            }
3988        }
3989    }
3990
3991    /// Get the value at given key, if value is a container, return a handler to the container
3992    pub fn get_(&self, key: &str) -> Option<ValueOrHandler> {
3993        match &self.inner {
3994            MaybeDetached::Detached(m) => {
3995                let m = m.lock().unwrap();
3996                m.value.get(key).cloned()
3997            }
3998            MaybeDetached::Attached(inner) => {
3999                let value =
4000                    inner.with_state(|state| state.as_map_state().unwrap().get(key).cloned());
4001                match value {
4002                    Some(LoroValue::Container(container_id)) => Some(ValueOrHandler::Handler(
4003                        create_handler(inner, container_id.clone()),
4004                    )),
4005                    Some(value) => Some(ValueOrHandler::Value(value.clone())),
4006                    None => None,
4007                }
4008            }
4009        }
4010    }
4011
4012    pub fn get_or_create_container<C: HandlerTrait>(&self, key: &str, child: C) -> LoroResult<C> {
4013        if let Some(ans) = self.get_(key) {
4014            if let ValueOrHandler::Handler(h) = ans {
4015                let kind = h.kind();
4016                return C::from_handler(h).ok_or_else(move || {
4017                    LoroError::ArgErr(
4018                        format!("Expected value type {} but found {:?}", child.kind(), kind)
4019                            .into_boxed_str(),
4020                    )
4021                });
4022            } else if let ValueOrHandler::Value(LoroValue::Null) = ans {
4023                // do nothing
4024            } else {
4025                return Err(LoroError::ArgErr(
4026                    format!("Expected value type {} but found {:?}", child.kind(), ans)
4027                        .into_boxed_str(),
4028                ));
4029            }
4030        }
4031
4032        self.insert_container(key, child)
4033    }
4034
4035    pub fn contains_key(&self, key: &str) -> bool {
4036        self.get(key).is_some()
4037    }
4038
4039    pub fn len(&self) -> usize {
4040        match &self.inner {
4041            MaybeDetached::Detached(m) => m.lock().unwrap().value.len(),
4042            MaybeDetached::Attached(a) => a.with_state(|state| state.as_map_state().unwrap().len()),
4043        }
4044    }
4045
4046    pub fn is_empty(&self) -> bool {
4047        self.len() == 0
4048    }
4049
4050    pub fn is_deleted(&self) -> bool {
4051        match &self.inner {
4052            MaybeDetached::Detached(_) => false,
4053            MaybeDetached::Attached(a) => a.is_deleted(),
4054        }
4055    }
4056
4057    pub fn clear(&self) -> LoroResult<()> {
4058        match &self.inner {
4059            MaybeDetached::Detached(m) => {
4060                let mut m = m.lock().unwrap();
4061                m.value.clear();
4062                Ok(())
4063            }
4064            MaybeDetached::Attached(a) => a.with_txn(|txn| self.clear_with_txn(txn)),
4065        }
4066    }
4067
4068    pub fn clear_with_txn(&self, txn: &mut Transaction) -> LoroResult<()> {
4069        let keys: Vec<InternalString> = self.inner.try_attached_state()?.with_state(|state| {
4070            state
4071                .as_map_state()
4072                .unwrap()
4073                .iter()
4074                .map(|(k, _)| k.clone())
4075                .collect()
4076        });
4077
4078        for key in keys {
4079            self.delete_with_txn(txn, &key)?;
4080        }
4081
4082        Ok(())
4083    }
4084
4085    pub fn keys(&self) -> impl Iterator<Item = InternalString> + '_ {
4086        let mut keys: Vec<InternalString> = Vec::with_capacity(self.len());
4087        match &self.inner {
4088            MaybeDetached::Detached(m) => {
4089                let m = m.lock().unwrap();
4090                keys = m.value.keys().map(|x| x.as_str().into()).collect();
4091            }
4092            MaybeDetached::Attached(a) => {
4093                a.with_state(|state| {
4094                    for (k, v) in state.as_map_state().unwrap().iter() {
4095                        if v.value.is_some() {
4096                            keys.push(k.clone());
4097                        }
4098                    }
4099                });
4100            }
4101        }
4102
4103        keys.into_iter()
4104    }
4105
4106    pub fn values(&self) -> impl Iterator<Item = ValueOrHandler> + '_ {
4107        let mut values: Vec<ValueOrHandler> = Vec::with_capacity(self.len());
4108        match &self.inner {
4109            MaybeDetached::Detached(m) => {
4110                let m = m.lock().unwrap();
4111                values = m.value.values().cloned().collect();
4112            }
4113            MaybeDetached::Attached(a) => {
4114                a.with_state(|state| {
4115                    for (_, v) in state.as_map_state().unwrap().iter() {
4116                        let value = match &v.value {
4117                            Some(LoroValue::Container(container_id)) => {
4118                                ValueOrHandler::Handler(create_handler(a, container_id.clone()))
4119                            }
4120                            Some(value) => ValueOrHandler::Value(value.clone()),
4121                            None => continue,
4122                        };
4123                        values.push(value);
4124                    }
4125                });
4126            }
4127        }
4128
4129        values.into_iter()
4130    }
4131
4132    pub fn get_last_editor(&self, key: &str) -> Option<PeerID> {
4133        match &self.inner {
4134            MaybeDetached::Detached(_) => None,
4135            MaybeDetached::Attached(a) => a.with_state(|state| {
4136                let m = state.as_map_state().unwrap();
4137                m.get_last_edit_peer(key)
4138            }),
4139        }
4140    }
4141}
4142
4143fn with_txn<R>(doc: &LoroDoc, f: impl FnOnce(&mut Transaction) -> LoroResult<R>) -> LoroResult<R> {
4144    let txn = &doc.txn;
4145    let mut txn = txn.lock().unwrap();
4146    loop {
4147        if let Some(txn) = &mut *txn {
4148            return f(txn);
4149        } else if cfg!(target_arch = "wasm32") || !doc.can_edit() {
4150            return Err(LoroError::AutoCommitNotStarted);
4151        } else {
4152            drop(txn);
4153            #[cfg(loom)]
4154            loom::thread::yield_now();
4155            doc.start_auto_commit();
4156            txn = doc.txn.lock().unwrap();
4157        }
4158    }
4159}
4160
4161#[cfg(feature = "counter")]
4162pub mod counter {
4163
4164    use loro_common::LoroResult;
4165
4166    use crate::{
4167        txn::{EventHint, Transaction},
4168        HandlerTrait,
4169    };
4170
4171    use super::{create_handler, Handler, MaybeDetached};
4172
4173    #[derive(Clone)]
4174    pub struct CounterHandler {
4175        pub(super) inner: MaybeDetached<f64>,
4176    }
4177
4178    impl CounterHandler {
4179        pub fn new_detached() -> Self {
4180            Self {
4181                inner: MaybeDetached::new_detached(0.),
4182            }
4183        }
4184
4185        pub fn increment(&self, n: f64) -> LoroResult<()> {
4186            match &self.inner {
4187                MaybeDetached::Detached(d) => {
4188                    let d = &mut d.lock().unwrap().value;
4189                    *d += n;
4190                    Ok(())
4191                }
4192                MaybeDetached::Attached(a) => a.with_txn(|txn| self.increment_with_txn(txn, n)),
4193            }
4194        }
4195
4196        pub fn decrement(&self, n: f64) -> LoroResult<()> {
4197            match &self.inner {
4198                MaybeDetached::Detached(d) => {
4199                    let d = &mut d.lock().unwrap().value;
4200                    *d -= n;
4201                    Ok(())
4202                }
4203                MaybeDetached::Attached(a) => a.with_txn(|txn| self.increment_with_txn(txn, -n)),
4204            }
4205        }
4206
4207        fn increment_with_txn(&self, txn: &mut Transaction, n: f64) -> LoroResult<()> {
4208            let inner = self.inner.try_attached_state()?;
4209            txn.apply_local_op(
4210                inner.container_idx,
4211                crate::op::RawOpContent::Counter(n),
4212                EventHint::Counter(n),
4213                &inner.doc,
4214            )
4215        }
4216
4217        pub fn is_deleted(&self) -> bool {
4218            match &self.inner {
4219                MaybeDetached::Detached(_) => false,
4220                MaybeDetached::Attached(a) => a.is_deleted(),
4221            }
4222        }
4223
4224        pub fn clear(&self) -> LoroResult<()> {
4225            self.decrement(self.get_value().into_double().unwrap())
4226        }
4227    }
4228
4229    impl std::fmt::Debug for CounterHandler {
4230        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4231            match &self.inner {
4232                MaybeDetached::Detached(_) => write!(f, "CounterHandler Detached"),
4233                MaybeDetached::Attached(a) => write!(f, "CounterHandler {}", a.id),
4234            }
4235        }
4236    }
4237
4238    impl HandlerTrait for CounterHandler {
4239        fn is_attached(&self) -> bool {
4240            matches!(&self.inner, MaybeDetached::Attached(..))
4241        }
4242
4243        fn attached_handler(&self) -> Option<&crate::BasicHandler> {
4244            self.inner.attached_handler()
4245        }
4246
4247        fn get_value(&self) -> loro_common::LoroValue {
4248            match &self.inner {
4249                MaybeDetached::Detached(t) => {
4250                    let t = t.lock().unwrap();
4251                    t.value.into()
4252                }
4253                MaybeDetached::Attached(a) => a.get_value(),
4254            }
4255        }
4256
4257        fn get_deep_value(&self) -> loro_common::LoroValue {
4258            self.get_value()
4259        }
4260
4261        fn kind(&self) -> loro_common::ContainerType {
4262            loro_common::ContainerType::Counter
4263        }
4264
4265        fn to_handler(&self) -> super::Handler {
4266            Handler::Counter(self.clone())
4267        }
4268
4269        fn from_handler(h: super::Handler) -> Option<Self> {
4270            match h {
4271                Handler::Counter(x) => Some(x),
4272                _ => None,
4273            }
4274        }
4275
4276        fn attach(
4277            &self,
4278            txn: &mut crate::txn::Transaction,
4279            parent: &crate::BasicHandler,
4280            self_id: loro_common::ContainerID,
4281        ) -> loro_common::LoroResult<Self> {
4282            match &self.inner {
4283                MaybeDetached::Detached(v) => {
4284                    let mut v = v.lock().unwrap();
4285                    let inner = create_handler(parent, self_id);
4286                    let c = inner.into_counter().unwrap();
4287
4288                    c.increment_with_txn(txn, v.value)?;
4289
4290                    v.attached = c.attached_handler().cloned();
4291                    Ok(c)
4292                }
4293                MaybeDetached::Attached(a) => {
4294                    let new_inner = create_handler(a, self_id);
4295                    let ans = new_inner.into_counter().unwrap();
4296                    let delta = *self.get_value().as_double().unwrap();
4297                    ans.increment_with_txn(txn, delta)?;
4298                    Ok(ans)
4299                }
4300            }
4301        }
4302
4303        fn get_attached(&self) -> Option<Self> {
4304            match &self.inner {
4305                MaybeDetached::Attached(a) => Some(Self {
4306                    inner: MaybeDetached::Attached(a.clone()),
4307                }),
4308                MaybeDetached::Detached(_) => None,
4309            }
4310        }
4311
4312        fn doc(&self) -> Option<crate::LoroDoc> {
4313            match &self.inner {
4314                MaybeDetached::Detached(_) => None,
4315                MaybeDetached::Attached(a) => Some(a.doc()),
4316            }
4317        }
4318    }
4319}
4320
4321#[cfg(test)]
4322mod test {
4323
4324    use super::{HandlerTrait, TextDelta};
4325    use crate::cursor::PosType;
4326    use crate::loro::ExportMode;
4327    use crate::state::TreeParentId;
4328    use crate::version::Frontiers;
4329    use crate::LoroDoc;
4330    use crate::{fx_map, ToJson};
4331    use loro_common::{LoroValue, ID};
4332    use serde_json::json;
4333
4334    #[test]
4335    fn richtext_handler() {
4336        let loro = LoroDoc::new();
4337        loro.set_peer_id(1).unwrap();
4338        let loro2 = LoroDoc::new();
4339        loro2.set_peer_id(2).unwrap();
4340
4341        let mut txn = loro.txn().unwrap();
4342        let text = txn.get_text("hello");
4343        text.insert_with_txn(&mut txn, 0, "hello", PosType::Unicode)
4344            .unwrap();
4345        txn.commit().unwrap();
4346        let exported = loro.export(ExportMode::all_updates()).unwrap();
4347
4348        loro2.import(&exported).unwrap();
4349        let mut txn = loro2.txn().unwrap();
4350        let text = txn.get_text("hello");
4351        assert_eq!(&**text.get_value().as_string().unwrap(), "hello");
4352        text.insert_with_txn(&mut txn, 5, " world", PosType::Unicode)
4353            .unwrap();
4354        assert_eq!(&**text.get_value().as_string().unwrap(), "hello world");
4355        txn.commit().unwrap();
4356
4357        loro.import(&loro2.export(ExportMode::all_updates()).unwrap())
4358            .unwrap();
4359        let txn = loro.txn().unwrap();
4360        let text = txn.get_text("hello");
4361        assert_eq!(&**text.get_value().as_string().unwrap(), "hello world");
4362        txn.commit().unwrap();
4363
4364        // test checkout
4365        loro.checkout(&Frontiers::from_id(ID::new(2, 1))).unwrap();
4366        assert_eq!(&**text.get_value().as_string().unwrap(), "hello w");
4367    }
4368
4369    #[test]
4370    fn richtext_handler_concurrent() {
4371        let loro = LoroDoc::new();
4372        let mut txn = loro.txn().unwrap();
4373        let handler = loro.get_text("richtext");
4374        handler
4375            .insert_with_txn(&mut txn, 0, "hello", PosType::Unicode)
4376            .unwrap();
4377        txn.commit().unwrap();
4378        for i in 0..100 {
4379            let new_loro = LoroDoc::new();
4380            new_loro
4381                .import(&loro.export(ExportMode::all_updates()).unwrap())
4382                .unwrap();
4383            let mut txn = new_loro.txn().unwrap();
4384            let handler = new_loro.get_text("richtext");
4385            handler
4386                .insert_with_txn(&mut txn, i % 5, &i.to_string(), PosType::Unicode)
4387                .unwrap();
4388            txn.commit().unwrap();
4389            loro.import(
4390                &new_loro
4391                    .export(ExportMode::updates(&loro.oplog_vv()))
4392                    .unwrap(),
4393            )
4394            .unwrap();
4395        }
4396    }
4397
4398    #[test]
4399    fn richtext_handler_mark() {
4400        let loro = LoroDoc::new_auto_commit();
4401        let handler = loro.get_text("richtext");
4402        handler.insert(0, "hello world", PosType::Unicode).unwrap();
4403        handler
4404            .mark(0, 5, "bold", true.into(), PosType::Event)
4405            .unwrap();
4406        loro.commit_then_renew();
4407
4408        // assert has bold
4409        let value = handler.get_richtext_value();
4410        assert_eq!(value[0]["insert"], "hello".into());
4411        let meta = value[0]["attributes"].as_map().unwrap();
4412        assert_eq!(meta.len(), 1);
4413        meta.get("bold").unwrap();
4414
4415        let loro2 = LoroDoc::new_auto_commit();
4416        loro2
4417            .import(&loro.export(ExportMode::all_updates()).unwrap())
4418            .unwrap();
4419        let handler2 = loro2.get_text("richtext");
4420        assert_eq!(&**handler2.get_value().as_string().unwrap(), "hello world");
4421
4422        // assert has bold
4423        let value = handler2.get_richtext_value();
4424        assert_eq!(value[0]["insert"], "hello".into());
4425        let meta = value[0]["attributes"].as_map().unwrap();
4426        assert_eq!(meta.len(), 1);
4427        meta.get("bold").unwrap();
4428
4429        // insert after bold should be bold
4430        {
4431            handler2.insert(5, " new", PosType::Unicode).unwrap();
4432            let value = handler2.get_richtext_value();
4433            assert_eq!(
4434                value.to_json_value(),
4435                serde_json::json!([
4436                    {"insert": "hello new", "attributes": {"bold": true}},
4437                    {"insert": " world"}
4438                ])
4439            );
4440        }
4441    }
4442
4443    #[test]
4444    fn richtext_snapshot() {
4445        let loro = LoroDoc::new();
4446        let mut txn = loro.txn().unwrap();
4447        let handler = loro.get_text("richtext");
4448        handler
4449            .insert_with_txn(&mut txn, 0, "hello world", PosType::Unicode)
4450            .unwrap();
4451        handler
4452            .mark_with_txn(&mut txn, 0, 5, "bold", true.into(), PosType::Event, false)
4453            .unwrap();
4454        txn.commit().unwrap();
4455
4456        let loro2 = LoroDoc::new();
4457        loro2
4458            .import(&loro.export(ExportMode::snapshot()).unwrap())
4459            .unwrap();
4460        let handler2 = loro2.get_text("richtext");
4461        assert_eq!(
4462            handler2.get_richtext_value().to_json_value(),
4463            serde_json::json!([
4464                {"insert": "hello", "attributes": {"bold": true}},
4465                {"insert": " world"}
4466            ])
4467        );
4468    }
4469
4470    #[test]
4471    fn tree_meta() {
4472        let loro = LoroDoc::new_auto_commit();
4473        loro.set_peer_id(1).unwrap();
4474        let tree = loro.get_tree("root");
4475        let id = tree.create(TreeParentId::Root).unwrap();
4476        let meta = tree.get_meta(id).unwrap();
4477        meta.insert("a", 123).unwrap();
4478        loro.commit_then_renew();
4479        let meta = tree.get_meta(id).unwrap();
4480        assert_eq!(meta.get("a").unwrap(), 123.into());
4481        assert_eq!(
4482            json!([{"parent":null,"meta":{"a":123},"id":"0@1","index":0,"children":[],"fractional_index":"80"}]),
4483            tree.get_deep_value().to_json_value()
4484        );
4485        let bytes = loro.export(ExportMode::snapshot()).unwrap();
4486        let loro2 = LoroDoc::new();
4487        loro2.import(&bytes).unwrap();
4488    }
4489
4490    #[test]
4491    fn tree_meta_event() {
4492        use std::sync::Arc;
4493        let loro = LoroDoc::new_auto_commit();
4494        let tree = loro.get_tree("root");
4495        let text = loro.get_text("text");
4496
4497        let id = tree.create(TreeParentId::Root).unwrap();
4498        let meta = tree.get_meta(id).unwrap();
4499        meta.insert("a", 1).unwrap();
4500        text.insert(0, "abc", PosType::Unicode).unwrap();
4501        let _id2 = tree.create(TreeParentId::Root).unwrap();
4502        meta.insert("b", 2).unwrap();
4503
4504        let loro2 = LoroDoc::new_auto_commit();
4505        let _g = loro2.subscribe_root(Arc::new(|e| {
4506            println!("{} {:?} ", e.event_meta.by, e.event_meta.diff)
4507        }));
4508        loro2
4509            .import(&loro.export(ExportMode::all_updates()).unwrap())
4510            .unwrap();
4511        assert_eq!(loro.get_deep_value(), loro2.get_deep_value());
4512    }
4513
4514    #[test]
4515    fn richtext_apply_delta() {
4516        let loro = LoroDoc::new_auto_commit();
4517        let text = loro.get_text("text");
4518        text.apply_delta(&[TextDelta::Insert {
4519            insert: "Hello World!".into(),
4520            attributes: None,
4521        }])
4522        .unwrap();
4523        dbg!(text.get_richtext_value());
4524        text.apply_delta(&[
4525            TextDelta::Retain {
4526                retain: 6,
4527                attributes: Some(fx_map!("italic".into() => loro_common::LoroValue::Bool(true))),
4528            },
4529            TextDelta::Insert {
4530                insert: "New ".into(),
4531                attributes: Some(fx_map!("bold".into() => loro_common::LoroValue::Bool(true))),
4532            },
4533        ])
4534        .unwrap();
4535        dbg!(text.get_richtext_value());
4536        loro.commit_then_renew();
4537        assert_eq!(
4538            text.get_richtext_value().to_json_value(),
4539            json!([
4540                {"insert": "Hello ", "attributes": {"italic": true}},
4541                {"insert": "New ", "attributes": {"bold": true}},
4542                {"insert": "World!"}
4543
4544            ])
4545        )
4546    }
4547
4548    #[test]
4549    fn richtext_apply_delta_marks_without_growth() {
4550        let loro = LoroDoc::new_auto_commit();
4551        let text = loro.get_text("text");
4552        text.insert(0, "abc", PosType::Unicode).unwrap();
4553
4554        text.apply_delta(&[TextDelta::Retain {
4555            retain: 3,
4556            attributes: Some(fx_map!("bold".into() => LoroValue::Bool(true))),
4557        }])
4558        .unwrap();
4559        loro.commit_then_renew();
4560
4561        assert_eq!(text.to_string(), "abc");
4562        assert_eq!(
4563            text.get_richtext_value().to_json_value(),
4564            json!([{"insert": "abc", "attributes": {"bold": true}}])
4565        );
4566    }
4567
4568    #[test]
4569    fn richtext_apply_delta_grows_for_mark_gap() {
4570        let loro = LoroDoc::new_auto_commit();
4571        let text = loro.get_text("text");
4572
4573        text.apply_delta(&[TextDelta::Retain {
4574            retain: 1,
4575            attributes: Some(fx_map!("bold".into() => LoroValue::Bool(true))),
4576        }])
4577        .unwrap();
4578        loro.commit_then_renew();
4579
4580        assert_eq!(text.to_string(), "\n");
4581        assert_eq!(
4582            text.get_richtext_value().to_json_value(),
4583            json!([{"insert": "\n", "attributes": {"bold": true}}])
4584        );
4585    }
4586
4587    #[test]
4588    fn richtext_apply_delta_ignores_empty_inserts() {
4589        let loro = LoroDoc::new_auto_commit();
4590        let text = loro.get_text("text");
4591        text.insert(0, "seed", PosType::Unicode).unwrap();
4592
4593        text.apply_delta(&[TextDelta::Insert {
4594            insert: "".into(),
4595            attributes: Some(fx_map!("bold".into() => LoroValue::Bool(true))),
4596        }])
4597        .unwrap();
4598        loro.commit_then_renew();
4599
4600        assert_eq!(text.to_string(), "seed");
4601        assert_eq!(
4602            text.get_richtext_value().to_json_value(),
4603            json!([{"insert": "seed"}])
4604        );
4605    }
4606}