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 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 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 }
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 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 .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 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 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 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 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 if self.is_parent(&target, &parent) {
710 if let Some(current_index) = self.get_index_by_tree_id(&target) {
712 if current_index == index {
713 return Ok(());
714 }
715 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 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 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 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 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 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 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 pub fn enable_fractional_index(&self, jitter: u8) {
1108 match &self.inner {
1109 MaybeDetached::Detached(_) => {
1110 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 pub fn disable_fractional_index(&self) {
1125 match &self.inner {
1126 MaybeDetached::Detached(_) => {
1127 }
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}