1use std::cell::{RefCell, RefMut};
2use std::cmp::{max, Ordering};
3use std::collections::HashMap;
4use std::mem;
5use std::rc::{Rc, Weak};
6
7pub type MarkerId = u64;
9
10#[derive(Debug, Clone, PartialEq)]
15pub struct Interval {
16 pub start: u64,
17 pub end: u64,
18}
19
20#[derive(Debug, Clone, PartialEq)]
22pub enum MarkerType {
23 Position,
25 LineAnchor {
27 estimated_line: usize,
28 confidence: AnchorConfidence,
29 },
30}
31
32#[derive(Debug, Clone, PartialEq)]
34pub enum AnchorConfidence {
35 Exact,
37 Estimated,
39 Relative(MarkerId),
41}
42
43#[derive(Debug, Clone, PartialEq)]
44pub struct Marker {
45 pub id: MarkerId,
46 pub interval: Interval,
47 pub marker_type: MarkerType,
48 pub right_gravity: bool,
59}
60
61type NodePtr = Option<Rc<RefCell<Node>>>;
63type WeakNodePtr = Weak<RefCell<Node>>;
65
66#[derive(Debug)]
68struct Node {
69 pub marker: Marker,
70
71 pub height: i32,
73 pub max_end: u64,
75 pub lazy_delta: i64,
77
78 pub parent: WeakNodePtr,
79 pub left: NodePtr,
80 pub right: NodePtr,
81}
82
83#[derive(Debug, Default)]
85pub struct IntervalTree {
86 root: NodePtr,
87 next_id: u64,
88 marker_map: HashMap<MarkerId, Rc<RefCell<Node>>>,
90}
91
92impl Node {
97 fn new(marker: Marker, parent: WeakNodePtr) -> Rc<RefCell<Self>> {
98 let max_end_val = marker.interval.end;
100
101 Rc::new(RefCell::new(Node {
102 marker,
103 height: 1,
104 max_end: max_end_val,
105 lazy_delta: 0,
106 parent,
107 left: None,
108 right: None,
109 }))
110 }
111
112 fn height(node: &NodePtr) -> i32 {
114 node.as_ref().map_or(0, |n| n.borrow().height)
115 }
116
117 fn balance_factor(node: &Rc<RefCell<Self>>) -> i32 {
119 let n = node.borrow();
120 Self::height(&n.left) - Self::height(&n.right)
121 }
122
123 fn push_delta(node_rc: &Rc<RefCell<Self>>) {
125 let mut node = node_rc.borrow_mut();
126 if node.lazy_delta == 0 {
127 return;
128 }
129
130 let delta = node.lazy_delta;
131
132 node.marker.interval.start = (node.marker.interval.start as i64 + delta) as u64;
134 node.marker.interval.end = (node.marker.interval.end as i64 + delta) as u64;
135
136 if let Some(ref left) = node.left {
138 left.borrow_mut().lazy_delta += delta;
139 }
140 if let Some(ref right) = node.right {
141 right.borrow_mut().lazy_delta += delta;
142 }
143
144 node.lazy_delta = 0;
145
146 let max_l = node.left.as_ref().map_or(0, |l| l.borrow().max_end);
148 let max_r = node.right.as_ref().map_or(0, |r| r.borrow().max_end);
149 node.max_end = max(node.marker.interval.end, max(max_l, max_r));
150 }
151
152 fn update_stats(node: &Rc<RefCell<Self>>) {
154 let mut n = node.borrow_mut();
155 let height_l = Self::height(&n.left);
156 let height_r = Self::height(&n.right);
157
158 n.height = 1 + max(height_l, height_r);
159
160 let max_l = n.left.as_ref().map_or(0, |l| l.borrow().max_end);
161 let max_r = n.right.as_ref().map_or(0, |r| r.borrow().max_end);
162 n.max_end = max(n.marker.interval.end, max(max_l, max_r));
163 }
164}
165
166impl IntervalTree {
171 pub fn new() -> Self {
172 Self::default()
173 }
174
175 pub fn insert(&mut self, start: u64, end: u64) -> MarkerId {
177 self.insert_with_type(start, end, MarkerType::Position)
178 }
179
180 pub fn insert_left_gravity(&mut self, start: u64, end: u64) -> MarkerId {
184 self.insert_full(start, end, MarkerType::Position, false)
185 }
186
187 fn insert_with_id(
190 &mut self,
191 id: MarkerId,
192 start: u64,
193 end: u64,
194 marker_type: MarkerType,
195 right_gravity: bool,
196 ) {
197 debug_assert!(
198 id < self.next_id,
199 "insert_with_id: id {} must be < next_id {}",
200 id,
201 self.next_id
202 );
203 debug_assert!(
204 !self.marker_map.contains_key(&id),
205 "insert_with_id: id {} already in use",
206 id
207 );
208 let marker = Marker {
209 id,
210 interval: Interval { start, end },
211 marker_type,
212 right_gravity,
213 };
214
215 let new_node = Node::new(marker.clone(), Weak::new());
216 self.root = Self::insert_recursive(self.root.take(), new_node.clone());
217 self.marker_map.insert(id, new_node);
218 }
219
220 pub fn insert_with_type(&mut self, start: u64, end: u64, marker_type: MarkerType) -> MarkerId {
222 self.insert_full(start, end, marker_type, true)
223 }
224
225 fn insert_full(
227 &mut self,
228 start: u64,
229 end: u64,
230 marker_type: MarkerType,
231 right_gravity: bool,
232 ) -> MarkerId {
233 let id = self.next_id;
234 self.next_id += 1;
235 let marker = Marker {
236 id,
237 interval: Interval { start, end },
238 marker_type,
239 right_gravity,
240 };
241
242 let new_node = Node::new(marker.clone(), Weak::new());
243 self.root = Self::insert_recursive(self.root.take(), new_node.clone());
244
245 self.marker_map.insert(id, new_node);
246 id
247 }
248
249 pub fn insert_line_anchor(
251 &mut self,
252 start: u64,
253 end: u64,
254 estimated_line: usize,
255 confidence: AnchorConfidence,
256 ) -> MarkerId {
257 self.insert_with_type(
258 start,
259 end,
260 MarkerType::LineAnchor {
261 estimated_line,
262 confidence,
263 },
264 )
265 }
266
267 pub fn get_position(&self, id: MarkerId) -> Option<(u64, u64)> {
269 let node_rc = self.marker_map.get(&id)?;
270 let mut node_opt = Some(Rc::clone(node_rc));
271 let mut current_delta: i64 = 0;
272
273 while let Some(current_rc) = node_opt {
275 let current = current_rc.borrow();
276
277 current_delta += current.lazy_delta;
279
280 node_opt = current.parent.upgrade();
282 }
283
284 let raw_marker = node_rc.borrow().marker.interval.clone();
285
286 let start = (raw_marker.start as i64 + current_delta) as u64;
287 let end = (raw_marker.end as i64 + current_delta) as u64;
288
289 Some((start, end))
290 }
291
292 pub fn delete(&mut self, id: MarkerId) -> bool {
294 let (start, _) = match self.get_position(id) {
295 Some(pos) => pos,
296 None => return false,
297 };
298
299 if !self.marker_map.contains_key(&id) {
300 return false;
301 }
302
303 self.root = Self::delete_recursive(self.root.take(), start, id, &mut self.marker_map);
304
305 self.marker_map.remove(&id).is_some()
306 }
307
308 pub fn set_position(&mut self, id: MarkerId, new_start: u64, new_end: u64) -> bool {
313 let (marker_type, right_gravity) = match self.get_marker(id) {
315 Some(m) => (m.marker_type, m.right_gravity),
316 None => return false,
317 };
318
319 if !self.delete(id) {
321 return false;
322 }
323
324 self.insert_with_id(id, new_start, new_end, marker_type, right_gravity);
326 true
327 }
328
329 pub fn adjust_for_edit(&mut self, pos: u64, delta: i64) {
332 Self::adjust_recursive(&mut self.root, pos, delta);
333 }
334
335 pub fn query(&self, query_start: u64, query_end: u64) -> Vec<Marker> {
338 let mut results = Vec::new();
339 Self::query_recursive(&self.root, query_start, query_end, &mut results);
340 results
341 }
342
343 pub fn get_marker(&self, id: MarkerId) -> Option<Marker> {
345 let node_rc = self.marker_map.get(&id)?;
346 Some(node_rc.borrow().marker.clone())
347 }
348
349 pub fn update_line_anchor(
351 &mut self,
352 id: MarkerId,
353 estimated_line: usize,
354 confidence: AnchorConfidence,
355 ) -> bool {
356 if let Some(node_rc) = self.marker_map.get(&id) {
357 let mut node = node_rc.borrow_mut();
358 node.marker.marker_type = MarkerType::LineAnchor {
359 estimated_line,
360 confidence,
361 };
362 true
363 } else {
364 false
365 }
366 }
367
368 pub fn query_line_anchors(&self, query_start: u64, query_end: u64) -> Vec<Marker> {
370 self.query(query_start, query_end)
371 .into_iter()
372 .filter(|m| matches!(m.marker_type, MarkerType::LineAnchor { .. }))
373 .collect()
374 }
375}
376
377impl IntervalTree {
382 fn insert_recursive(root: NodePtr, new_node: Rc<RefCell<Node>>) -> NodePtr {
384 let root = match root {
386 Some(r) => r,
387 None => return Some(new_node),
388 };
389
390 Node::push_delta(&root);
391
392 let (start, id) = (
393 new_node.borrow().marker.interval.start,
394 new_node.borrow().marker.id,
395 );
396
397 let mut root_mut = root.borrow_mut();
398 let (root_start, root_id) = (root_mut.marker.interval.start, root_mut.marker.id);
399
400 if start < root_start || (start == root_start && id < root_id) {
401 root_mut.left = Self::insert_recursive(root_mut.left.take(), Rc::clone(&new_node));
402 root_mut.left.as_ref().unwrap().borrow_mut().parent = Rc::downgrade(&root);
403 } else {
404 root_mut.right = Self::insert_recursive(root_mut.right.take(), Rc::clone(&new_node));
405 root_mut.right.as_ref().unwrap().borrow_mut().parent = Rc::downgrade(&root);
406 }
407
408 drop(root_mut);
409 Node::update_stats(&root);
410 Self::balance(root)
411 }
412
413 fn delete_recursive(
415 root: NodePtr,
416 start: u64,
417 id: MarkerId,
418 marker_map: &mut HashMap<MarkerId, Rc<RefCell<Node>>>,
419 ) -> NodePtr {
420 let root = root?;
422
423 Node::push_delta(&root);
424
425 let mut root_mut = root.borrow_mut();
426 let (root_start, root_id) = (root_mut.marker.interval.start, root_mut.marker.id);
427
428 match start.cmp(&root_start) {
429 Ordering::Less => {
430 root_mut.left = Self::delete_recursive(root_mut.left.take(), start, id, marker_map);
431 }
432 Ordering::Greater => {
433 root_mut.right =
434 Self::delete_recursive(root_mut.right.take(), start, id, marker_map);
435 }
436 Ordering::Equal => match id.cmp(&root_id) {
437 Ordering::Less => {
438 root_mut.left =
439 Self::delete_recursive(root_mut.left.take(), start, id, marker_map);
440 }
441 Ordering::Greater => {
442 root_mut.right =
443 Self::delete_recursive(root_mut.right.take(), start, id, marker_map);
444 }
445 Ordering::Equal => {
446 return Self::perform_node_deletion(root_mut, Rc::clone(&root), marker_map);
447 }
448 },
449 }
450
451 drop(root_mut);
452 Node::update_stats(&root);
453 Self::balance(root)
454 }
455
456 fn perform_node_deletion(
458 mut node: RefMut<Node>,
459 node_rc: Rc<RefCell<Node>>,
460 marker_map: &mut HashMap<MarkerId, Rc<RefCell<Node>>>,
461 ) -> NodePtr {
462 if node.left.is_none() {
463 let right = node.right.take();
464 if let Some(ref r) = right {
465 r.borrow_mut().parent = node.parent.clone();
466 }
467 right
468 } else if node.right.is_none() {
469 let left = node.left.take();
470 if let Some(ref l) = left {
471 l.borrow_mut().parent = node.parent.clone();
472 }
473 left
474 } else {
475 let successor_rc = Self::min_node(node.right.as_ref().unwrap());
476
477 let (_successor_start, successor_id) = {
478 let s = successor_rc.borrow();
479 (s.marker.interval.start, s.marker.id)
480 };
481
482 let (orig_start, orig_id) = (node.marker.interval.start, node.marker.id);
487
488 mem::swap(&mut node.marker, &mut successor_rc.borrow_mut().marker);
489
490 marker_map.insert(successor_id, Rc::clone(&node_rc));
500
501 node.right = Self::delete_recursive(node.right.take(), orig_start, orig_id, marker_map);
506
507 drop(node);
508 Node::update_stats(&node_rc);
509 Self::balance(node_rc)
510 }
511 }
512
513 fn min_node(node_rc: &Rc<RefCell<Node>>) -> Rc<RefCell<Node>> {
515 let mut current = Rc::clone(node_rc);
516 loop {
517 Node::push_delta(¤t);
518
519 let next_left_opt = current.borrow().left.clone();
522
523 if let Some(next) = next_left_opt {
524 current = next;
525 } else {
526 break current;
527 }
528 }
529 }
530
531 fn adjust_recursive(node_opt: &mut NodePtr, pos: u64, delta: i64) {
533 let node_rc = match node_opt {
534 Some(n) => n,
535 None => return,
536 };
537
538 Node::push_delta(node_rc);
539
540 let mut node = node_rc.borrow_mut();
541 let start = node.marker.interval.start;
542 let left_gravity = !node.marker.right_gravity;
547
548 if pos <= start {
549 let stay_put = left_gravity && delta > 0 && pos == start;
555
556 if !stay_put {
558 if delta < 0 {
559 node.marker.interval.start = (start as i64 + delta).max(pos as i64) as u64;
560 } else {
561 node.marker.interval.start = (start as i64 + delta) as u64;
562 }
563 }
564
565 if delta < 0 || pos == start {
574 Self::adjust_recursive(&mut node.right, pos, delta);
575 } else if let Some(ref right) = node.right {
576 right.borrow_mut().lazy_delta += delta;
577 }
578
579 Self::adjust_recursive(&mut node.left, pos, delta);
581 } else {
582 Self::adjust_recursive(&mut node.right, pos, delta);
587 }
588
589 let end = node.marker.interval.end;
593 let shift_end = if left_gravity && delta > 0 {
594 end > pos
595 } else {
596 end >= pos
597 };
598 if shift_end {
599 node.marker.interval.end =
600 (end as i64 + delta).max(node.marker.interval.start as i64) as u64;
601 }
602
603 drop(node);
604 Node::update_stats(node_rc);
605 }
606
607 fn query_recursive(
609 node_opt: &NodePtr,
610 query_start: u64,
611 query_end: u64,
612 results: &mut Vec<Marker>,
613 ) {
614 let node_rc = match node_opt {
615 Some(n) => n,
616 None => return,
617 };
618
619 Node::push_delta(node_rc);
620 let node = node_rc.borrow();
621
622 let i = &node.marker.interval;
623 if i.start <= query_end && i.end >= query_start {
624 results.push(node.marker.clone());
625 }
626
627 if node.left.is_some() && node.left.as_ref().unwrap().borrow().max_end >= query_start {
628 Self::query_recursive(&node.left, query_start, query_end, results);
629 }
630
631 if node.right.is_some() && node.marker.interval.start <= query_end {
632 Self::query_recursive(&node.right, query_start, query_end, results);
633 }
634 }
635
636 fn balance(node: Rc<RefCell<Node>>) -> NodePtr {
639 let bf = Node::balance_factor(&node);
640
641 if bf > 1 {
642 let left_rc = node.borrow().left.as_ref().unwrap().clone();
643 if Node::balance_factor(&left_rc) < 0 {
644 let left_child = node.borrow_mut().left.take().unwrap();
646 node.borrow_mut().left = Self::rotate_left(left_child);
647 }
648 Self::rotate_right(node)
649 } else if bf < -1 {
650 let right_rc = node.borrow().right.as_ref().unwrap().clone();
651 if Node::balance_factor(&right_rc) > 0 {
652 let right_child = node.borrow_mut().right.take().unwrap();
654 node.borrow_mut().right = Self::rotate_right(right_child);
655 }
656 Self::rotate_left(node)
657 } else {
658 Some(node)
659 }
660 }
661
662 fn rotate_left(node_rc: Rc<RefCell<Node>>) -> NodePtr {
663 Node::push_delta(&node_rc);
664 let x_rc = node_rc.borrow_mut().right.take().unwrap();
665 Node::push_delta(&x_rc);
666
667 let mut y = node_rc.borrow_mut();
668 let mut x = x_rc.borrow_mut();
669
670 y.right = x.left.take();
671 if let Some(ref r) = y.right {
672 r.borrow_mut().parent = Rc::downgrade(&node_rc);
673 }
674 x.left = Some(Rc::clone(&node_rc));
675 x.parent = y.parent.clone();
676 y.parent = Rc::downgrade(&x_rc);
677
678 drop(x);
679 drop(y);
680
681 Node::update_stats(&node_rc);
682 Node::update_stats(&x_rc);
683 Some(x_rc)
684 }
685
686 fn rotate_right(node_rc: Rc<RefCell<Node>>) -> NodePtr {
687 Node::push_delta(&node_rc);
688 let x_rc = node_rc.borrow_mut().left.take().unwrap();
689 Node::push_delta(&x_rc);
690
691 let mut y = node_rc.borrow_mut();
692 let mut x = x_rc.borrow_mut();
693
694 y.left = x.right.take();
695 if let Some(ref l) = y.left {
696 l.borrow_mut().parent = Rc::downgrade(&node_rc);
697 }
698 x.right = Some(Rc::clone(&node_rc));
699 x.parent = y.parent.clone();
700 y.parent = Rc::downgrade(&x_rc);
701
702 drop(x);
703 drop(y);
704
705 Node::update_stats(&node_rc);
706 Node::update_stats(&x_rc);
707 Some(x_rc)
708 }
709}
710
711#[cfg(test)]
712mod tests {
713 use super::*;
714
715 fn insert_marker(tree: &mut IntervalTree, start: u64, end: u64) -> MarkerId {
717 tree.insert(start, end)
718 }
719
720 fn get_pos(tree: &IntervalTree, id: MarkerId) -> (u64, u64) {
722 tree.get_position(id)
723 .unwrap_or_else(|| panic!("Marker ID {} not found.", id))
724 }
725
726 #[test]
729 fn test_left_gravity_marker_stays_on_insert_at_position() {
730 let mut tree = IntervalTree::new();
734 let m = tree.insert_left_gravity(3, 3);
735
736 tree.adjust_for_edit(3, 4);
738
739 assert_eq!(
740 get_pos(&tree, m),
741 (3, 3),
742 "left-gravity marker must stay put when text is inserted at its position"
743 );
744 }
745
746 #[test]
747 fn test_right_gravity_marker_moves_on_insert_at_position() {
748 let mut tree = IntervalTree::new();
751 let m = tree.insert(3, 3);
752
753 tree.adjust_for_edit(3, 4);
754
755 assert_eq!(get_pos(&tree, m), (7, 7));
756 }
757
758 #[test]
759 fn test_left_gravity_marker_still_shifts_on_insert_before() {
760 let mut tree = IntervalTree::new();
763 let m = tree.insert_left_gravity(5, 5);
764
765 tree.adjust_for_edit(2, 3);
766
767 assert_eq!(get_pos(&tree, m), (8, 8));
768 }
769
770 #[test]
771 fn test_search_match_does_not_grow_on_adjacent_insert() {
772 let mut tree = IntervalTree::new();
777 let start = tree.insert(0, 0);
778 let end = tree.insert_left_gravity(3, 3);
779
780 tree.adjust_for_edit(3, 1);
782
783 assert_eq!(get_pos(&tree, start), (0, 0));
784 assert_eq!(
785 get_pos(&tree, end),
786 (3, 3),
787 "highlight end must not extend over text typed after the match"
788 );
789 }
790
791 #[test]
792 fn test_adjacent_matches_keep_independent_gravity_at_shared_boundary() {
793 let mut tree = IntervalTree::new();
798 let m1_start = tree.insert(0, 0);
799 let m1_end = tree.insert_left_gravity(2, 2);
800 let m2_start = tree.insert(2, 2);
801 let m2_end = tree.insert_left_gravity(4, 4);
802
803 tree.adjust_for_edit(2, 3);
805
806 assert_eq!(get_pos(&tree, m1_start), (0, 0));
807 assert_eq!(get_pos(&tree, m1_end), (2, 2), "first match must not grow");
808 assert_eq!(get_pos(&tree, m2_start), (5, 5), "second match shifts");
809 assert_eq!(get_pos(&tree, m2_end), (7, 7));
810 }
811
812 #[test]
813 fn test_initial_insert_and_delete() {
814 let mut tree = IntervalTree::new();
815 let id1 = insert_marker(&mut tree, 10, 20);
816 let id2 = insert_marker(&mut tree, 30, 40);
817
818 assert_eq!(get_pos(&tree, id1), (10, 20));
819 assert_eq!(get_pos(&tree, id2), (30, 40));
820
821 assert!(tree.delete(id1));
822 assert_eq!(tree.get_position(id1), None);
823 assert_eq!(get_pos(&tree, id2), (30, 40));
824 }
825
826 #[test]
827 fn test_basic_edit_adjustment() {
828 let mut tree = IntervalTree::new();
829 let id1 = insert_marker(&mut tree, 10, 20); let id2 = insert_marker(&mut tree, 30, 40); tree.adjust_for_edit(30, 5);
834
835 assert_eq!(
837 get_pos(&tree, id1),
838 (10, 20),
839 "Marker before edit should not move."
840 );
841
842 assert_eq!(
844 get_pos(&tree, id2),
845 (35, 45),
846 "Marker at/after edit should move."
847 );
848
849 tree.adjust_for_edit(5, -10); assert_eq!(
854 get_pos(&tree, id1),
855 (5, 10),
856 "Marker moved back by deletion."
857 );
858
859 assert_eq!(
861 get_pos(&tree, id2),
862 (25, 35),
863 "Marker moved back by deletion."
864 );
865 }
866
867 #[test]
868 fn test_problematic_lazy_delta_scenario() {
869 let mut tree = IntervalTree::new();
873
874 let id_p = insert_marker(&mut tree, 200, 250); let id_r = insert_marker(&mut tree, 300, 350); let id_l = insert_marker(&mut tree, 100, 150); assert_eq!(
883 get_pos(&tree, id_l),
884 (100, 150),
885 "L initial position incorrect."
886 );
887 assert_eq!(
888 get_pos(&tree, id_p),
889 (200, 250),
890 "P initial position incorrect."
891 );
892 assert_eq!(
893 get_pos(&tree, id_r),
894 (300, 350),
895 "R initial position incorrect."
896 );
897
898 tree.adjust_for_edit(150, 50);
903
904 assert_eq!(
908 get_pos(&tree, id_l),
909 (100, 200),
910 "L(100) should expand to (100, 200)."
911 );
912
913 assert_eq!(
915 get_pos(&tree, id_p),
916 (250, 300),
917 "P(200) did not shift correctly. Should be 250."
918 );
919
920 assert_eq!(
922 get_pos(&tree, id_r),
923 (350, 400),
924 "R(300) did not shift correctly. Should be 350."
925 );
926 }
927
928 #[test]
929 fn test_interval_spanning_edit() {
930 let mut tree = IntervalTree::new();
931 let id_s = insert_marker(&mut tree, 50, 200);
933
934 tree.adjust_for_edit(100, 10);
936
937 assert_eq!(
940 get_pos(&tree, id_s),
941 (50, 210),
942 "Spanning marker end did not move correctly."
943 );
944 }
945
946 #[test]
947 fn test_deletion_engulfing_marker_start() {
948 let mut tree = IntervalTree::new();
949 let id1 = insert_marker(&mut tree, 8, 20);
950
951 tree.adjust_for_edit(5, -10);
957
958 assert_eq!(
959 get_pos(&tree, id1),
960 (5, 10),
961 "Marker should be clamped and shrunk."
962 );
963 }
964
965 #[test]
966 fn test_zero_length_marker() {
967 let mut tree = IntervalTree::new();
968 let id1 = insert_marker(&mut tree, 10, 10);
969
970 tree.adjust_for_edit(10, 5);
972 assert_eq!(
973 get_pos(&tree, id1),
974 (15, 15),
975 "Insertion at zero-length marker."
976 );
977
978 tree.adjust_for_edit(5, 5);
980 assert_eq!(
981 get_pos(&tree, id1),
982 (20, 20),
983 "Insertion before zero-length marker."
984 );
985
986 tree.adjust_for_edit(25, -5);
988 assert_eq!(
989 get_pos(&tree, id1),
990 (20, 20),
991 "Deletion after zero-length marker."
992 );
993
994 tree.adjust_for_edit(15, -10);
996 assert_eq!(
1000 get_pos(&tree, id1),
1001 (15, 15),
1002 "Deletion containing zero-length marker."
1003 );
1004 }
1005
1006 #[test]
1007 fn test_edit_at_pos_zero() {
1008 let mut tree = IntervalTree::new();
1009 let id1 = insert_marker(&mut tree, 10, 20);
1010
1011 tree.adjust_for_edit(0, 5);
1013 assert_eq!(get_pos(&tree, id1), (15, 25), "Insertion at pos 0.");
1014
1015 tree.adjust_for_edit(0, -5);
1017 assert_eq!(get_pos(&tree, id1), (10, 20), "Deletion at pos 0.");
1018
1019 tree.adjust_for_edit(0, -15);
1021 assert_eq!(get_pos(&tree, id1), (0, 5), "Engulfing deletion at pos 0.");
1025 }
1026
1027 #[test]
1028 fn test_deletion_preserves_marker_ordering() {
1029 let mut tree = IntervalTree::new();
1032
1033 let id0 = insert_marker(&mut tree, 0, 0);
1035 let id1 = insert_marker(&mut tree, 10, 10);
1036 let id2 = insert_marker(&mut tree, 20, 20);
1037 let id3 = insert_marker(&mut tree, 30, 30);
1038 let id4 = insert_marker(&mut tree, 40, 40);
1039
1040 assert_eq!(get_pos(&tree, id0), (0, 0));
1042 assert_eq!(get_pos(&tree, id1), (10, 10));
1043 assert_eq!(get_pos(&tree, id2), (20, 20));
1044 assert_eq!(get_pos(&tree, id3), (30, 30));
1045 assert_eq!(get_pos(&tree, id4), (40, 40));
1046
1047 tree.adjust_for_edit(5, -16);
1051
1052 let positions = vec![
1054 get_pos(&tree, id0).0,
1055 get_pos(&tree, id1).0,
1056 get_pos(&tree, id2).0,
1057 get_pos(&tree, id3).0,
1058 get_pos(&tree, id4).0,
1059 ];
1060
1061 for i in 0..positions.len() - 1 {
1063 assert!(
1064 positions[i] <= positions[i + 1],
1065 "Ordering violated at index {}: {:?}[{}]={} > {:?}[{}]={}",
1066 i,
1067 positions,
1068 i,
1069 positions[i],
1070 positions,
1071 i + 1,
1072 positions[i + 1]
1073 );
1074 }
1075
1076 assert_eq!(get_pos(&tree, id0), (0, 0), "Marker at 0 should stay at 0");
1078 assert_eq!(
1079 get_pos(&tree, id1),
1080 (5, 5),
1081 "Marker at 10 should clamp to 5"
1082 );
1083 assert_eq!(
1084 get_pos(&tree, id2),
1085 (5, 5),
1086 "Marker at 20 should clamp to 5"
1087 );
1088 assert_eq!(
1089 get_pos(&tree, id3),
1090 (14, 14),
1091 "Marker at 30 should shift to 14"
1092 );
1093 assert_eq!(
1094 get_pos(&tree, id4),
1095 (24, 24),
1096 "Marker at 40 should shift to 24"
1097 );
1098 }
1099}