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 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 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 }
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 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 .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 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 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 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 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 if self.is_parent(&target, &parent) {
619 if let Some(current_index) = self.get_index_by_tree_id(&target) {
621 if current_index == index {
622 return Ok(());
623 }
624 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 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 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 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 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 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 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 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 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 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}