Skip to main content

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