1use std::cell::RefCell;
42use std::collections::{HashMap, HashSet};
43use std::rc::Rc;
44
45use teksilo_core::ObserverHandle;
46use teksilo_core::signal::Signal;
47
48use crate::TreeModel;
49use crate::dnd_types::{DragEligibility, DragSource, DropCommit, DropQuery, DropResponse};
50use crate::tree_change::{NodeId, TreeChange};
51use crate::tree_data_source::{
52 FlatEntry, TreeDataSource, tree_apply_reorder, tree_is_desc_or_self,
53};
54
55pub struct TreeSlice<T: 'static> {
62 tree: TreeModel<T>,
63 expanded: Rc<RefCell<HashSet<NodeId>>>,
64 flattened: Rc<RefCell<Vec<FlatEntry>>>,
65 positions: Rc<RefCell<HashMap<NodeId, usize>>>,
69 version: Signal<u64>,
70 version_counter: Rc<std::cell::Cell<u64>>,
71 divergence: Rc<std::cell::Cell<Option<usize>>>,
74 _tree_observer: ObserverHandle,
75}
76
77impl<T: 'static> TreeSlice<T> {
78 pub fn new(tree: TreeModel<T>) -> Self {
81 let expanded: Rc<RefCell<HashSet<NodeId>>> = Rc::new(RefCell::new(HashSet::new()));
82 let flattened: Rc<RefCell<Vec<FlatEntry>>> = Rc::new(RefCell::new(Vec::new()));
83 let positions: Rc<RefCell<HashMap<NodeId, usize>>> = Rc::new(RefCell::new(HashMap::new()));
84 let version = Signal::new(0_u64);
85 let version_counter = Rc::new(std::cell::Cell::new(0_u64));
86 let divergence = Rc::new(std::cell::Cell::new(None));
87
88 Self::rebuild_flat_list(
90 &tree,
91 &expanded.borrow(),
92 &mut flattened.borrow_mut(),
93 &mut positions.borrow_mut(),
94 );
95
96 let exp = expanded.clone();
98 let flat = flattened.clone();
99 let pos = positions.clone();
100 let tree_for_obs = tree.clone();
101 let ver = version.clone();
102 let vc = version_counter.clone();
103 let div = divergence.clone();
104 let observer = tree.observe_changes(move |change| {
105 let mut d = Self::rebuild_flat_list(
106 &tree_for_obs,
107 &exp.borrow(),
108 &mut flat.borrow_mut(),
109 &mut pos.borrow_mut(),
110 );
111 if let TreeChange::NodeUpdated { node } = change
116 && let Some(&p) = pos.borrow().get(node)
117 {
118 d = d.min(p);
119 }
120 div.set(Some(d));
121 let next = vc.get() + 1;
122 vc.set(next);
123 ver.set(next);
124 });
125
126 Self {
127 tree,
128 expanded,
129 flattened,
130 positions,
131 version,
132 version_counter,
133 divergence,
134 _tree_observer: observer,
135 }
136 }
137
138 pub fn visible_count(&self) -> usize {
140 self.flattened.borrow().len()
141 }
142
143 pub fn with_entry<R>(
146 &self,
147 flat_index: usize,
148 f: impl FnOnce(&T, &FlatEntry) -> R,
149 ) -> Option<R> {
150 let flat = self.flattened.borrow();
151 let entry = flat.get(flat_index)?;
152 let node_id = entry.node_id;
153 self.tree.with_item(node_id, |item| f(item, entry))
156 }
157
158 pub fn visible_node_id(&self, flat_index: usize) -> Option<NodeId> {
160 self.flattened.borrow().get(flat_index).map(|e| e.node_id)
161 }
162
163 pub fn entry_at(&self, flat_index: usize) -> Option<FlatEntry> {
165 self.flattened.borrow().get(flat_index).cloned()
166 }
167
168 pub fn depth_at(&self, flat_index: usize) -> usize {
170 self.flattened
171 .borrow()
172 .get(flat_index)
173 .map(|e| e.depth)
174 .unwrap_or(0)
175 }
176
177 pub fn flat_index_of(&self, node: NodeId) -> Option<usize> {
180 self.positions.borrow().get(&node).copied()
181 }
182
183 pub fn is_expanded(&self, node: NodeId) -> bool {
187 self.expanded.borrow().contains(&node)
188 }
189
190 pub fn expand(&self, node: NodeId) {
192 {
193 let mut exp = self.expanded.borrow_mut();
194 if !exp.insert(node) {
195 return; }
197 }
198 self.reflatten_and_notify();
199 }
200
201 pub fn collapse(&self, node: NodeId) {
203 {
204 let mut exp = self.expanded.borrow_mut();
205 if !exp.remove(&node) {
206 return; }
208 }
209 self.reflatten_and_notify();
210 }
211
212 pub fn toggle(&self, node: NodeId) {
214 {
215 let mut exp = self.expanded.borrow_mut();
216 if exp.contains(&node) {
217 exp.remove(&node);
218 } else {
219 exp.insert(node);
220 }
221 }
222 self.reflatten_and_notify();
223 }
224
225 pub fn expand_all(&self) {
227 {
228 let mut exp = self.expanded.borrow_mut();
229 self.expand_all_recursive(&mut exp);
230 }
231 self.reflatten_and_notify();
232 }
233
234 pub fn collapse_all(&self) {
236 {
237 let mut exp = self.expanded.borrow_mut();
238 exp.clear();
239 }
240 self.reflatten_and_notify();
241 }
242
243 pub fn expanded_nodes(&self) -> Vec<NodeId> {
245 self.expanded.borrow().iter().copied().collect()
246 }
247
248 pub fn set_expanded_nodes(&self, nodes: &[NodeId]) {
250 {
251 let mut exp = self.expanded.borrow_mut();
252 exp.clear();
253 for &node in nodes {
254 exp.insert(node);
255 }
256 }
257 self.reflatten_and_notify();
258 }
259
260 pub fn version_signal(&self) -> Signal<u64> {
262 self.version.clone()
263 }
264
265 pub fn first_changed_index(&self) -> Option<usize> {
276 self.divergence.get()
277 }
278
279 pub fn tree(&self) -> &TreeModel<T> {
281 &self.tree
282 }
283
284 pub fn handle(&self) -> TreeSliceHandle<T> {
287 TreeSliceHandle {
288 tree: self.tree.clone(),
289 expanded: self.expanded.clone(),
290 flattened: self.flattened.clone(),
291 positions: self.positions.clone(),
292 version: self.version.clone(),
293 version_counter: self.version_counter.clone(),
294 divergence: self.divergence.clone(),
295 }
296 }
297
298 fn reflatten_and_notify(&self) {
301 let d = Self::rebuild_flat_list(
302 &self.tree,
303 &self.expanded.borrow(),
304 &mut self.flattened.borrow_mut(),
305 &mut self.positions.borrow_mut(),
306 );
307 self.divergence.set(Some(d));
308 let next = self.version_counter.get() + 1;
309 self.version_counter.set(next);
310 self.version.set(next);
311 }
312
313 fn expand_all_recursive(&self, expanded: &mut HashSet<NodeId>) {
314 let root_count = self.tree.root_count();
316 for i in 0..root_count {
317 let root = self.tree.root(i);
318 Self::expand_subtree_recursive(&self.tree, root, expanded);
319 }
320 }
321
322 fn expand_subtree_recursive(tree: &TreeModel<T>, root: NodeId, expanded: &mut HashSet<NodeId>) {
325 let mut stack = vec![root];
326 while let Some(node) = stack.pop() {
327 if tree.has_children(node) {
328 expanded.insert(node);
329 for child in tree.children(node) {
330 stack.push(child);
331 }
332 }
333 }
334 }
335
336 fn rebuild_flat_list(
343 tree: &TreeModel<T>,
344 expanded: &HashSet<NodeId>,
345 out: &mut Vec<FlatEntry>,
346 pos: &mut HashMap<NodeId, usize>,
347 ) -> usize {
348 let old = std::mem::take(out);
349 out.reserve(old.len());
350 let root_count = tree.root_count();
351 for i in 0..root_count {
352 let root = tree.root(i);
353 Self::flatten_node(tree, root, 0, expanded, out);
354 }
355 pos.clear();
356 pos.extend(out.iter().enumerate().map(|(i, e)| (e.node_id, i)));
357 old.iter()
358 .zip(out.iter())
359 .take_while(|(a, b)| a == b)
360 .count()
361 }
362
363 fn flatten_node(
367 tree: &TreeModel<T>,
368 root: NodeId,
369 depth: usize,
370 expanded: &HashSet<NodeId>,
371 out: &mut Vec<FlatEntry>,
372 ) {
373 let mut stack = vec![(root, depth)];
374 while let Some((node, depth)) = stack.pop() {
375 let has_children = tree.has_children(node);
376 let is_expanded = expanded.contains(&node);
377
378 out.push(FlatEntry {
379 node_id: node,
380 depth,
381 has_children,
382 is_expanded,
383 });
384
385 if is_expanded && has_children {
386 for child in tree.children(node).into_iter().rev() {
387 stack.push((child, depth + 1));
388 }
389 }
390 }
391 }
392}
393
394impl<T: 'static> std::fmt::Debug for TreeSlice<T> {
395 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
396 f.debug_struct("TreeSlice")
397 .field("visible_count", &self.visible_count())
398 .field("expanded_count", &self.expanded.borrow().len())
399 .finish()
400 }
401}
402
403pub struct TreeSliceHandle<T: 'static> {
410 tree: TreeModel<T>,
411 expanded: Rc<RefCell<HashSet<NodeId>>>,
412 flattened: Rc<RefCell<Vec<FlatEntry>>>,
413 positions: Rc<RefCell<HashMap<NodeId, usize>>>,
414 version: Signal<u64>,
415 version_counter: Rc<std::cell::Cell<u64>>,
416 divergence: Rc<std::cell::Cell<Option<usize>>>,
417}
418
419impl<T: 'static> TreeSliceHandle<T> {
420 pub fn visible_count(&self) -> usize {
422 self.flattened.borrow().len()
423 }
424
425 pub fn entry_at(&self, flat_index: usize) -> Option<FlatEntry> {
427 self.flattened.borrow().get(flat_index).cloned()
428 }
429
430 pub fn visible_node_id(&self, flat_index: usize) -> Option<NodeId> {
432 self.flattened.borrow().get(flat_index).map(|e| e.node_id)
433 }
434
435 pub fn expand(&self, node: NodeId) {
438 let inserted = self.expanded.borrow_mut().insert(node);
439 if inserted {
440 self.reflatten_and_notify();
441 }
442 }
443
444 pub fn collapse(&self, node: NodeId) {
447 let removed = self.expanded.borrow_mut().remove(&node);
448 if removed {
449 self.reflatten_and_notify();
450 }
451 }
452
453 pub fn is_expanded(&self, node: NodeId) -> bool {
455 self.expanded.borrow().contains(&node)
456 }
457
458 pub fn toggle_expand(&self, node: NodeId) {
460 {
461 let mut exp = self.expanded.borrow_mut();
462 if exp.contains(&node) {
463 exp.remove(&node);
464 } else {
465 exp.insert(node);
466 }
467 }
468 self.reflatten_and_notify();
469 }
470
471 pub fn tree(&self) -> &TreeModel<T> {
473 &self.tree
474 }
475
476 pub fn expand_all(&self) {
480 {
481 let mut exp = self.expanded.borrow_mut();
482 let root_count = self.tree.root_count();
483 for i in 0..root_count {
484 let root = self.tree.root(i);
485 TreeSlice::<T>::expand_subtree_recursive(&self.tree, root, &mut exp);
486 }
487 }
488 self.reflatten_and_notify();
489 }
490
491 pub fn first_changed_index(&self) -> Option<usize> {
493 self.divergence.get()
494 }
495
496 fn reflatten_and_notify(&self) {
497 let d = TreeSlice::<T>::rebuild_flat_list(
498 &self.tree,
499 &self.expanded.borrow(),
500 &mut self.flattened.borrow_mut(),
501 &mut self.positions.borrow_mut(),
502 );
503 self.divergence.set(Some(d));
504 let next = self.version_counter.get() + 1;
505 self.version_counter.set(next);
506 self.version.set(next);
507 }
508}
509
510impl<T: 'static> Clone for TreeSliceHandle<T> {
511 fn clone(&self) -> Self {
512 Self {
513 tree: self.tree.clone(),
514 expanded: self.expanded.clone(),
515 flattened: self.flattened.clone(),
516 positions: self.positions.clone(),
517 version: self.version.clone(),
518 version_counter: self.version_counter.clone(),
519 divergence: self.divergence.clone(),
520 }
521 }
522}
523
524impl<T: 'static> TreeDataSource for TreeSlice<T> {
529 type Item = T;
530 type Key = NodeId;
531
532 fn visible_count(&self) -> usize {
533 TreeSlice::visible_count(self)
534 }
535
536 fn with_entry<R>(
537 &self,
538 flat_index: usize,
539 f: impl FnOnce(&Self::Item, &FlatEntry<Self::Key>) -> R,
540 ) -> Option<R> {
541 TreeSlice::with_entry(self, flat_index, f)
542 }
543
544 fn key_at(&self, flat_index: usize) -> Option<NodeId> {
545 self.visible_node_id(flat_index)
546 }
547
548 fn flat_index_of(&self, key: &NodeId) -> Option<usize> {
549 TreeSlice::flat_index_of(self, *key)
550 }
551
552 fn parent(&self, key: &NodeId) -> Option<NodeId> {
553 self.tree().parent(*key)
554 }
555
556 fn child_keys(&self, key: &NodeId) -> Vec<NodeId> {
557 self.tree().children(*key)
558 }
559
560 fn version_signal(&self) -> Signal<u64> {
561 TreeSlice::version_signal(self)
562 }
563
564 fn first_changed_index(&self) -> Option<usize> {
565 TreeSlice::first_changed_index(self)
566 }
567
568 fn contains_key(&self, key: &NodeId) -> bool {
569 self.tree().with_item(*key, |_| ()).is_some()
572 }
573
574 fn is_expanded(&self, key: &NodeId) -> bool {
575 TreeSlice::is_expanded(self, *key)
576 }
577
578 fn set_expanded(&self, key: &NodeId, expanded: bool) {
579 if expanded {
580 self.expand(*key);
581 } else {
582 self.collapse(*key);
583 }
584 }
585
586 fn drag(&self, _key: &NodeId) -> DragEligibility {
587 DragEligibility::CanDrag
588 }
589
590 fn can_accept(&self, query: &DropQuery<'_, NodeId>) -> DropResponse {
591 match &query.source {
592 DragSource::SameView { key: source } => {
593 if *source == query.target
594 || tree_is_desc_or_self(self.tree(), query.target, *source)
595 {
596 DropResponse::Reject
597 } else {
598 DropResponse::Accept
599 }
600 }
601 DragSource::Foreign { .. } => DropResponse::Reject,
602 }
603 }
604
605 fn accept_drop(&self, commit: DropCommit<'_, NodeId>) -> bool {
606 match commit.source {
607 DragSource::SameView { key: source } => {
608 tree_apply_reorder(self.tree(), source, commit.target, commit.position)
609 }
610 DragSource::Foreign { .. } => false,
611 }
612 }
613
614 fn on_drag_out(&self, key: &NodeId) {
615 if self.tree().with_item(*key, |_| ()).is_some() {
621 self.tree().remove(*key);
622 }
623 }
624}
625
626#[cfg(test)]
627mod tests {
628 use super::*;
629 use crate::dnd_types::DropPosition;
630
631 fn sample_tree() -> TreeModel<&'static str> {
640 let tree = TreeModel::new();
641 let a = tree.insert_root(0, "A");
642 let a1 = tree.insert_child(a, 0, "A1");
643 tree.insert_child(a1, 0, "A1a");
644 tree.insert_child(a, 1, "A2");
645 let b = tree.insert_root(1, "B");
646 tree.insert_child(b, 0, "B1");
647 tree.insert_root(2, "C");
648 tree
649 }
650
651 #[test]
652 fn initial_state_shows_only_roots() {
653 let tree = sample_tree();
654 let slice = TreeSlice::new(tree);
655
656 assert_eq!(slice.visible_count(), 3); assert_eq!(
658 slice.with_entry(0, |item, entry| {
659 assert_eq!(*item, "A");
660 assert_eq!(entry.depth, 0);
661 assert!(entry.has_children);
662 assert!(!entry.is_expanded);
663 }),
664 Some(())
665 );
666 assert_eq!(slice.with_entry(1, |item, _| *item), Some("B"));
667 assert_eq!(slice.with_entry(2, |item, _| *item), Some("C"));
668 }
669
670 #[test]
671 fn expand_shows_children() {
672 let tree = sample_tree();
673 let a = tree.root(0);
674 let slice = TreeSlice::new(tree);
675
676 assert_eq!(slice.visible_count(), 3);
677
678 slice.expand(a);
679 assert_eq!(slice.visible_count(), 5); assert_eq!(slice.with_entry(0, |item, _| *item), Some("A"));
682 assert_eq!(
683 slice.with_entry(1, |item, entry| {
684 assert_eq!(*item, "A1");
685 assert_eq!(entry.depth, 1);
686 assert!(entry.has_children); }),
688 Some(())
689 );
690 assert_eq!(slice.with_entry(2, |item, _| *item), Some("A2"));
691 assert_eq!(slice.with_entry(3, |item, _| *item), Some("B"));
692 }
693
694 #[test]
695 fn collapse_hides_children() {
696 let tree = sample_tree();
697 let a = tree.root(0);
698 let slice = TreeSlice::new(tree);
699
700 slice.expand(a);
701 assert_eq!(slice.visible_count(), 5);
702
703 slice.collapse(a);
704 assert_eq!(slice.visible_count(), 3);
705 }
706
707 #[test]
708 fn deep_expand() {
709 let tree = sample_tree();
710 let a = tree.root(0);
711 let slice = TreeSlice::new(tree.clone());
712
713 slice.expand(a);
714 let a1 = slice.visible_node_id(1).unwrap();
715 slice.expand(a1);
716
717 assert_eq!(slice.visible_count(), 6);
719 assert_eq!(
720 slice.with_entry(2, |item, entry| {
721 assert_eq!(*item, "A1a");
722 assert_eq!(entry.depth, 2);
723 }),
724 Some(())
725 );
726 }
727
728 #[test]
729 fn toggle() {
730 let tree = sample_tree();
731 let a = tree.root(0);
732 let slice = TreeSlice::new(tree);
733
734 slice.toggle(a);
735 assert_eq!(slice.visible_count(), 5); assert!(slice.is_expanded(a));
737
738 slice.toggle(a);
739 assert_eq!(slice.visible_count(), 3); assert!(!slice.is_expanded(a));
741 }
742
743 #[test]
744 fn expand_all() {
745 let tree = sample_tree();
746 let slice = TreeSlice::new(tree);
747
748 slice.expand_all();
749 assert_eq!(slice.visible_count(), 7);
751 }
752
753 #[test]
754 fn collapse_all() {
755 let tree = sample_tree();
756 let slice = TreeSlice::new(tree);
757
758 slice.expand_all();
759 assert_eq!(slice.visible_count(), 7);
760
761 slice.collapse_all();
762 assert_eq!(slice.visible_count(), 3);
763 }
764
765 #[test]
766 fn handle_expand_all_matches_slice() {
767 let tree = sample_tree();
768 let slice = TreeSlice::new(tree);
769 let handle = slice.handle();
770
771 assert_eq!(slice.visible_count(), 3); handle.expand_all();
773 assert_eq!(slice.visible_count(), 7);
775 }
776
777 #[test]
778 fn two_slices_independent_expand() {
779 let tree = sample_tree();
780 let a = tree.root(0);
781 let b = tree.root(1);
782
783 let slice1 = TreeSlice::new(tree.clone());
784 let slice2 = TreeSlice::new(tree);
785
786 slice1.expand(a);
787 slice2.expand(b);
788
789 assert_eq!(slice1.visible_count(), 5); assert!(slice1.is_expanded(a));
792 assert!(!slice1.is_expanded(b));
793
794 assert_eq!(slice2.visible_count(), 4); assert!(!slice2.is_expanded(a));
797 assert!(slice2.is_expanded(b));
798 }
799
800 #[test]
801 fn tree_mutation_updates_slice() {
802 let tree = sample_tree();
803 let a = tree.root(0);
804 let slice = TreeSlice::new(tree.clone());
805
806 slice.expand(a);
807 assert_eq!(slice.visible_count(), 5); tree.insert_child(a, 2, "A3");
811 assert_eq!(slice.visible_count(), 6); }
813
814 #[test]
815 fn tree_remove_updates_slice() {
816 let tree = sample_tree();
817 let a = tree.root(0);
818 let slice = TreeSlice::new(tree.clone());
819
820 slice.expand(a);
821 let a1 = slice.visible_node_id(1).unwrap();
822 tree.remove(a1);
823
824 assert_eq!(slice.visible_count(), 4); }
826
827 #[test]
828 fn version_signal_increments() {
829 let tree = sample_tree();
830 let a = tree.root(0);
831 let slice = TreeSlice::new(tree.clone());
832
833 let v0 = slice.version_signal().get();
834
835 slice.expand(a);
836 let v1 = slice.version_signal().get();
837 assert!(v1 > v0, "version should increment on expand");
838
839 tree.insert_root(3, "D");
840 let v2 = slice.version_signal().get();
841 assert!(v2 > v1, "version should increment on tree mutation");
842 }
843
844 #[test]
845 fn flat_index_of() {
846 let tree = sample_tree();
847 let a = tree.root(0);
848 let b = tree.root(1);
849 let slice = TreeSlice::new(tree);
850
851 assert_eq!(slice.flat_index_of(a), Some(0));
852 assert_eq!(slice.flat_index_of(b), Some(1));
853 }
854
855 fn assert_positions_match_iteration_order<T>(slice: &TreeSlice<T>) {
860 for i in 0..slice.visible_count() {
861 let node = slice.visible_node_id(i).unwrap();
862 assert_eq!(
863 slice.flat_index_of(node),
864 Some(i),
865 "flat_index_of({node:?}) should be the iteration position {i}"
866 );
867 }
868 }
869
870 #[test]
871 fn flat_index_of_matches_iteration_order_across_mutations() {
872 let tree = sample_tree();
873 let a = tree.root(0);
874 let b = tree.root(1);
875 let slice = TreeSlice::new(tree.clone());
876
877 assert_positions_match_iteration_order(&slice);
878
879 slice.expand(a);
880 assert_positions_match_iteration_order(&slice);
881
882 slice.expand(b);
883 assert_positions_match_iteration_order(&slice);
884
885 slice.collapse(a);
886 assert_positions_match_iteration_order(&slice);
887
888 tree.insert_root(3, "D");
889 assert_positions_match_iteration_order(&slice);
890
891 tree.remove(b);
892 assert_positions_match_iteration_order(&slice);
893 }
894
895 #[test]
896 fn persistence_save_restore() {
897 let tree = sample_tree();
898 let a = tree.root(0);
899 let slice = TreeSlice::new(tree.clone());
900
901 slice.expand(a);
902 let saved = slice.expanded_nodes();
903 assert_eq!(saved.len(), 1);
904
905 slice.collapse_all();
906 assert_eq!(slice.visible_count(), 3);
907
908 slice.set_expanded_nodes(&saved);
909 assert_eq!(slice.visible_count(), 5); }
911
912 #[test]
913 fn out_of_bounds_returns_none() {
914 let tree = sample_tree();
915 let slice = TreeSlice::new(tree);
916 assert_eq!(slice.with_entry(99, |_, _| ()), None);
917 assert_eq!(slice.visible_node_id(99), None);
918 }
919
920 #[test]
923 fn divergence_unknown_before_first_reflatten() {
924 let tree = sample_tree();
925 let slice = TreeSlice::new(tree);
926 assert_eq!(slice.first_changed_index(), None);
927 }
928
929 #[test]
930 fn divergence_on_expand_is_the_toggled_row() {
931 let tree = sample_tree();
932 let b = tree.root(1);
933 let slice = TreeSlice::new(tree);
934
935 slice.expand(b);
938 assert_eq!(slice.first_changed_index(), Some(1));
939
940 slice.collapse(b);
941 assert_eq!(slice.first_changed_index(), Some(1));
942 }
943
944 #[test]
945 fn divergence_on_append_is_old_len() {
946 let tree = sample_tree();
947 let slice = TreeSlice::new(tree.clone());
948
949 tree.insert_root(3, "D"); assert_eq!(slice.first_changed_index(), Some(3));
951 }
952
953 #[test]
954 fn divergence_on_remove_is_removed_position() {
955 let tree = sample_tree();
956 let b = tree.root(1);
957 let slice = TreeSlice::new(tree.clone());
958
959 tree.remove(b); assert_eq!(slice.first_changed_index(), Some(1));
961 }
962
963 #[test]
964 fn divergence_on_node_update_is_its_flat_index() {
965 let tree = sample_tree();
966 let c = tree.root(2);
967 let slice = TreeSlice::new(tree.clone());
968
969 tree.update(c, "C-updated");
971 assert_eq!(slice.first_changed_index(), Some(2));
972 }
973
974 #[test]
975 fn divergence_on_invisible_update_is_visible_count() {
976 let tree = sample_tree();
977 let a = tree.root(0);
978 let a1 = tree.children(a)[0];
979 let slice = TreeSlice::new(tree.clone());
980
981 tree.update(a1, "A1-updated");
983 assert_eq!(slice.first_changed_index(), Some(slice.visible_count()));
984 }
985
986 #[test]
987 fn divergence_via_handle_toggle() {
988 let tree = sample_tree();
989 let b = tree.root(1);
990 let slice = TreeSlice::new(tree);
991 let handle = slice.handle();
992
993 handle.toggle_expand(b);
994 assert_eq!(handle.first_changed_index(), Some(1));
995 assert_eq!(slice.first_changed_index(), Some(1));
996 }
997
998 #[test]
1001 fn tree_source_accept_drop_reparents_into() {
1002 let tree = sample_tree();
1004 let a = tree.root(0);
1005 let b = tree.root(1);
1006 let slice = TreeSlice::new(tree.clone());
1007 assert!(slice.accept_drop(DropCommit {
1008 source: DragSource::SameView { key: b },
1009 target: a,
1010 position: DropPosition::Into,
1011 }));
1012 assert_eq!(tree.root_count(), 2);
1013 assert_eq!(tree.parent(b), Some(a));
1014 }
1015
1016 #[test]
1017 fn tree_source_can_accept_rejects_cycle_and_refuses_drop() {
1018 let tree = sample_tree();
1020 let a = tree.root(0);
1021 let slice = TreeSlice::new(tree.clone());
1022 slice.expand(a);
1023 let a1 = slice.visible_node_id(1).unwrap();
1024 assert_eq!(
1025 slice.can_accept(&DropQuery {
1026 source: DragSource::SameView { key: a },
1027 target: a1,
1028 position: DropPosition::Into,
1029 }),
1030 DropResponse::Reject
1031 );
1032 assert!(!slice.accept_drop(DropCommit {
1034 source: DragSource::SameView { key: a },
1035 target: a1,
1036 position: DropPosition::Into,
1037 }));
1038 }
1039
1040 #[test]
1041 fn tree_source_reorders_root_siblings() {
1042 let tree = sample_tree();
1044 let a = tree.root(0);
1045 let c = tree.root(2);
1046 let slice = TreeSlice::new(tree.clone());
1047 assert!(slice.accept_drop(DropCommit {
1048 source: DragSource::SameView { key: c },
1049 target: a,
1050 position: DropPosition::Before,
1051 }));
1052 assert_eq!(slice.with_entry(0, |v, _| *v), Some("C"));
1053 assert_eq!(slice.with_entry(1, |v, _| *v), Some("A"));
1054 assert_eq!(slice.with_entry(2, |v, _| *v), Some("B"));
1055 }
1056
1057 #[test]
1058 fn tree_reorder_within_filters_descendants_of_selected() {
1059 let tree = sample_tree();
1062 let a = tree.root(0);
1063 let c = tree.root(2);
1064 let slice = TreeSlice::new(tree.clone());
1065 let a1 = slice.child_keys(&a)[0];
1066 assert!(slice.reorder_within(&[a, a1], &c, DropPosition::After));
1067 assert_eq!(slice.with_entry(0, |v, _| *v), Some("B"));
1068 assert_eq!(slice.with_entry(1, |v, _| *v), Some("C"));
1069 assert_eq!(slice.with_entry(2, |v, _| *v), Some("A"));
1070 assert_eq!(slice.child_keys(&a).len(), 2);
1072 }
1073
1074 #[test]
1075 fn tree_on_drag_out_removes_node_and_subtree() {
1076 let tree = sample_tree();
1077 let b = tree.root(1);
1078 let slice = TreeSlice::new(tree.clone());
1079 slice.on_drag_out(&b);
1080 assert_eq!(slice.visible_count(), 2);
1082 assert_eq!(slice.with_entry(0, |v, _| *v), Some("A"));
1083 assert_eq!(slice.with_entry(1, |v, _| *v), Some("C"));
1084 }
1085
1086 #[test]
1090 fn deep_chain_flattens_and_expands_without_overflow() {
1091 const DEPTH: usize = 50_000;
1092 let tree = TreeModel::new();
1093 let root = tree.insert_root(0, 0usize);
1094 let mut leaf = root;
1095 for i in 1..DEPTH {
1096 leaf = tree.insert_child(leaf, 0, i);
1097 }
1098 let slice = TreeSlice::new(tree);
1099
1100 slice.expand_all();
1105
1106 assert_eq!(slice.visible_count(), DEPTH);
1107 assert_eq!(slice.flat_index_of(leaf), Some(DEPTH - 1));
1108 assert_eq!(slice.depth_at(DEPTH - 1), DEPTH - 1);
1109 }
1110}