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