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