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