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 index = self
466 .get_index_by_fractional_index(
467 &parent,
468 &NodePosition {
469 position: position.clone(),
470 idlp: self.next_idlp(),
471 },
472 )
473 .unwrap_or(0);
474 let with_event = !parent
475 .tree_id()
476 .is_some_and(|p| self.is_node_deleted(&p).unwrap());
477
478 if !with_event {
479 return Ok(false);
480 }
481
482 a.with_txn(|txn| {
488 let inner = self.inner.try_attached_state()?;
489 txn.apply_local_op(
490 inner.container_idx,
491 crate::op::RawOpContent::Tree(Arc::new(TreeOp::Move {
492 target,
493 parent: parent.tree_id(),
494 position: position.clone(),
495 })),
496 EventHint::Tree(smallvec![TreeDiffItem {
497 target,
498 action: TreeExternalDiff::Move {
499 parent,
500 index,
501 position: position.clone(),
502 old_parent: self.get_node_parent(&target).unwrap(),
504 old_index: self.get_index_by_tree_id(&target).unwrap(),
505 },
506 }]),
507 &inner.doc,
508 )
509 })?;
510 Ok(true)
511 }
512
513 pub(crate) fn create_with_txn(
514 &self,
515 txn: &mut Transaction,
516 parent: TreeParentId,
517 index: usize,
518 cfg: FiIfNotConfigured,
519 ) -> LoroResult<TreeID> {
520 let inner = self.inner.try_attached_state()?;
521 let target = TreeID::from_id(txn.next_id());
522
523 match self.generate_position_at(&target, &parent, index, cfg) {
524 FractionalIndexGenResult::Ok(position) => {
525 self.create_with_position(inner, txn, target, parent, index, position)
526 }
527 FractionalIndexGenResult::Rearrange(ids) => {
528 for (i, (id, position)) in ids.into_iter().enumerate() {
529 if i == 0 {
530 self.create_with_position(inner, txn, id, parent, index, position)?;
531 continue;
532 }
533 self.mov_with_position(inner, txn, id, parent, index + i, position, index + i)?;
534 }
535 Ok(target)
536 }
537 FractionalIndexGenResult::NotConfigured => {
538 Err(LoroTreeError::FractionalIndexNotEnabled.into())
539 }
540 }
541 }
542
543 pub fn mov(&self, target: TreeID, parent: TreeParentId) -> LoroResult<()> {
544 match &self.inner {
545 MaybeDetached::Detached(_) => {
546 let mut index: usize = self.children_num(&parent).unwrap_or(0);
547 if self.is_parent(&target, &parent) {
548 index -= 1;
549 }
550 self.move_to(target, parent, index)
551 }
552 MaybeDetached::Attached(a) => {
553 let mut index: usize = self.children_num(&parent).unwrap_or(0);
554 if self.is_parent(&target, &parent) {
555 index -= 1;
556 }
557 a.with_txn(|txn| {
558 self.mov_with_txn(txn, target, parent, index, FiIfNotConfigured::Zero)
559 })
560 }
561 }
562 }
563
564 pub fn mov_after(&self, target: TreeID, other: TreeID) -> LoroResult<()> {
565 let parent = self
566 .get_node_parent(&other)
567 .ok_or(LoroTreeError::TreeNodeNotExist(other))?;
568 let mut index = self.get_index_by_tree_id(&other).unwrap() + 1;
569 if self.is_parent(&target, &parent) && self.get_index_by_tree_id(&target).unwrap() < index {
570 index -= 1;
571 }
572 self.move_to(target, parent, index)
573 }
574
575 pub fn mov_before(&self, target: TreeID, other: TreeID) -> LoroResult<()> {
576 let parent = self
577 .get_node_parent(&other)
578 .ok_or(LoroTreeError::TreeNodeNotExist(other))?;
579 let mut index = self.get_index_by_tree_id(&other).unwrap();
580 if self.is_parent(&target, &parent)
581 && index >= 1
582 && self.get_index_by_tree_id(&target).unwrap() < index
583 {
584 index -= 1;
585 }
586 self.move_to(target, parent, index)
587 }
588
589 pub fn move_to(&self, target: TreeID, parent: TreeParentId, index: usize) -> LoroResult<()> {
590 match &self.inner {
591 MaybeDetached::Detached(t) => {
592 let mut t = t.lock().unwrap();
593 t.value.mov(target, parent.tree_id(), index)
594 }
595 MaybeDetached::Attached(a) => a.with_txn(|txn| {
596 self.mov_with_txn(txn, target, parent, index, FiIfNotConfigured::Throw)
597 }),
598 }
599 }
600
601 pub(crate) fn mov_with_txn(
602 &self,
603 txn: &mut Transaction,
604 target: TreeID,
605 parent: TreeParentId,
606 index: usize,
607 cfg: FiIfNotConfigured,
608 ) -> LoroResult<()> {
609 let inner = self.inner.try_attached_state()?;
610 let mut children_len = self.children_num(&parent).unwrap_or(0);
611 let mut already_in_parent = false;
612 if self.is_parent(&target, &parent) {
614 if let Some(current_index) = self.get_index_by_tree_id(&target) {
616 if current_index == index {
617 return Ok(());
618 }
619 children_len -= 1;
622 already_in_parent = true;
623 }
624 };
625 if index > children_len {
626 return Err(LoroTreeError::IndexOutOfBound {
627 len: children_len,
628 index,
629 }
630 .into());
631 }
632 let Some(old_index) = self.get_index_by_tree_id(&target) else {
633 return Err(LoroError::TreeError(
634 LoroTreeError::TreeNodeDeletedOrNotExist(target),
635 ));
636 };
637
638 if already_in_parent {
639 self.delete_position(&parent, &target);
640 }
641
642 match self.generate_position_at(&target, &parent, index, cfg) {
643 FractionalIndexGenResult::Ok(position) => {
644 self.mov_with_position(inner, txn, target, parent, index, position, old_index)
645 }
646 FractionalIndexGenResult::Rearrange(ids) => {
647 for (i, (id, position)) in ids.into_iter().enumerate() {
648 self.mov_with_position(inner, txn, id, parent, index + i, position, old_index)?;
649 }
650 Ok(())
651 }
652 FractionalIndexGenResult::NotConfigured => {
653 Err(LoroTreeError::FractionalIndexNotEnabled.into())
654 }
655 }
656 }
657
658 #[allow(clippy::too_many_arguments)]
659 fn create_with_position(
660 &self,
661 inner: &BasicHandler,
662 txn: &mut Transaction,
663 tree_id: TreeID,
664 parent: TreeParentId,
665 index: usize,
666 position: FractionalIndex,
667 ) -> LoroResult<TreeID> {
668 txn.apply_local_op(
669 inner.container_idx,
670 crate::op::RawOpContent::Tree(Arc::new(TreeOp::Create {
671 target: tree_id,
672 parent: parent.tree_id(),
673 position: position.clone(),
674 })),
675 EventHint::Tree(smallvec![TreeDiffItem {
676 target: tree_id,
677 action: TreeExternalDiff::Create {
678 parent,
679 index,
680 position,
681 },
682 }]),
683 &inner.doc,
684 )?;
685 Ok(tree_id)
686 }
687
688 #[allow(clippy::too_many_arguments)]
689 fn mov_with_position(
690 &self,
691 inner: &BasicHandler,
692 txn: &mut Transaction,
693 target: TreeID,
694 parent: TreeParentId,
695 index: usize,
696 position: FractionalIndex,
697 old_index: usize,
698 ) -> LoroResult<()> {
699 txn.apply_local_op(
700 inner.container_idx,
701 crate::op::RawOpContent::Tree(Arc::new(TreeOp::Move {
702 target,
703 parent: parent.tree_id(),
704 position: position.clone(),
705 })),
706 EventHint::Tree(smallvec![TreeDiffItem {
707 target,
708 action: TreeExternalDiff::Move {
709 parent,
710 index,
711 position,
712 old_parent: self.get_node_parent(&target).unwrap(),
713 old_index,
714 },
715 }]),
716 &inner.doc,
717 )
718 }
719
720 pub fn get_meta(&self, target: TreeID) -> LoroResult<MapHandler> {
721 match &self.inner {
722 MaybeDetached::Detached(d) => {
723 let d = d.lock().unwrap();
724 d.value
725 .map
726 .get(&target)
727 .cloned()
728 .ok_or(LoroTreeError::TreeNodeNotExist(target).into())
729 }
730 MaybeDetached::Attached(a) => {
731 if self.is_node_unexist(&target) {
732 return Err(LoroTreeError::TreeNodeNotExist(target).into());
733 }
734 let map_container_id = target.associated_meta_container();
735 let handler = create_handler(a, map_container_id);
736 Ok(handler.into_map().unwrap())
737 }
738 }
739 }
740
741 pub fn is_node_unexist(&self, target: &TreeID) -> bool {
742 match &self.inner {
743 MaybeDetached::Detached(d) => {
744 let d = d.lock().unwrap();
745 !d.value.map.contains_key(target)
746 }
747 MaybeDetached::Attached(a) => a.with_state(|state| {
748 let a = state.as_tree_state().unwrap();
749 a.is_node_unexist(target)
750 }),
751 }
752 }
753
754 pub fn is_node_deleted(&self, target: &TreeID) -> LoroResult<bool> {
755 match &self.inner {
756 MaybeDetached::Detached(t) => {
757 let t = t.lock().unwrap();
758 t.value
759 .map
760 .get(target)
761 .and(Some(true))
762 .ok_or(LoroTreeError::TreeNodeNotExist(*target).into())
763 }
764 MaybeDetached::Attached(a) => a.with_state(|state| {
765 let a = state.as_tree_state().unwrap();
766 a.is_node_deleted(target)
767 .ok_or(LoroTreeError::TreeNodeNotExist(*target).into())
768 }),
769 }
770 }
771
772 pub fn get_node_parent(&self, target: &TreeID) -> Option<TreeParentId> {
774 match &self.inner {
775 MaybeDetached::Detached(t) => {
776 let t = t.lock().unwrap();
777 t.value.get_parent(target).map(TreeParentId::from)
778 }
779 MaybeDetached::Attached(a) => a.with_state(|state| {
780 let a = state.as_tree_state().unwrap();
781 a.parent(target)
782 }),
783 }
784 }
785
786 pub fn children(&self, parent: &TreeParentId) -> Option<Vec<TreeID>> {
788 match &self.inner {
789 MaybeDetached::Detached(t) => {
790 let t = t.lock().unwrap();
791 t.value.get_children(parent.tree_id())
792 }
793 MaybeDetached::Attached(a) => a.with_state(|state| {
794 let a = state.as_tree_state().unwrap();
795 a.get_children(parent).map(|x| x.collect())
796 }),
797 }
798 }
799
800 pub fn children_num(&self, parent: &TreeParentId) -> Option<usize> {
801 match &self.inner {
802 MaybeDetached::Detached(t) => {
803 let t = t.lock().unwrap();
804 t.value.children_num(parent.tree_id())
805 }
806 MaybeDetached::Attached(a) => a.with_state(|state| {
807 let a = state.as_tree_state().unwrap();
808 a.children_num(parent)
809 }),
810 }
811 }
812
813 pub fn contains(&self, target: TreeID) -> bool {
815 match &self.inner {
816 MaybeDetached::Detached(t) => {
817 let t = t.lock().unwrap();
818 t.value.map.contains_key(&target)
819 }
820 MaybeDetached::Attached(a) => a.with_state(|state| {
821 let a = state.as_tree_state().unwrap();
822 !a.is_node_unexist(&target)
823 }),
824 }
825 }
826
827 pub fn get_child_at(&self, parent: &TreeParentId, index: usize) -> Option<TreeID> {
828 match &self.inner {
829 MaybeDetached::Detached(t) => {
830 let t = t.lock().unwrap();
831 t.value.get_id_by_index(&parent.tree_id(), index)
832 }
833 MaybeDetached::Attached(a) => a.with_state(|state| {
834 let a = state.as_tree_state().unwrap();
835 a.get_id_by_index(parent, index)
836 }),
837 }
838 }
839
840 pub fn is_parent(&self, target: &TreeID, parent: &TreeParentId) -> bool {
841 match &self.inner {
842 MaybeDetached::Detached(t) => {
843 let t = t.lock().unwrap();
844 t.value.is_parent(target, &parent.tree_id())
845 }
846 MaybeDetached::Attached(a) => a.with_state(|state| {
847 let a = state.as_tree_state().unwrap();
848 a.is_parent(target, parent)
849 }),
850 }
851 }
852
853 pub fn nodes(&self) -> Vec<TreeID> {
855 match &self.inner {
856 MaybeDetached::Detached(t) => {
857 let t = t.lock().unwrap();
858 t.value.map.keys().cloned().collect()
859 }
860 MaybeDetached::Attached(a) => a.with_state(|state| {
861 let a = state.as_tree_state().unwrap();
862 a.nodes()
863 }),
864 }
865 }
866
867 pub fn get_nodes_under(&self, parent: TreeParentId) -> Vec<TreeNode> {
868 match &self.inner {
869 MaybeDetached::Detached(_t) => {
870 unreachable!()
871 }
872 MaybeDetached::Attached(a) => a.with_state(|state| {
873 let a = state.as_tree_state().unwrap();
874 a.get_all_tree_nodes_under(parent)
875 }),
876 }
877 }
878 pub fn roots(&self) -> Vec<TreeID> {
879 self.children(&TreeParentId::Root).unwrap_or_default()
880 }
881
882 pub fn get_all_hierarchy_nodes_under(&self, parent: TreeParentId) -> Vec<TreeNodeWithChildren> {
883 match &self.inner {
884 MaybeDetached::Detached(_t) => {
885 unimplemented!()
887 }
888 MaybeDetached::Attached(a) => a.with_state(|state| {
889 let a = state.as_tree_state().unwrap();
890 a.get_all_hierarchy_nodes_under(parent)
891 }),
892 }
893 }
894
895 #[allow(non_snake_case)]
896 pub fn __internal__next_tree_id(&self) -> TreeID {
897 match &self.inner {
898 MaybeDetached::Detached(d) => {
899 let d = d.lock().unwrap();
900 TreeID::new(PeerID::MAX, d.value.next_counter)
901 }
902 MaybeDetached::Attached(a) => a
903 .with_txn(|txn| Ok(TreeID::from_id(txn.next_id())))
904 .unwrap(),
905 }
906 }
907
908 fn generate_position_at(
909 &self,
910 target: &TreeID,
911 parent: &TreeParentId,
912 index: usize,
913 cfg: FiIfNotConfigured,
914 ) -> FractionalIndexGenResult {
915 let MaybeDetached::Attached(a) = &self.inner else {
916 unreachable!()
917 };
918 a.with_state(|state| {
919 let a = state.as_tree_state_mut().unwrap();
920 a.generate_position_at(target, parent, index, cfg)
921 })
922 }
923
924 pub fn get_index_by_tree_id(&self, target: &TreeID) -> Option<usize> {
928 match &self.inner {
929 MaybeDetached::Detached(t) => {
930 let t = t.lock().unwrap();
931 t.value.get_index_by_tree_id(target)
932 }
933 MaybeDetached::Attached(a) => a.with_state(|state| {
934 let a = state.as_tree_state().unwrap();
935 a.get_index_by_tree_id(target)
936 }),
937 }
938 }
939
940 pub fn get_position_by_tree_id(&self, target: &TreeID) -> Option<FractionalIndex> {
941 match &self.inner {
942 MaybeDetached::Detached(_) => unreachable!(),
943 MaybeDetached::Attached(a) => a.with_state(|state| {
944 let a = state.as_tree_state().unwrap();
945 a.get_position(target)
946 }),
947 }
948 }
949
950 fn delete_position(&self, parent: &TreeParentId, target: &TreeID) {
951 let MaybeDetached::Attached(a) = &self.inner else {
952 unreachable!()
953 };
954 a.with_state(|state| {
955 let a = state.as_tree_state_mut().unwrap();
956 a.try_delete_position_cache(parent, target)
957 })
958 }
959
960 pub(crate) fn get_index_by_fractional_index(
962 &self,
963 parent: &TreeParentId,
964 node_position: &NodePosition,
965 ) -> Option<usize> {
966 match &self.inner {
967 MaybeDetached::Detached(_) => {
968 unreachable!();
969 }
970 MaybeDetached::Attached(a) => a.with_state(|state| {
971 let a = state.as_tree_state().unwrap();
972 a.get_index_by_position(parent, node_position)
973 }),
974 }
975 }
976
977 pub(crate) fn next_idlp(&self) -> IdLp {
978 match &self.inner {
979 MaybeDetached::Detached(_) => {
980 unreachable!()
981 }
982 MaybeDetached::Attached(a) => a.with_txn(|txn| Ok(txn.next_idlp())).unwrap(),
983 }
984 }
985
986 pub fn is_fractional_index_enabled(&self) -> bool {
987 match &self.inner {
988 MaybeDetached::Detached(_) => {
989 unreachable!()
990 }
991 MaybeDetached::Attached(a) => a.with_state(|state| {
992 let a = state.as_tree_state().unwrap();
993 a.is_fractional_index_enabled()
994 }),
995 }
996 }
997
998 pub fn enable_fractional_index(&self, jitter: u8) {
1006 match &self.inner {
1007 MaybeDetached::Detached(_) => {
1008 unreachable!()
1009 }
1010 MaybeDetached::Attached(a) => a.with_state(|state| {
1011 let a = state.as_tree_state_mut().unwrap();
1012 a.enable_generate_fractional_index(jitter);
1013 }),
1014 }
1015 }
1016
1017 pub fn disable_fractional_index(&self) {
1022 match &self.inner {
1023 MaybeDetached::Detached(_) => {
1024 unreachable!()
1025 }
1026 MaybeDetached::Attached(a) => a.with_state(|state| {
1027 let a = state.as_tree_state_mut().unwrap();
1028 a.disable_generate_fractional_index();
1029 }),
1030 }
1031 }
1032
1033 pub fn is_deleted(&self) -> bool {
1034 match &self.inner {
1035 MaybeDetached::Detached(_) => false,
1036 MaybeDetached::Attached(a) => a.is_deleted(),
1037 }
1038 }
1039
1040 pub fn is_empty(&self) -> bool {
1041 match &self.inner {
1042 MaybeDetached::Detached(t) => {
1043 let t = t.lock().unwrap();
1044 t.value.map.is_empty()
1045 }
1046 MaybeDetached::Attached(a) => a.with_state(|state| {
1047 let a = state.as_tree_state().unwrap();
1048 a.is_empty()
1049 }),
1050 }
1051 }
1052
1053 pub fn get_last_move_id(&self, target: &TreeID) -> Option<ID> {
1054 match &self.inner {
1055 MaybeDetached::Detached(_) => None,
1056 MaybeDetached::Attached(a) => a.with_state(|state| {
1057 let a = state.as_tree_state().unwrap();
1058 a.get_last_move_id(target)
1059 }),
1060 }
1061 }
1062
1063 pub fn clear(&self) -> LoroResult<()> {
1064 match &self.inner {
1065 MaybeDetached::Detached(t) => {
1066 let mut t = t.lock().unwrap();
1067 t.value.map.clear();
1068 t.value.children_links.clear();
1069 t.value.parent_links.clear();
1070 Ok(())
1071 }
1072 MaybeDetached::Attached(_) => {
1073 let nodes = self.get_nodes_under(TreeParentId::Root);
1074 for node in nodes {
1075 self.delete(node.id)?;
1076 }
1077 Ok(())
1078 }
1079 }
1080 }
1081}