Skip to main content

loro_internal/
handler.rs

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