Skip to main content

loro_internal/handler/
tree.rs

1use std::{collections::VecDeque, sync::Arc};
2
3use fractional_index::FractionalIndex;
4use loro_common::{
5    ContainerID, ContainerType, Counter, IdFull, IdLp, LoroError, LoroResult, LoroTreeError,
6    LoroValue, PeerID, TreeID, ID,
7};
8use rustc_hash::FxHashMap;
9use smallvec::smallvec;
10
11use crate::{
12    container::tree::tree_op::TreeOp,
13    delta::{TreeDiffItem, TreeExternalDiff},
14    state::{
15        FiIfNotConfigured, FractionalIndexGenResult, NodePosition, TreeNode, TreeNodeWithChildren,
16        TreeParentId,
17    },
18    txn::{EventHint, Transaction},
19    BasicHandler, HandlerTrait, MapHandler,
20};
21
22use super::{create_handler, Handler, MaybeDetached};
23
24#[derive(Clone)]
25pub struct TreeHandler {
26    pub(super) inner: MaybeDetached<TreeInner>,
27}
28
29#[derive(Clone)]
30pub(super) struct TreeInner {
31    next_counter: Counter,
32    map: FxHashMap<TreeID, MapHandler>,
33    parent_links: FxHashMap<TreeID, Option<TreeID>>,
34    children_links: FxHashMap<Option<TreeID>, Vec<TreeID>>,
35}
36
37impl TreeInner {
38    fn new() -> Self {
39        TreeInner {
40            next_counter: 0,
41            map: FxHashMap::default(),
42            parent_links: FxHashMap::default(),
43            children_links: FxHashMap::default(),
44        }
45    }
46
47    fn create(&mut self, parent: Option<TreeID>, index: usize) -> TreeID {
48        let id = TreeID::new(PeerID::MAX, self.next_counter);
49        self.next_counter += 1;
50        self.map.insert(id, MapHandler::new_detached());
51        self.parent_links.insert(id, parent);
52        let children = self.children_links.entry(parent).or_default();
53        children.insert(index, id);
54        id
55    }
56
57    fn mov(&mut self, target: TreeID, new_parent: Option<TreeID>, index: usize) -> LoroResult<()> {
58        let old_parent = self
59            .parent_links
60            .get_mut(&target)
61            .ok_or(LoroTreeError::TreeNodeNotExist(target))?;
62        let children = self.children_links.get_mut(old_parent).unwrap();
63        children.retain(|x| x != &target);
64        self.parent_links.insert(target, new_parent);
65        let children = self.children_links.entry(new_parent).or_default();
66        children.insert(index, target);
67        Ok(())
68    }
69
70    fn delete(&mut self, id: TreeID) -> LoroResult<()> {
71        self.map.remove(&id);
72        let parent = self
73            .parent_links
74            .remove(&id)
75            .ok_or(LoroTreeError::TreeNodeNotExist(id))?;
76        let children = self.children_links.get_mut(&parent).unwrap();
77        children.retain(|x| x != &id);
78        self.children_links.remove(&Some(id));
79        Ok(())
80    }
81
82    fn get_id_by_index(&self, parent: &Option<TreeID>, index: usize) -> Option<TreeID> {
83        self.children_links
84            .get(parent)
85            .and_then(|x| x.get(index).cloned())
86    }
87
88    fn get_parent(&self, id: &TreeID) -> Option<Option<TreeID>> {
89        self.parent_links.get(id).cloned()
90    }
91
92    fn get_children(&self, parent: Option<TreeID>) -> Option<Vec<TreeID>> {
93        self.children_links.get(&parent).cloned()
94    }
95
96    fn children_num(&self, parent: Option<TreeID>) -> Option<usize> {
97        self.children_links.get(&parent).map(|x| x.len())
98    }
99
100    fn is_parent(&self, target: &TreeID, parent: &Option<TreeID>) -> bool {
101        self.parent_links.get(target) == Some(parent)
102    }
103
104    fn get_index_by_tree_id(&self, target: &TreeID) -> Option<usize> {
105        self.parent_links
106            .get(target)
107            .and_then(|parent| self.children_links.get(parent))
108            .and_then(|children| children.iter().position(|x| x == target))
109    }
110
111    fn get_value(&self, deep: bool) -> LoroValue {
112        let mut ans = vec![];
113
114        let empty_vec = vec![];
115        let mut q = VecDeque::from_iter(
116            self.children_links
117                .get(&None)
118                .unwrap_or(&empty_vec)
119                .iter()
120                .enumerate()
121                .zip(std::iter::repeat(None::<TreeID>)),
122        );
123
124        while let Some(((idx, target), parent)) = q.pop_front() {
125            let map = self.map.get(target).unwrap();
126            let mut loro_map_value = FxHashMap::default();
127            loro_map_value.insert("id".to_string(), target.to_string().into());
128            let parent = parent
129                .map(|p| p.to_string().into())
130                .unwrap_or(LoroValue::Null);
131            loro_map_value.insert("parent".to_string(), parent);
132            loro_map_value.insert(
133                "meta".to_string(),
134                if deep {
135                    map.get_deep_value()
136                } else {
137                    String::from("UnResolved").into()
138                },
139            );
140            loro_map_value.insert("index".to_string(), (idx as i64).into());
141            ans.push(loro_map_value);
142            if let Some(children) = self.children_links.get(&Some(*target)) {
143                for (idx, child) in children.iter().enumerate() {
144                    q.push_back(((idx, child), Some(*target)));
145                }
146            }
147        }
148        ans.into()
149    }
150
151    fn get_nodes_under(&self, root: TreeParentId) -> Vec<TreeNode> {
152        let root_id = root.tree_id();
153        let mut ans = vec![];
154        let empty_vec = vec![];
155        let mut q = VecDeque::from_iter(
156            self.children_links
157                .get(&root_id)
158                .unwrap_or(&empty_vec)
159                .iter()
160                .enumerate()
161                .zip(std::iter::repeat(root)),
162        );
163
164        while let Some(((index, target), parent)) = q.pop_front() {
165            ans.push(TreeNode {
166                id: *target,
167                parent,
168                fractional_index: FractionalIndex::default(),
169                index,
170                last_move_op: IdFull {
171                    peer: target.peer,
172                    lamport: 0,
173                    counter: target.counter,
174                },
175            });
176            if let Some(children) = self.children_links.get(&Some(*target)) {
177                let parent = TreeParentId::Node(*target);
178                q.extend(
179                    children
180                        .iter()
181                        .enumerate()
182                        .map(|(index, target)| ((index, target), parent)),
183                );
184            }
185        }
186
187        ans
188    }
189}
190
191impl HandlerTrait for TreeHandler {
192    fn to_handler(&self) -> Handler {
193        Handler::Tree(self.clone())
194    }
195
196    fn attach(
197        &self,
198        txn: &mut Transaction,
199        parent: &BasicHandler,
200        self_id: ContainerID,
201    ) -> LoroResult<Self> {
202        match &self.inner {
203            MaybeDetached::Detached(t) => {
204                let mut t = t.lock();
205                let inner = create_handler(parent, self_id);
206                let tree = inner.into_tree().unwrap();
207
208                let children = t.value.children_links.get(&None);
209                let mut q = children
210                    .map(|c| {
211                        VecDeque::from_iter(
212                            c.iter()
213                                .enumerate()
214                                .zip(std::iter::repeat(TreeParentId::Root)),
215                        )
216                    })
217                    .unwrap_or_default();
218                while let Some(((idx, target), parent)) = q.pop_front() {
219                    let real_id =
220                        tree.create_with_txn(txn, parent, idx, FiIfNotConfigured::UseJitterZero)?;
221                    let map = t.value.map.get(target).unwrap();
222                    map.attach(
223                        txn,
224                        tree.inner.try_attached_state()?,
225                        real_id.associated_meta_container(),
226                    )?;
227
228                    if let Some(children) = t.value.children_links.get(&Some(*target)) {
229                        for (idx, child) in children.iter().enumerate() {
230                            q.push_back(((idx, child), TreeParentId::Node(real_id)));
231                        }
232                    }
233                }
234                t.attached = tree.attached_handler().cloned();
235                Ok(tree)
236            }
237            MaybeDetached::Attached(a) => {
238                let new_inner = create_handler(a, self_id);
239                let ans = new_inner.into_tree().unwrap();
240
241                fn attach_nodes(
242                    source: &TreeHandler,
243                    target: &TreeHandler,
244                    txn: &mut Transaction,
245                    parent: TreeParentId,
246                    nodes: Vec<TreeNodeWithChildren>,
247                ) -> LoroResult<()> {
248                    for node in nodes {
249                        let real_id = target.create_with_txn(
250                            txn,
251                            parent,
252                            node.index,
253                            FiIfNotConfigured::UseJitterZero,
254                        )?;
255                        source.get_meta(node.id)?.attach(
256                            txn,
257                            target.inner.try_attached_state()?,
258                            real_id.associated_meta_container(),
259                        )?;
260                        attach_nodes(
261                            source,
262                            target,
263                            txn,
264                            TreeParentId::Node(real_id),
265                            node.children,
266                        )?;
267                    }
268
269                    Ok(())
270                }
271
272                let tree_nodes = self.get_all_hierarchy_nodes_under(TreeParentId::Root);
273                attach_nodes(self, &ans, txn, TreeParentId::Root, tree_nodes)?;
274                Ok(ans)
275            }
276        }
277    }
278
279    fn is_attached(&self) -> bool {
280        self.inner.is_attached()
281    }
282
283    fn attached_handler(&self) -> Option<&BasicHandler> {
284        self.inner.attached_handler()
285    }
286
287    fn get_value(&self) -> LoroValue {
288        match &self.inner {
289            MaybeDetached::Detached(t) => {
290                let t = t.lock();
291                t.value.get_value(false)
292            }
293            MaybeDetached::Attached(a) => a.get_value(),
294        }
295    }
296
297    fn get_deep_value(&self) -> LoroValue {
298        match &self.inner {
299            MaybeDetached::Detached(t) => {
300                let t = t.lock();
301                t.value.get_value(true)
302            }
303            MaybeDetached::Attached(a) => a.get_deep_value(),
304        }
305    }
306
307    fn kind(&self) -> ContainerType {
308        ContainerType::Tree
309    }
310
311    fn get_attached(&self) -> Option<Self> {
312        match &self.inner {
313            MaybeDetached::Detached(d) => d.lock().attached.clone().map(|x| Self {
314                inner: MaybeDetached::Attached(x),
315            }),
316            MaybeDetached::Attached(_a) => Some(self.clone()),
317        }
318    }
319
320    fn from_handler(h: Handler) -> Option<Self> {
321        match h {
322            Handler::Tree(x) => Some(x),
323            _ => None,
324        }
325    }
326
327    fn doc(&self) -> Option<crate::LoroDoc> {
328        match &self.inner {
329            MaybeDetached::Detached(_) => None,
330            MaybeDetached::Attached(a) => Some(a.doc()),
331        }
332    }
333}
334
335impl std::fmt::Debug for TreeHandler {
336    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
337        match &self.inner {
338            MaybeDetached::Detached(_) => write!(f, "TreeHandler Detached"),
339            MaybeDetached::Attached(a) => write!(f, "TreeHandler {}", a.id),
340        }
341    }
342}
343
344impl TreeHandler {
345    /// Create a new container that is detached from the document.
346    ///
347    /// The edits on a detached container will not be persisted/synced.
348    /// To attach the container to the document, please insert it into an attached
349    /// container.
350    pub fn new_detached() -> Self {
351        Self {
352            inner: MaybeDetached::new_detached(TreeInner::new()),
353        }
354    }
355
356    /// Get the deep value of the tree with its container id, as a
357    /// `{ cid, value }` map. Each node in `value` carries the deep value of its
358    /// associated meta map under the `meta` field.
359    pub fn get_deep_value_with_id(&self) -> LoroResult<LoroValue> {
360        let inner = self.inner.try_attached_state()?;
361        Ok(inner.with_doc_state(|state| {
362            state.get_container_deep_value_with_id(inner.container_idx, None)
363        }))
364    }
365
366    pub fn delete(&self, target: TreeID) -> LoroResult<()> {
367        match &self.inner {
368            MaybeDetached::Detached(t) => {
369                let mut t = t.lock();
370                t.value.delete(target)?;
371                Ok(())
372            }
373            MaybeDetached::Attached(a) => a.with_txn(|txn| self.delete_with_txn(txn, target)),
374        }
375    }
376
377    pub(crate) fn delete_with_txn(&self, txn: &mut Transaction, target: TreeID) -> LoroResult<()> {
378        let inner = self.inner.try_attached_state()?;
379        let index = match self.get_index_by_tree_id(&target) {
380            Some(i) => i,
381            None => {
382                return Err(LoroTreeError::TreeNodeDeletedOrNotExist(target).into());
383            }
384        };
385        txn.apply_local_op(
386            inner.container_idx,
387            crate::op::RawOpContent::Tree(Arc::new(TreeOp::Delete { target })),
388            EventHint::Tree(smallvec![TreeDiffItem {
389                target,
390                action: TreeExternalDiff::Delete {
391                    old_parent: self
392                        .get_node_parent(&target)
393                        .ok_or(LoroTreeError::TreeNodeDeletedOrNotExist(target))?,
394                    old_index: index
395                },
396            }]),
397            &inner.doc,
398        )
399    }
400
401    pub fn create(&self, parent: TreeParentId) -> LoroResult<TreeID> {
402        match parent {
403            TreeParentId::Deleted | TreeParentId::Unexist => {
404                return Err(LoroTreeError::InvalidParent.into());
405            }
406            _ => {}
407        }
408        let index: usize = self.children_num(&parent).unwrap_or(0);
409        match &self.inner {
410            MaybeDetached::Detached(t) => {
411                let t = &mut t.lock().value;
412                Ok(t.create(parent.tree_id(), index))
413            }
414            MaybeDetached::Attached(a) => {
415                a.with_txn(|txn| self.create_with_txn(txn, parent, index, FiIfNotConfigured::Zero))
416            }
417        }
418    }
419
420    pub fn create_at(&self, parent: TreeParentId, index: usize) -> LoroResult<TreeID> {
421        match parent {
422            TreeParentId::Deleted | TreeParentId::Unexist => {
423                return Err(LoroTreeError::InvalidParent.into());
424            }
425            _ => {}
426        }
427        let children_len = self.children_num(&parent).unwrap_or(0);
428        if index > children_len {
429            return Err(LoroTreeError::IndexOutOfBound {
430                len: children_len,
431                index,
432            }
433            .into());
434        }
435        match &self.inner {
436            MaybeDetached::Detached(t) => {
437                let t = &mut t.lock().value;
438                Ok(t.create(parent.tree_id(), index))
439            }
440            MaybeDetached::Attached(a) => {
441                a.with_txn(|txn| self.create_with_txn(txn, parent, index, FiIfNotConfigured::Throw))
442            }
443        }
444    }
445
446    /// For undo/redo, Specify the TreeID of the created node
447    pub(crate) fn create_at_with_target_for_apply_diff(
448        &self,
449        parent: TreeParentId,
450        position: FractionalIndex,
451        target: TreeID,
452    ) -> LoroResult<bool> {
453        let MaybeDetached::Attached(a) = &self.inner else {
454            unreachable!();
455        };
456
457        if let Some(p) = self.get_node_parent(&target) {
458            if p == parent {
459                return Ok(false);
460                // If parent is deleted, we need to create the node, so this op from move_apply_diff
461            }
462            match p {
463                TreeParentId::Node(p) => {
464                    if !self.is_node_unexist(&target) && !self.is_node_deleted(&p)? {
465                        return self.move_at_with_target_for_apply_diff(parent, position, target);
466                    }
467                }
468                TreeParentId::Root => {
469                    return self.move_at_with_target_for_apply_diff(parent, position, target);
470                }
471                TreeParentId::Deleted | TreeParentId::Unexist => {}
472            }
473        }
474
475        let with_event = !parent
476            .tree_id()
477            .is_some_and(|p| self.is_node_deleted(&p).unwrap());
478        if !with_event {
479            return Ok(false);
480        }
481
482        // println!(
483        //     "create_at_with_target_for_apply_diff: {:?} {:?}",
484        //     target, parent
485        // );
486
487        let index = self
488            .get_index_by_fractional_index(
489                &parent,
490                &NodePosition {
491                    position: position.clone(),
492                    idlp: self.next_idlp(),
493                },
494            )
495            // TODO: parent has deleted?
496            .unwrap_or(0);
497
498        let children = a.with_txn(|txn| {
499            let inner = self.inner.try_attached_state()?;
500
501            txn.apply_local_op(
502                inner.container_idx,
503                crate::op::RawOpContent::Tree(Arc::new(TreeOp::Create {
504                    target,
505                    parent: parent.tree_id(),
506                    position: position.clone(),
507                })),
508                EventHint::Tree(smallvec![TreeDiffItem {
509                    target,
510                    action: TreeExternalDiff::Create {
511                        parent,
512                        index,
513                        position: position.clone(),
514                    },
515                }]),
516                &inner.doc,
517            )?;
518
519            Ok(self
520                .children(&TreeParentId::Node(target))
521                .unwrap_or_default())
522        })?;
523        for child in children {
524            let position = self.get_position_by_tree_id(&child).unwrap();
525            self.create_at_with_target_for_apply_diff(TreeParentId::Node(target), position, child)?;
526        }
527        Ok(true)
528    }
529
530    /// For undo/redo, Specify the TreeID of the created node
531    pub(crate) fn move_at_with_target_for_apply_diff(
532        &self,
533        parent: TreeParentId,
534        position: FractionalIndex,
535        target: TreeID,
536    ) -> LoroResult<bool> {
537        let MaybeDetached::Attached(a) = &self.inner else {
538            unreachable!();
539        };
540
541        // // the move node does not exist, create it
542        // if self.is_node_unexist(&target) || self.is_node_deleted(&target).unwrap() {
543        //     return self.create_at_with_target_for_apply_diff(parent, position, target);
544        // }
545
546        if let (Some(p), Some(fi)) = (
547            self.get_node_parent(&target),
548            self.get_position_by_tree_id(&target),
549        ) {
550            if p == parent && position == fi {
551                return Ok(false);
552            }
553        }
554
555        let old_parent = self.get_node_parent(&target).unwrap();
556        let old_index = self.get_index_by_tree_id(&target).unwrap();
557        let mut index = self
558            .get_index_by_fractional_index(
559                &parent,
560                &NodePosition {
561                    position: position.clone(),
562                    idlp: self.next_idlp(),
563                },
564            )
565            .unwrap_or(0);
566        if old_parent == parent && old_index < index {
567            index -= 1;
568        }
569        let with_event = match parent.tree_id() {
570            Some(p) => !self.is_node_deleted(&p)?,
571            None => true,
572        };
573
574        if !with_event {
575            return Ok(false);
576        }
577
578        // println!(
579        //     "move_at_with_target_for_apply_diff: {:?} {:?}",
580        //     target, parent
581        // );
582
583        a.with_txn(|txn| {
584            let inner = self.inner.try_attached_state()?;
585            txn.apply_local_op(
586                inner.container_idx,
587                crate::op::RawOpContent::Tree(Arc::new(TreeOp::Move {
588                    target,
589                    parent: parent.tree_id(),
590                    position: position.clone(),
591                })),
592                EventHint::Tree(smallvec![TreeDiffItem {
593                    target,
594                    action: TreeExternalDiff::Move {
595                        parent,
596                        index,
597                        position: position.clone(),
598                        // the old parent should be exist, so we can unwrap
599                        old_parent,
600                        old_index,
601                    },
602                }]),
603                &inner.doc,
604            )
605        })?;
606        Ok(true)
607    }
608
609    pub(crate) fn create_with_txn(
610        &self,
611        txn: &mut Transaction,
612        parent: TreeParentId,
613        index: usize,
614        cfg: FiIfNotConfigured,
615    ) -> LoroResult<TreeID> {
616        let inner = self.inner.try_attached_state()?;
617        let target = TreeID::from_id(txn.next_id());
618
619        match self.generate_position_at(&target, &parent, index, cfg) {
620            FractionalIndexGenResult::Ok(position) => {
621                self.create_with_position(inner, txn, target, parent, index, position)
622            }
623            FractionalIndexGenResult::Rearrange(ids) => {
624                for (i, (id, position)) in ids.into_iter().enumerate() {
625                    if i == 0 {
626                        self.create_with_position(inner, txn, id, parent, index, position)?;
627                        continue;
628                    }
629                    self.mov_with_position(inner, txn, id, parent, index + i, position, index + i)?;
630                }
631                Ok(target)
632            }
633            FractionalIndexGenResult::NotConfigured => {
634                Err(LoroTreeError::FractionalIndexNotEnabled.into())
635            }
636        }
637    }
638
639    pub fn mov(&self, target: TreeID, parent: TreeParentId) -> LoroResult<()> {
640        match &self.inner {
641            MaybeDetached::Detached(_) => {
642                let mut index: usize = self.children_num(&parent).unwrap_or(0);
643                if self.is_parent(&target, &parent) {
644                    index -= 1;
645                }
646                self.move_to(target, parent, index)
647            }
648            MaybeDetached::Attached(a) => {
649                let mut index: usize = self.children_num(&parent).unwrap_or(0);
650                if self.is_parent(&target, &parent) {
651                    index -= 1;
652                }
653                a.with_txn(|txn| {
654                    self.mov_with_txn(txn, target, parent, index, FiIfNotConfigured::Zero)
655                })
656            }
657        }
658    }
659
660    pub fn mov_after(&self, target: TreeID, other: TreeID) -> LoroResult<()> {
661        let parent = self
662            .get_node_parent(&other)
663            .ok_or(LoroTreeError::TreeNodeNotExist(other))?;
664        let mut index = self
665            .get_index_by_tree_id(&other)
666            .ok_or(LoroTreeError::TreeNodeDeletedOrNotExist(other))?
667            + 1;
668        if self.is_parent(&target, &parent) {
669            if let Some(target_index) = self.get_index_by_tree_id(&target) {
670                if target_index < index {
671                    index -= 1;
672                }
673            }
674        }
675        self.move_to(target, parent, index)
676    }
677
678    pub fn mov_before(&self, target: TreeID, other: TreeID) -> LoroResult<()> {
679        let parent = self
680            .get_node_parent(&other)
681            .ok_or(LoroTreeError::TreeNodeNotExist(other))?;
682        let mut index = self
683            .get_index_by_tree_id(&other)
684            .ok_or(LoroTreeError::TreeNodeDeletedOrNotExist(other))?;
685        if self.is_parent(&target, &parent) && index >= 1 {
686            if let Some(target_index) = self.get_index_by_tree_id(&target) {
687                if target_index < index {
688                    index -= 1;
689                }
690            }
691        }
692        self.move_to(target, parent, index)
693    }
694
695    pub fn move_to(&self, target: TreeID, parent: TreeParentId, index: usize) -> LoroResult<()> {
696        match &self.inner {
697            MaybeDetached::Detached(t) => {
698                let mut t = t.lock();
699                t.value.mov(target, parent.tree_id(), index)
700            }
701            MaybeDetached::Attached(a) => a.with_txn(|txn| {
702                self.mov_with_txn(txn, target, parent, index, FiIfNotConfigured::Throw)
703            }),
704        }
705    }
706
707    pub(crate) fn mov_with_txn(
708        &self,
709        txn: &mut Transaction,
710        target: TreeID,
711        parent: TreeParentId,
712        index: usize,
713        cfg: FiIfNotConfigured,
714    ) -> LoroResult<()> {
715        let inner = self.inner.try_attached_state()?;
716        let mut children_len = self.children_num(&parent).unwrap_or(0);
717        let mut already_in_parent = false;
718        // check the input is valid
719        if self.is_parent(&target, &parent) {
720            // If the position after moving is same as the current position , do nothing
721            if let Some(current_index) = self.get_index_by_tree_id(&target) {
722                if current_index == index {
723                    return Ok(());
724                }
725                // move out first, we cannot delete the position here
726                // If throw error, the tree will be in a inconsistent state
727                children_len -= 1;
728                already_in_parent = true;
729            }
730        };
731        if index > children_len {
732            return Err(LoroTreeError::IndexOutOfBound {
733                len: children_len,
734                index,
735            }
736            .into());
737        }
738        let Some(old_index) = self.get_index_by_tree_id(&target) else {
739            return Err(LoroError::TreeError(
740                LoroTreeError::TreeNodeDeletedOrNotExist(target),
741            ));
742        };
743
744        if already_in_parent {
745            self.delete_position(&parent, &target);
746        }
747
748        match self.generate_position_at(&target, &parent, index, cfg) {
749            FractionalIndexGenResult::Ok(position) => {
750                self.mov_with_position(inner, txn, target, parent, index, position, old_index)
751            }
752            FractionalIndexGenResult::Rearrange(ids) => {
753                for (i, (id, position)) in ids.into_iter().enumerate() {
754                    self.mov_with_position(inner, txn, id, parent, index + i, position, old_index)?;
755                }
756                Ok(())
757            }
758            FractionalIndexGenResult::NotConfigured => {
759                Err(LoroTreeError::FractionalIndexNotEnabled.into())
760            }
761        }
762    }
763
764    #[allow(clippy::too_many_arguments)]
765    fn create_with_position(
766        &self,
767        inner: &BasicHandler,
768        txn: &mut Transaction,
769        tree_id: TreeID,
770        parent: TreeParentId,
771        index: usize,
772        position: FractionalIndex,
773    ) -> LoroResult<TreeID> {
774        txn.apply_local_op(
775            inner.container_idx,
776            crate::op::RawOpContent::Tree(Arc::new(TreeOp::Create {
777                target: tree_id,
778                parent: parent.tree_id(),
779                position: position.clone(),
780            })),
781            EventHint::Tree(smallvec![TreeDiffItem {
782                target: tree_id,
783                action: TreeExternalDiff::Create {
784                    parent,
785                    index,
786                    position,
787                },
788            }]),
789            &inner.doc,
790        )?;
791        Ok(tree_id)
792    }
793
794    #[allow(clippy::too_many_arguments)]
795    fn mov_with_position(
796        &self,
797        inner: &BasicHandler,
798        txn: &mut Transaction,
799        target: TreeID,
800        parent: TreeParentId,
801        index: usize,
802        position: FractionalIndex,
803        old_index: usize,
804    ) -> LoroResult<()> {
805        txn.apply_local_op(
806            inner.container_idx,
807            crate::op::RawOpContent::Tree(Arc::new(TreeOp::Move {
808                target,
809                parent: parent.tree_id(),
810                position: position.clone(),
811            })),
812            EventHint::Tree(smallvec![TreeDiffItem {
813                target,
814                action: TreeExternalDiff::Move {
815                    parent,
816                    index,
817                    position,
818                    old_parent: self
819                        .get_node_parent(&target)
820                        .ok_or(LoroTreeError::TreeNodeDeletedOrNotExist(target))?,
821                    old_index,
822                },
823            }]),
824            &inner.doc,
825        )
826    }
827
828    pub fn get_meta(&self, target: TreeID) -> LoroResult<MapHandler> {
829        match &self.inner {
830            MaybeDetached::Detached(d) => {
831                let d = d.lock();
832                d.value
833                    .map
834                    .get(&target)
835                    .cloned()
836                    .ok_or(LoroTreeError::TreeNodeNotExist(target).into())
837            }
838            MaybeDetached::Attached(a) => {
839                if self.is_node_unexist(&target) {
840                    return Err(LoroTreeError::TreeNodeNotExist(target).into());
841                }
842                let map_container_id = target.associated_meta_container();
843                let handler = create_handler(a, map_container_id);
844                handler.into_map().map_err(|_| {
845                    LoroError::DecodeError(
846                        "Tree node's associated meta container is not a map".into(),
847                    )
848                })
849            }
850        }
851    }
852
853    pub fn is_node_unexist(&self, target: &TreeID) -> bool {
854        match &self.inner {
855            MaybeDetached::Detached(d) => {
856                let d = d.lock();
857                !d.value.map.contains_key(target)
858            }
859            MaybeDetached::Attached(a) => a.with_state(|state| {
860                let a = state.as_tree_state().unwrap();
861                a.is_node_unexist(target)
862            }),
863        }
864    }
865
866    pub fn is_node_deleted(&self, target: &TreeID) -> LoroResult<bool> {
867        match &self.inner {
868            MaybeDetached::Detached(t) => {
869                let t = t.lock();
870                t.value
871                    .map
872                    .get(target)
873                    .and(Some(true))
874                    .ok_or(LoroTreeError::TreeNodeNotExist(*target).into())
875            }
876            MaybeDetached::Attached(a) => a.with_state(|state| {
877                let a = state.as_tree_state().unwrap();
878                a.is_node_deleted(target)
879                    .ok_or(LoroTreeError::TreeNodeNotExist(*target).into())
880            }),
881        }
882    }
883
884    /// Get the parent of the node, if the node does not exist, return None
885    pub fn get_node_parent(&self, target: &TreeID) -> Option<TreeParentId> {
886        match &self.inner {
887            MaybeDetached::Detached(t) => {
888                let t = t.lock();
889                t.value.get_parent(target).map(TreeParentId::from)
890            }
891            MaybeDetached::Attached(a) => a.with_state(|state| {
892                let a = state.as_tree_state().unwrap();
893                a.parent(target)
894            }),
895        }
896    }
897
898    // TODO: iterator
899    pub fn children(&self, parent: &TreeParentId) -> Option<Vec<TreeID>> {
900        match &self.inner {
901            MaybeDetached::Detached(t) => {
902                let t = t.lock();
903                t.value.get_children(parent.tree_id())
904            }
905            MaybeDetached::Attached(a) => a.with_state(|state| {
906                let a = state.as_tree_state().unwrap();
907                a.get_children(parent).map(|x| x.collect())
908            }),
909        }
910    }
911
912    pub fn children_num(&self, parent: &TreeParentId) -> Option<usize> {
913        match &self.inner {
914            MaybeDetached::Detached(t) => {
915                let t = t.lock();
916                t.value.children_num(parent.tree_id())
917            }
918            MaybeDetached::Attached(a) => a.with_state(|state| {
919                let a = state.as_tree_state().unwrap();
920                a.children_num(parent)
921            }),
922        }
923    }
924
925    /// Check if the node is exist. include deleted node.
926    pub fn contains(&self, target: TreeID) -> bool {
927        match &self.inner {
928            MaybeDetached::Detached(t) => {
929                let t = t.lock();
930                t.value.map.contains_key(&target)
931            }
932            MaybeDetached::Attached(a) => a.with_state(|state| {
933                let a = state.as_tree_state().unwrap();
934                !a.is_node_unexist(&target)
935            }),
936        }
937    }
938
939    pub fn get_child_at(&self, parent: &TreeParentId, index: usize) -> Option<TreeID> {
940        match &self.inner {
941            MaybeDetached::Detached(t) => {
942                let t = t.lock();
943                t.value.get_id_by_index(&parent.tree_id(), index)
944            }
945            MaybeDetached::Attached(a) => a.with_state(|state| {
946                let a = state.as_tree_state().unwrap();
947                a.get_id_by_index(parent, index)
948            }),
949        }
950    }
951
952    pub fn is_parent(&self, target: &TreeID, parent: &TreeParentId) -> bool {
953        match &self.inner {
954            MaybeDetached::Detached(t) => {
955                let t = t.lock();
956                t.value.is_parent(target, &parent.tree_id())
957            }
958            MaybeDetached::Attached(a) => a.with_state(|state| {
959                let a = state.as_tree_state().unwrap();
960                a.is_parent(target, parent)
961            }),
962        }
963    }
964
965    /// Get all nodes in the tree, including deleted nodes
966    pub fn nodes(&self) -> Vec<TreeID> {
967        match &self.inner {
968            MaybeDetached::Detached(t) => {
969                let t = t.lock();
970                t.value.map.keys().cloned().collect()
971            }
972            MaybeDetached::Attached(a) => a.with_state(|state| {
973                let a = state.as_tree_state().unwrap();
974                a.nodes()
975            }),
976        }
977    }
978
979    pub fn get_nodes_under(&self, parent: TreeParentId) -> Vec<TreeNode> {
980        match &self.inner {
981            MaybeDetached::Detached(t) => t.lock().value.get_nodes_under(parent),
982            MaybeDetached::Attached(a) => a.with_state(|state| {
983                let a = state.as_tree_state().unwrap();
984                a.get_all_tree_nodes_under(parent)
985            }),
986        }
987    }
988    pub fn roots(&self) -> Vec<TreeID> {
989        self.children(&TreeParentId::Root).unwrap_or_default()
990    }
991
992    pub fn get_all_hierarchy_nodes_under(&self, parent: TreeParentId) -> Vec<TreeNodeWithChildren> {
993        match &self.inner {
994            MaybeDetached::Detached(_t) => {
995                unreachable!()
996            }
997            MaybeDetached::Attached(a) => a.with_state(|state| {
998                let a = state.as_tree_state().unwrap();
999                a.get_all_hierarchy_nodes_under(parent)
1000            }),
1001        }
1002    }
1003
1004    #[allow(non_snake_case)]
1005    pub fn __internal__next_tree_id(&self) -> TreeID {
1006        match &self.inner {
1007            MaybeDetached::Detached(d) => {
1008                let d = d.lock();
1009                TreeID::new(PeerID::MAX, d.value.next_counter)
1010            }
1011            MaybeDetached::Attached(a) => a
1012                .with_txn(|txn| Ok(TreeID::from_id(txn.next_id())))
1013                .unwrap(),
1014        }
1015    }
1016
1017    fn generate_position_at(
1018        &self,
1019        target: &TreeID,
1020        parent: &TreeParentId,
1021        index: usize,
1022        cfg: FiIfNotConfigured,
1023    ) -> FractionalIndexGenResult {
1024        let MaybeDetached::Attached(a) = &self.inner else {
1025            unreachable!()
1026        };
1027        a.with_state(|state| {
1028            let a = state.as_tree_state_mut().unwrap();
1029            a.generate_position_at(target, parent, index, cfg)
1030        })
1031    }
1032
1033    /// Get the index of the target node in the parent node
1034    ///
1035    /// O(logN)
1036    pub fn get_index_by_tree_id(&self, target: &TreeID) -> Option<usize> {
1037        match &self.inner {
1038            MaybeDetached::Detached(t) => {
1039                let t = t.lock();
1040                t.value.get_index_by_tree_id(target)
1041            }
1042            MaybeDetached::Attached(a) => a.with_state(|state| {
1043                let a = state.as_tree_state().unwrap();
1044                a.get_index_by_tree_id(target)
1045            }),
1046        }
1047    }
1048
1049    pub fn get_position_by_tree_id(&self, target: &TreeID) -> Option<FractionalIndex> {
1050        match &self.inner {
1051            MaybeDetached::Detached(t) => t
1052                .lock()
1053                .value
1054                .parent_links
1055                .contains_key(target)
1056                .then(FractionalIndex::default),
1057            MaybeDetached::Attached(a) => a.with_state(|state| {
1058                let a = state.as_tree_state().unwrap();
1059                a.get_position(target)
1060            }),
1061        }
1062    }
1063
1064    fn delete_position(&self, parent: &TreeParentId, target: &TreeID) {
1065        let MaybeDetached::Attached(a) = &self.inner else {
1066            unreachable!()
1067        };
1068        a.with_state(|state| {
1069            let a = state.as_tree_state_mut().unwrap();
1070            a.try_delete_position_cache(parent, target)
1071        })
1072    }
1073
1074    // use for apply diff
1075    pub(crate) fn get_index_by_fractional_index(
1076        &self,
1077        parent: &TreeParentId,
1078        node_position: &NodePosition,
1079    ) -> Option<usize> {
1080        match &self.inner {
1081            MaybeDetached::Detached(_) => {
1082                unreachable!();
1083            }
1084            MaybeDetached::Attached(a) => a.with_state(|state| {
1085                let a = state.as_tree_state().unwrap();
1086                a.get_index_by_position(parent, node_position)
1087            }),
1088        }
1089    }
1090
1091    pub(crate) fn next_idlp(&self) -> IdLp {
1092        match &self.inner {
1093            MaybeDetached::Detached(_) => {
1094                unreachable!()
1095            }
1096            MaybeDetached::Attached(a) => a.with_txn(|txn| Ok(txn.next_idlp())).unwrap(),
1097        }
1098    }
1099
1100    pub fn is_fractional_index_enabled(&self) -> bool {
1101        match &self.inner {
1102            MaybeDetached::Detached(_) => true,
1103            MaybeDetached::Attached(a) => a.with_state(|state| {
1104                let a = state.as_tree_state().unwrap();
1105                a.is_fractional_index_enabled()
1106            }),
1107        }
1108    }
1109
1110    /// Set whether to generate fractional index for Tree Position. The LoroDoc is set to use jitter 0 by default.
1111    ///
1112    /// The jitter is used to avoid conflicts when multiple users are creating the node at the same position.
1113    /// value 0 is default, which means no jitter, any value larger than 0 will enable jitter.
1114    ///
1115    /// Generally speaking, jitter will affect the growth rate of document size.
1116    /// [Read more about it](https://www.loro.dev/blog/movable-tree#implementation-and-encoding-size)
1117    pub fn enable_fractional_index(&self, jitter: u8) {
1118        match &self.inner {
1119            MaybeDetached::Detached(_) => {
1120                // No-op on detached trees
1121                let _ = jitter;
1122            }
1123            MaybeDetached::Attached(a) => a.with_state(|state| {
1124                let a = state.as_tree_state_mut().unwrap();
1125                a.enable_generate_fractional_index(jitter);
1126            }),
1127        }
1128    }
1129
1130    /// Disable the fractional index generation for Tree Position when
1131    /// you don't need the Tree's siblings to be sorted. The fractional index will be always default.
1132    ///
1133    /// The LoroDoc is set to disable fractional index by default.
1134    pub fn disable_fractional_index(&self) {
1135        match &self.inner {
1136            MaybeDetached::Detached(_) => {
1137                // No-op on detached trees
1138            }
1139            MaybeDetached::Attached(a) => a.with_state(|state| {
1140                let a = state.as_tree_state_mut().unwrap();
1141                a.disable_generate_fractional_index();
1142            }),
1143        }
1144    }
1145
1146    pub fn is_deleted(&self) -> bool {
1147        match &self.inner {
1148            MaybeDetached::Detached(_) => false,
1149            MaybeDetached::Attached(a) => a.is_deleted(),
1150        }
1151    }
1152
1153    pub fn is_empty(&self) -> bool {
1154        match &self.inner {
1155            MaybeDetached::Detached(t) => {
1156                let t = t.lock();
1157                t.value.map.is_empty()
1158            }
1159            MaybeDetached::Attached(a) => a.with_state(|state| {
1160                let a = state.as_tree_state().unwrap();
1161                a.is_empty()
1162            }),
1163        }
1164    }
1165
1166    pub fn get_last_move_id(&self, target: &TreeID) -> Option<ID> {
1167        match &self.inner {
1168            MaybeDetached::Detached(_) => None,
1169            MaybeDetached::Attached(a) => a.with_state(|state| {
1170                let a = state.as_tree_state().unwrap();
1171                a.get_last_move_id(target)
1172            }),
1173        }
1174    }
1175
1176    pub fn clear(&self) -> LoroResult<()> {
1177        match &self.inner {
1178            MaybeDetached::Detached(t) => {
1179                let mut t = t.lock();
1180                t.value.map.clear();
1181                t.value.children_links.clear();
1182                t.value.parent_links.clear();
1183                Ok(())
1184            }
1185            MaybeDetached::Attached(_) => {
1186                let nodes = self.get_nodes_under(TreeParentId::Root);
1187                for node in nodes {
1188                    self.delete(node.id)?;
1189                }
1190                Ok(())
1191            }
1192        }
1193    }
1194}