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    pub fn delete(&self, target: TreeID) -> LoroResult<()> {
357        match &self.inner {
358            MaybeDetached::Detached(t) => {
359                let mut t = t.lock();
360                t.value.delete(target)?;
361                Ok(())
362            }
363            MaybeDetached::Attached(a) => a.with_txn(|txn| self.delete_with_txn(txn, target)),
364        }
365    }
366
367    pub(crate) fn delete_with_txn(&self, txn: &mut Transaction, target: TreeID) -> LoroResult<()> {
368        let inner = self.inner.try_attached_state()?;
369        let index = match self.get_index_by_tree_id(&target) {
370            Some(i) => i,
371            None => {
372                return Err(LoroTreeError::TreeNodeDeletedOrNotExist(target).into());
373            }
374        };
375        txn.apply_local_op(
376            inner.container_idx,
377            crate::op::RawOpContent::Tree(Arc::new(TreeOp::Delete { target })),
378            EventHint::Tree(smallvec![TreeDiffItem {
379                target,
380                action: TreeExternalDiff::Delete {
381                    old_parent: self
382                        .get_node_parent(&target)
383                        .ok_or(LoroTreeError::TreeNodeDeletedOrNotExist(target))?,
384                    old_index: index
385                },
386            }]),
387            &inner.doc,
388        )
389    }
390
391    pub fn create(&self, parent: TreeParentId) -> LoroResult<TreeID> {
392        match parent {
393            TreeParentId::Deleted | TreeParentId::Unexist => {
394                return Err(LoroTreeError::InvalidParent.into());
395            }
396            _ => {}
397        }
398        let index: usize = self.children_num(&parent).unwrap_or(0);
399        match &self.inner {
400            MaybeDetached::Detached(t) => {
401                let t = &mut t.lock().value;
402                Ok(t.create(parent.tree_id(), index))
403            }
404            MaybeDetached::Attached(a) => {
405                a.with_txn(|txn| self.create_with_txn(txn, parent, index, FiIfNotConfigured::Zero))
406            }
407        }
408    }
409
410    pub fn create_at(&self, parent: TreeParentId, index: usize) -> LoroResult<TreeID> {
411        match parent {
412            TreeParentId::Deleted | TreeParentId::Unexist => {
413                return Err(LoroTreeError::InvalidParent.into());
414            }
415            _ => {}
416        }
417        let children_len = self.children_num(&parent).unwrap_or(0);
418        if index > children_len {
419            return Err(LoroTreeError::IndexOutOfBound {
420                len: children_len,
421                index,
422            }
423            .into());
424        }
425        match &self.inner {
426            MaybeDetached::Detached(t) => {
427                let t = &mut t.lock().value;
428                Ok(t.create(parent.tree_id(), index))
429            }
430            MaybeDetached::Attached(a) => {
431                a.with_txn(|txn| self.create_with_txn(txn, parent, index, FiIfNotConfigured::Throw))
432            }
433        }
434    }
435
436    /// For undo/redo, Specify the TreeID of the created node
437    pub(crate) fn create_at_with_target_for_apply_diff(
438        &self,
439        parent: TreeParentId,
440        position: FractionalIndex,
441        target: TreeID,
442    ) -> LoroResult<bool> {
443        let MaybeDetached::Attached(a) = &self.inner else {
444            unreachable!();
445        };
446
447        if let Some(p) = self.get_node_parent(&target) {
448            if p == parent {
449                return Ok(false);
450                // If parent is deleted, we need to create the node, so this op from move_apply_diff
451            }
452            match p {
453                TreeParentId::Node(p) => {
454                    if !self.is_node_unexist(&target) && !self.is_node_deleted(&p)? {
455                        return self.move_at_with_target_for_apply_diff(parent, position, target);
456                    }
457                }
458                TreeParentId::Root => {
459                    return self.move_at_with_target_for_apply_diff(parent, position, target);
460                }
461                TreeParentId::Deleted | TreeParentId::Unexist => {}
462            }
463        }
464
465        let with_event = !parent
466            .tree_id()
467            .is_some_and(|p| self.is_node_deleted(&p).unwrap());
468        if !with_event {
469            return Ok(false);
470        }
471
472        // println!(
473        //     "create_at_with_target_for_apply_diff: {:?} {:?}",
474        //     target, parent
475        // );
476
477        let index = self
478            .get_index_by_fractional_index(
479                &parent,
480                &NodePosition {
481                    position: position.clone(),
482                    idlp: self.next_idlp(),
483                },
484            )
485            // TODO: parent has deleted?
486            .unwrap_or(0);
487
488        let children = a.with_txn(|txn| {
489            let inner = self.inner.try_attached_state()?;
490
491            txn.apply_local_op(
492                inner.container_idx,
493                crate::op::RawOpContent::Tree(Arc::new(TreeOp::Create {
494                    target,
495                    parent: parent.tree_id(),
496                    position: position.clone(),
497                })),
498                EventHint::Tree(smallvec![TreeDiffItem {
499                    target,
500                    action: TreeExternalDiff::Create {
501                        parent,
502                        index,
503                        position: position.clone(),
504                    },
505                }]),
506                &inner.doc,
507            )?;
508
509            Ok(self
510                .children(&TreeParentId::Node(target))
511                .unwrap_or_default())
512        })?;
513        for child in children {
514            let position = self.get_position_by_tree_id(&child).unwrap();
515            self.create_at_with_target_for_apply_diff(TreeParentId::Node(target), position, child)?;
516        }
517        Ok(true)
518    }
519
520    /// For undo/redo, Specify the TreeID of the created node
521    pub(crate) fn move_at_with_target_for_apply_diff(
522        &self,
523        parent: TreeParentId,
524        position: FractionalIndex,
525        target: TreeID,
526    ) -> LoroResult<bool> {
527        let MaybeDetached::Attached(a) = &self.inner else {
528            unreachable!();
529        };
530
531        // // the move node does not exist, create it
532        // if self.is_node_unexist(&target) || self.is_node_deleted(&target).unwrap() {
533        //     return self.create_at_with_target_for_apply_diff(parent, position, target);
534        // }
535
536        if let (Some(p), Some(fi)) = (
537            self.get_node_parent(&target),
538            self.get_position_by_tree_id(&target),
539        ) {
540            if p == parent && position == fi {
541                return Ok(false);
542            }
543        }
544
545        let old_parent = self.get_node_parent(&target).unwrap();
546        let old_index = self.get_index_by_tree_id(&target).unwrap();
547        let mut index = self
548            .get_index_by_fractional_index(
549                &parent,
550                &NodePosition {
551                    position: position.clone(),
552                    idlp: self.next_idlp(),
553                },
554            )
555            .unwrap_or(0);
556        if old_parent == parent && old_index < index {
557            index -= 1;
558        }
559        let with_event = match parent.tree_id() {
560            Some(p) => !self.is_node_deleted(&p)?,
561            None => true,
562        };
563
564        if !with_event {
565            return Ok(false);
566        }
567
568        // println!(
569        //     "move_at_with_target_for_apply_diff: {:?} {:?}",
570        //     target, parent
571        // );
572
573        a.with_txn(|txn| {
574            let inner = self.inner.try_attached_state()?;
575            txn.apply_local_op(
576                inner.container_idx,
577                crate::op::RawOpContent::Tree(Arc::new(TreeOp::Move {
578                    target,
579                    parent: parent.tree_id(),
580                    position: position.clone(),
581                })),
582                EventHint::Tree(smallvec![TreeDiffItem {
583                    target,
584                    action: TreeExternalDiff::Move {
585                        parent,
586                        index,
587                        position: position.clone(),
588                        // the old parent should be exist, so we can unwrap
589                        old_parent,
590                        old_index,
591                    },
592                }]),
593                &inner.doc,
594            )
595        })?;
596        Ok(true)
597    }
598
599    pub(crate) fn create_with_txn(
600        &self,
601        txn: &mut Transaction,
602        parent: TreeParentId,
603        index: usize,
604        cfg: FiIfNotConfigured,
605    ) -> LoroResult<TreeID> {
606        let inner = self.inner.try_attached_state()?;
607        let target = TreeID::from_id(txn.next_id());
608
609        match self.generate_position_at(&target, &parent, index, cfg) {
610            FractionalIndexGenResult::Ok(position) => {
611                self.create_with_position(inner, txn, target, parent, index, position)
612            }
613            FractionalIndexGenResult::Rearrange(ids) => {
614                for (i, (id, position)) in ids.into_iter().enumerate() {
615                    if i == 0 {
616                        self.create_with_position(inner, txn, id, parent, index, position)?;
617                        continue;
618                    }
619                    self.mov_with_position(inner, txn, id, parent, index + i, position, index + i)?;
620                }
621                Ok(target)
622            }
623            FractionalIndexGenResult::NotConfigured => {
624                Err(LoroTreeError::FractionalIndexNotEnabled.into())
625            }
626        }
627    }
628
629    pub fn mov(&self, target: TreeID, parent: TreeParentId) -> LoroResult<()> {
630        match &self.inner {
631            MaybeDetached::Detached(_) => {
632                let mut index: usize = self.children_num(&parent).unwrap_or(0);
633                if self.is_parent(&target, &parent) {
634                    index -= 1;
635                }
636                self.move_to(target, parent, index)
637            }
638            MaybeDetached::Attached(a) => {
639                let mut index: usize = self.children_num(&parent).unwrap_or(0);
640                if self.is_parent(&target, &parent) {
641                    index -= 1;
642                }
643                a.with_txn(|txn| {
644                    self.mov_with_txn(txn, target, parent, index, FiIfNotConfigured::Zero)
645                })
646            }
647        }
648    }
649
650    pub fn mov_after(&self, target: TreeID, other: TreeID) -> LoroResult<()> {
651        let parent = self
652            .get_node_parent(&other)
653            .ok_or(LoroTreeError::TreeNodeNotExist(other))?;
654        let mut index = self
655            .get_index_by_tree_id(&other)
656            .ok_or(LoroTreeError::TreeNodeDeletedOrNotExist(other))?
657            + 1;
658        if self.is_parent(&target, &parent) {
659            if let Some(target_index) = self.get_index_by_tree_id(&target) {
660                if target_index < index {
661                    index -= 1;
662                }
663            }
664        }
665        self.move_to(target, parent, index)
666    }
667
668    pub fn mov_before(&self, target: TreeID, other: TreeID) -> LoroResult<()> {
669        let parent = self
670            .get_node_parent(&other)
671            .ok_or(LoroTreeError::TreeNodeNotExist(other))?;
672        let mut index = self
673            .get_index_by_tree_id(&other)
674            .ok_or(LoroTreeError::TreeNodeDeletedOrNotExist(other))?;
675        if self.is_parent(&target, &parent) && index >= 1 {
676            if let Some(target_index) = self.get_index_by_tree_id(&target) {
677                if target_index < index {
678                    index -= 1;
679                }
680            }
681        }
682        self.move_to(target, parent, index)
683    }
684
685    pub fn move_to(&self, target: TreeID, parent: TreeParentId, index: usize) -> LoroResult<()> {
686        match &self.inner {
687            MaybeDetached::Detached(t) => {
688                let mut t = t.lock();
689                t.value.mov(target, parent.tree_id(), index)
690            }
691            MaybeDetached::Attached(a) => a.with_txn(|txn| {
692                self.mov_with_txn(txn, target, parent, index, FiIfNotConfigured::Throw)
693            }),
694        }
695    }
696
697    pub(crate) fn mov_with_txn(
698        &self,
699        txn: &mut Transaction,
700        target: TreeID,
701        parent: TreeParentId,
702        index: usize,
703        cfg: FiIfNotConfigured,
704    ) -> LoroResult<()> {
705        let inner = self.inner.try_attached_state()?;
706        let mut children_len = self.children_num(&parent).unwrap_or(0);
707        let mut already_in_parent = false;
708        // check the input is valid
709        if self.is_parent(&target, &parent) {
710            // If the position after moving is same as the current position , do nothing
711            if let Some(current_index) = self.get_index_by_tree_id(&target) {
712                if current_index == index {
713                    return Ok(());
714                }
715                // move out first, we cannot delete the position here
716                // If throw error, the tree will be in a inconsistent state
717                children_len -= 1;
718                already_in_parent = true;
719            }
720        };
721        if index > children_len {
722            return Err(LoroTreeError::IndexOutOfBound {
723                len: children_len,
724                index,
725            }
726            .into());
727        }
728        let Some(old_index) = self.get_index_by_tree_id(&target) else {
729            return Err(LoroError::TreeError(
730                LoroTreeError::TreeNodeDeletedOrNotExist(target),
731            ));
732        };
733
734        if already_in_parent {
735            self.delete_position(&parent, &target);
736        }
737
738        match self.generate_position_at(&target, &parent, index, cfg) {
739            FractionalIndexGenResult::Ok(position) => {
740                self.mov_with_position(inner, txn, target, parent, index, position, old_index)
741            }
742            FractionalIndexGenResult::Rearrange(ids) => {
743                for (i, (id, position)) in ids.into_iter().enumerate() {
744                    self.mov_with_position(inner, txn, id, parent, index + i, position, old_index)?;
745                }
746                Ok(())
747            }
748            FractionalIndexGenResult::NotConfigured => {
749                Err(LoroTreeError::FractionalIndexNotEnabled.into())
750            }
751        }
752    }
753
754    #[allow(clippy::too_many_arguments)]
755    fn create_with_position(
756        &self,
757        inner: &BasicHandler,
758        txn: &mut Transaction,
759        tree_id: TreeID,
760        parent: TreeParentId,
761        index: usize,
762        position: FractionalIndex,
763    ) -> LoroResult<TreeID> {
764        txn.apply_local_op(
765            inner.container_idx,
766            crate::op::RawOpContent::Tree(Arc::new(TreeOp::Create {
767                target: tree_id,
768                parent: parent.tree_id(),
769                position: position.clone(),
770            })),
771            EventHint::Tree(smallvec![TreeDiffItem {
772                target: tree_id,
773                action: TreeExternalDiff::Create {
774                    parent,
775                    index,
776                    position,
777                },
778            }]),
779            &inner.doc,
780        )?;
781        Ok(tree_id)
782    }
783
784    #[allow(clippy::too_many_arguments)]
785    fn mov_with_position(
786        &self,
787        inner: &BasicHandler,
788        txn: &mut Transaction,
789        target: TreeID,
790        parent: TreeParentId,
791        index: usize,
792        position: FractionalIndex,
793        old_index: usize,
794    ) -> LoroResult<()> {
795        txn.apply_local_op(
796            inner.container_idx,
797            crate::op::RawOpContent::Tree(Arc::new(TreeOp::Move {
798                target,
799                parent: parent.tree_id(),
800                position: position.clone(),
801            })),
802            EventHint::Tree(smallvec![TreeDiffItem {
803                target,
804                action: TreeExternalDiff::Move {
805                    parent,
806                    index,
807                    position,
808                    old_parent: self
809                        .get_node_parent(&target)
810                        .ok_or(LoroTreeError::TreeNodeDeletedOrNotExist(target))?,
811                    old_index,
812                },
813            }]),
814            &inner.doc,
815        )
816    }
817
818    pub fn get_meta(&self, target: TreeID) -> LoroResult<MapHandler> {
819        match &self.inner {
820            MaybeDetached::Detached(d) => {
821                let d = d.lock();
822                d.value
823                    .map
824                    .get(&target)
825                    .cloned()
826                    .ok_or(LoroTreeError::TreeNodeNotExist(target).into())
827            }
828            MaybeDetached::Attached(a) => {
829                if self.is_node_unexist(&target) {
830                    return Err(LoroTreeError::TreeNodeNotExist(target).into());
831                }
832                let map_container_id = target.associated_meta_container();
833                let handler = create_handler(a, map_container_id);
834                handler.into_map().map_err(|_| {
835                    LoroError::DecodeError(
836                        "Tree node's associated meta container is not a map".into(),
837                    )
838                })
839            }
840        }
841    }
842
843    pub fn is_node_unexist(&self, target: &TreeID) -> bool {
844        match &self.inner {
845            MaybeDetached::Detached(d) => {
846                let d = d.lock();
847                !d.value.map.contains_key(target)
848            }
849            MaybeDetached::Attached(a) => a.with_state(|state| {
850                let a = state.as_tree_state().unwrap();
851                a.is_node_unexist(target)
852            }),
853        }
854    }
855
856    pub fn is_node_deleted(&self, target: &TreeID) -> LoroResult<bool> {
857        match &self.inner {
858            MaybeDetached::Detached(t) => {
859                let t = t.lock();
860                t.value
861                    .map
862                    .get(target)
863                    .and(Some(true))
864                    .ok_or(LoroTreeError::TreeNodeNotExist(*target).into())
865            }
866            MaybeDetached::Attached(a) => a.with_state(|state| {
867                let a = state.as_tree_state().unwrap();
868                a.is_node_deleted(target)
869                    .ok_or(LoroTreeError::TreeNodeNotExist(*target).into())
870            }),
871        }
872    }
873
874    /// Get the parent of the node, if the node does not exist, return None
875    pub fn get_node_parent(&self, target: &TreeID) -> Option<TreeParentId> {
876        match &self.inner {
877            MaybeDetached::Detached(t) => {
878                let t = t.lock();
879                t.value.get_parent(target).map(TreeParentId::from)
880            }
881            MaybeDetached::Attached(a) => a.with_state(|state| {
882                let a = state.as_tree_state().unwrap();
883                a.parent(target)
884            }),
885        }
886    }
887
888    // TODO: iterator
889    pub fn children(&self, parent: &TreeParentId) -> Option<Vec<TreeID>> {
890        match &self.inner {
891            MaybeDetached::Detached(t) => {
892                let t = t.lock();
893                t.value.get_children(parent.tree_id())
894            }
895            MaybeDetached::Attached(a) => a.with_state(|state| {
896                let a = state.as_tree_state().unwrap();
897                a.get_children(parent).map(|x| x.collect())
898            }),
899        }
900    }
901
902    pub fn children_num(&self, parent: &TreeParentId) -> Option<usize> {
903        match &self.inner {
904            MaybeDetached::Detached(t) => {
905                let t = t.lock();
906                t.value.children_num(parent.tree_id())
907            }
908            MaybeDetached::Attached(a) => a.with_state(|state| {
909                let a = state.as_tree_state().unwrap();
910                a.children_num(parent)
911            }),
912        }
913    }
914
915    /// Check if the node is exist. include deleted node.
916    pub fn contains(&self, target: TreeID) -> bool {
917        match &self.inner {
918            MaybeDetached::Detached(t) => {
919                let t = t.lock();
920                t.value.map.contains_key(&target)
921            }
922            MaybeDetached::Attached(a) => a.with_state(|state| {
923                let a = state.as_tree_state().unwrap();
924                !a.is_node_unexist(&target)
925            }),
926        }
927    }
928
929    pub fn get_child_at(&self, parent: &TreeParentId, index: usize) -> Option<TreeID> {
930        match &self.inner {
931            MaybeDetached::Detached(t) => {
932                let t = t.lock();
933                t.value.get_id_by_index(&parent.tree_id(), index)
934            }
935            MaybeDetached::Attached(a) => a.with_state(|state| {
936                let a = state.as_tree_state().unwrap();
937                a.get_id_by_index(parent, index)
938            }),
939        }
940    }
941
942    pub fn is_parent(&self, target: &TreeID, parent: &TreeParentId) -> bool {
943        match &self.inner {
944            MaybeDetached::Detached(t) => {
945                let t = t.lock();
946                t.value.is_parent(target, &parent.tree_id())
947            }
948            MaybeDetached::Attached(a) => a.with_state(|state| {
949                let a = state.as_tree_state().unwrap();
950                a.is_parent(target, parent)
951            }),
952        }
953    }
954
955    /// Get all nodes in the tree, including deleted nodes
956    pub fn nodes(&self) -> Vec<TreeID> {
957        match &self.inner {
958            MaybeDetached::Detached(t) => {
959                let t = t.lock();
960                t.value.map.keys().cloned().collect()
961            }
962            MaybeDetached::Attached(a) => a.with_state(|state| {
963                let a = state.as_tree_state().unwrap();
964                a.nodes()
965            }),
966        }
967    }
968
969    pub fn get_nodes_under(&self, parent: TreeParentId) -> Vec<TreeNode> {
970        match &self.inner {
971            MaybeDetached::Detached(t) => t.lock().value.get_nodes_under(parent),
972            MaybeDetached::Attached(a) => a.with_state(|state| {
973                let a = state.as_tree_state().unwrap();
974                a.get_all_tree_nodes_under(parent)
975            }),
976        }
977    }
978    pub fn roots(&self) -> Vec<TreeID> {
979        self.children(&TreeParentId::Root).unwrap_or_default()
980    }
981
982    pub fn get_all_hierarchy_nodes_under(&self, parent: TreeParentId) -> Vec<TreeNodeWithChildren> {
983        match &self.inner {
984            MaybeDetached::Detached(_t) => {
985                unreachable!()
986            }
987            MaybeDetached::Attached(a) => a.with_state(|state| {
988                let a = state.as_tree_state().unwrap();
989                a.get_all_hierarchy_nodes_under(parent)
990            }),
991        }
992    }
993
994    #[allow(non_snake_case)]
995    pub fn __internal__next_tree_id(&self) -> TreeID {
996        match &self.inner {
997            MaybeDetached::Detached(d) => {
998                let d = d.lock();
999                TreeID::new(PeerID::MAX, d.value.next_counter)
1000            }
1001            MaybeDetached::Attached(a) => a
1002                .with_txn(|txn| Ok(TreeID::from_id(txn.next_id())))
1003                .unwrap(),
1004        }
1005    }
1006
1007    fn generate_position_at(
1008        &self,
1009        target: &TreeID,
1010        parent: &TreeParentId,
1011        index: usize,
1012        cfg: FiIfNotConfigured,
1013    ) -> FractionalIndexGenResult {
1014        let MaybeDetached::Attached(a) = &self.inner else {
1015            unreachable!()
1016        };
1017        a.with_state(|state| {
1018            let a = state.as_tree_state_mut().unwrap();
1019            a.generate_position_at(target, parent, index, cfg)
1020        })
1021    }
1022
1023    /// Get the index of the target node in the parent node
1024    ///
1025    /// O(logN)
1026    pub fn get_index_by_tree_id(&self, target: &TreeID) -> Option<usize> {
1027        match &self.inner {
1028            MaybeDetached::Detached(t) => {
1029                let t = t.lock();
1030                t.value.get_index_by_tree_id(target)
1031            }
1032            MaybeDetached::Attached(a) => a.with_state(|state| {
1033                let a = state.as_tree_state().unwrap();
1034                a.get_index_by_tree_id(target)
1035            }),
1036        }
1037    }
1038
1039    pub fn get_position_by_tree_id(&self, target: &TreeID) -> Option<FractionalIndex> {
1040        match &self.inner {
1041            MaybeDetached::Detached(t) => t
1042                .lock()
1043                .value
1044                .parent_links
1045                .contains_key(target)
1046                .then(FractionalIndex::default),
1047            MaybeDetached::Attached(a) => a.with_state(|state| {
1048                let a = state.as_tree_state().unwrap();
1049                a.get_position(target)
1050            }),
1051        }
1052    }
1053
1054    fn delete_position(&self, parent: &TreeParentId, target: &TreeID) {
1055        let MaybeDetached::Attached(a) = &self.inner else {
1056            unreachable!()
1057        };
1058        a.with_state(|state| {
1059            let a = state.as_tree_state_mut().unwrap();
1060            a.try_delete_position_cache(parent, target)
1061        })
1062    }
1063
1064    // use for apply diff
1065    pub(crate) fn get_index_by_fractional_index(
1066        &self,
1067        parent: &TreeParentId,
1068        node_position: &NodePosition,
1069    ) -> Option<usize> {
1070        match &self.inner {
1071            MaybeDetached::Detached(_) => {
1072                unreachable!();
1073            }
1074            MaybeDetached::Attached(a) => a.with_state(|state| {
1075                let a = state.as_tree_state().unwrap();
1076                a.get_index_by_position(parent, node_position)
1077            }),
1078        }
1079    }
1080
1081    pub(crate) fn next_idlp(&self) -> IdLp {
1082        match &self.inner {
1083            MaybeDetached::Detached(_) => {
1084                unreachable!()
1085            }
1086            MaybeDetached::Attached(a) => a.with_txn(|txn| Ok(txn.next_idlp())).unwrap(),
1087        }
1088    }
1089
1090    pub fn is_fractional_index_enabled(&self) -> bool {
1091        match &self.inner {
1092            MaybeDetached::Detached(_) => true,
1093            MaybeDetached::Attached(a) => a.with_state(|state| {
1094                let a = state.as_tree_state().unwrap();
1095                a.is_fractional_index_enabled()
1096            }),
1097        }
1098    }
1099
1100    /// Set whether to generate fractional index for Tree Position. The LoroDoc is set to use jitter 0 by default.
1101    ///
1102    /// The jitter is used to avoid conflicts when multiple users are creating the node at the same position.
1103    /// value 0 is default, which means no jitter, any value larger than 0 will enable jitter.
1104    ///
1105    /// Generally speaking, jitter will affect the growth rate of document size.
1106    /// [Read more about it](https://www.loro.dev/blog/movable-tree#implementation-and-encoding-size)
1107    pub fn enable_fractional_index(&self, jitter: u8) {
1108        match &self.inner {
1109            MaybeDetached::Detached(_) => {
1110                // No-op on detached trees
1111                let _ = jitter;
1112            }
1113            MaybeDetached::Attached(a) => a.with_state(|state| {
1114                let a = state.as_tree_state_mut().unwrap();
1115                a.enable_generate_fractional_index(jitter);
1116            }),
1117        }
1118    }
1119
1120    /// Disable the fractional index generation for Tree Position when
1121    /// you don't need the Tree's siblings to be sorted. The fractional index will be always default.
1122    ///
1123    /// The LoroDoc is set to disable fractional index by default.
1124    pub fn disable_fractional_index(&self) {
1125        match &self.inner {
1126            MaybeDetached::Detached(_) => {
1127                // No-op on detached trees
1128            }
1129            MaybeDetached::Attached(a) => a.with_state(|state| {
1130                let a = state.as_tree_state_mut().unwrap();
1131                a.disable_generate_fractional_index();
1132            }),
1133        }
1134    }
1135
1136    pub fn is_deleted(&self) -> bool {
1137        match &self.inner {
1138            MaybeDetached::Detached(_) => false,
1139            MaybeDetached::Attached(a) => a.is_deleted(),
1140        }
1141    }
1142
1143    pub fn is_empty(&self) -> bool {
1144        match &self.inner {
1145            MaybeDetached::Detached(t) => {
1146                let t = t.lock();
1147                t.value.map.is_empty()
1148            }
1149            MaybeDetached::Attached(a) => a.with_state(|state| {
1150                let a = state.as_tree_state().unwrap();
1151                a.is_empty()
1152            }),
1153        }
1154    }
1155
1156    pub fn get_last_move_id(&self, target: &TreeID) -> Option<ID> {
1157        match &self.inner {
1158            MaybeDetached::Detached(_) => None,
1159            MaybeDetached::Attached(a) => a.with_state(|state| {
1160                let a = state.as_tree_state().unwrap();
1161                a.get_last_move_id(target)
1162            }),
1163        }
1164    }
1165
1166    pub fn clear(&self) -> LoroResult<()> {
1167        match &self.inner {
1168            MaybeDetached::Detached(t) => {
1169                let mut t = t.lock();
1170                t.value.map.clear();
1171                t.value.children_links.clear();
1172                t.value.parent_links.clear();
1173                Ok(())
1174            }
1175            MaybeDetached::Attached(_) => {
1176                let nodes = self.get_nodes_under(TreeParentId::Root);
1177                for node in nodes {
1178                    self.delete(node.id)?;
1179                }
1180                Ok(())
1181            }
1182        }
1183    }
1184}