Skip to main content

fresh/model/
marker_tree.rs

1use std::cell::{RefCell, RefMut};
2use std::cmp::{max, Ordering};
3use std::collections::HashMap;
4use std::mem;
5use std::rc::{Rc, Weak};
6
7/// Use a simple u64 for marker IDs
8pub type MarkerId = u64;
9
10// ---
11// 1. Core Data Structures and Pointers
12// ---
13
14#[derive(Debug, Clone, PartialEq)]
15pub struct Interval {
16    pub start: u64,
17    pub end: u64,
18}
19
20/// Type of marker - either a position marker or a line anchor
21#[derive(Debug, Clone, PartialEq)]
22pub enum MarkerType {
23    /// Regular position marker (for overlays, cursors, etc.)
24    Position,
25    /// Line anchor with estimated/exact line number
26    LineAnchor {
27        estimated_line: usize,
28        confidence: AnchorConfidence,
29    },
30}
31
32/// Confidence level for line anchor estimates
33#[derive(Debug, Clone, PartialEq)]
34pub enum AnchorConfidence {
35    /// Exact line number (scanned from known position)
36    Exact,
37    /// Estimated from average line length
38    Estimated,
39    /// Relative to another anchor
40    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}
49
50/// A Strong pointer to a tree node (child/sibling/map reference)
51type NodePtr = Option<Rc<RefCell<Node>>>;
52/// A Weak pointer to a tree node (parent reference, doesn't count for ownership)
53type WeakNodePtr = Weak<RefCell<Node>>;
54
55/// The internal tree node
56#[derive(Debug)]
57struct Node {
58    pub marker: Marker,
59
60    /// AVL: Height of this node's subtree
61    pub height: i32,
62    /// Augmentation: The max 'end' value in this node's subtree
63    pub max_end: u64,
64    /// VSCode-style: The delta to be applied to this node and its children
65    pub lazy_delta: i64,
66
67    pub parent: WeakNodePtr,
68    pub left: NodePtr,
69    pub right: NodePtr,
70}
71
72/// The main Interval Tree structure
73#[derive(Debug, Default)]
74pub struct IntervalTree {
75    root: NodePtr,
76    next_id: u64,
77    /// ID-to-Node map for O(1) lookups
78    marker_map: HashMap<MarkerId, Rc<RefCell<Node>>>,
79}
80
81// ---
82// 2. Node Helpers (Pushing Deltas, Stats, Heights)
83// ---
84
85impl Node {
86    fn new(marker: Marker, parent: WeakNodePtr) -> Rc<RefCell<Self>> {
87        // Fix E0382: Calculate max_end before moving ownership of `marker` into the struct.
88        let max_end_val = marker.interval.end;
89
90        Rc::new(RefCell::new(Node {
91            marker,
92            height: 1,
93            max_end: max_end_val,
94            lazy_delta: 0,
95            parent,
96            left: None,
97            right: None,
98        }))
99    }
100
101    /// Gets the height of a node (0 for None).
102    fn height(node: &NodePtr) -> i32 {
103        node.as_ref().map_or(0, |n| n.borrow().height)
104    }
105
106    /// Calculates the balance factor of a node (height(left) - height(right)).
107    fn balance_factor(node: &Rc<RefCell<Self>>) -> i32 {
108        let n = node.borrow();
109        Self::height(&n.left) - Self::height(&n.right)
110    }
111
112    /// Pushes this node's lazy_delta down to its immediate children.
113    fn push_delta(node_rc: &Rc<RefCell<Self>>) {
114        let mut node = node_rc.borrow_mut();
115        if node.lazy_delta == 0 {
116            return;
117        }
118
119        let delta = node.lazy_delta;
120
121        // Apply delta to self (start and end)
122        node.marker.interval.start = (node.marker.interval.start as i64 + delta) as u64;
123        node.marker.interval.end = (node.marker.interval.end as i64 + delta) as u64;
124
125        // Apply delta to children (only update their lazy_delta fields)
126        if let Some(ref left) = node.left {
127            left.borrow_mut().lazy_delta += delta;
128        }
129        if let Some(ref right) = node.right {
130            right.borrow_mut().lazy_delta += delta;
131        }
132
133        node.lazy_delta = 0;
134
135        // The max_end needs to be updated after the push
136        let max_l = node.left.as_ref().map_or(0, |l| l.borrow().max_end);
137        let max_r = node.right.as_ref().map_or(0, |r| r.borrow().max_end);
138        node.max_end = max(node.marker.interval.end, max(max_l, max_r));
139    }
140
141    /// Updates a node's height and max_end based on its children.
142    fn update_stats(node: &Rc<RefCell<Self>>) {
143        let mut n = node.borrow_mut();
144        let height_l = Self::height(&n.left);
145        let height_r = Self::height(&n.right);
146
147        n.height = 1 + max(height_l, height_r);
148
149        let max_l = n.left.as_ref().map_or(0, |l| l.borrow().max_end);
150        let max_r = n.right.as_ref().map_or(0, |r| r.borrow().max_end);
151        n.max_end = max(n.marker.interval.end, max(max_l, max_r));
152    }
153}
154
155// ---
156// 3. Main Public API
157// ---
158
159impl IntervalTree {
160    pub fn new() -> Self {
161        Self::default()
162    }
163
164    /// Inserts a new marker interval. Performance: O(log n)
165    pub fn insert(&mut self, start: u64, end: u64) -> MarkerId {
166        self.insert_with_type(start, end, MarkerType::Position)
167    }
168
169    /// Insert a marker with a specific ID and type (for set_position).
170    /// The caller must ensure the ID is not already in use.
171    fn insert_with_id(&mut self, id: MarkerId, start: u64, end: u64, marker_type: MarkerType) {
172        debug_assert!(
173            id < self.next_id,
174            "insert_with_id: id {} must be < next_id {}",
175            id,
176            self.next_id
177        );
178        debug_assert!(
179            !self.marker_map.contains_key(&id),
180            "insert_with_id: id {} already in use",
181            id
182        );
183        let marker = Marker {
184            id,
185            interval: Interval { start, end },
186            marker_type,
187        };
188
189        let new_node = Node::new(marker.clone(), Weak::new());
190        self.root = Self::insert_recursive(self.root.take(), new_node.clone());
191        self.marker_map.insert(id, new_node);
192    }
193
194    /// Insert a marker with a specific type
195    pub fn insert_with_type(&mut self, start: u64, end: u64, marker_type: MarkerType) -> MarkerId {
196        let id = self.next_id;
197        self.next_id += 1;
198        let marker = Marker {
199            id,
200            interval: Interval { start, end },
201            marker_type,
202        };
203
204        let new_node = Node::new(marker.clone(), Weak::new());
205        self.root = Self::insert_recursive(self.root.take(), new_node.clone());
206
207        self.marker_map.insert(id, new_node);
208        id
209    }
210
211    /// Insert a line anchor at a specific position
212    pub fn insert_line_anchor(
213        &mut self,
214        start: u64,
215        end: u64,
216        estimated_line: usize,
217        confidence: AnchorConfidence,
218    ) -> MarkerId {
219        self.insert_with_type(
220            start,
221            end,
222            MarkerType::LineAnchor {
223                estimated_line,
224                confidence,
225            },
226        )
227    }
228
229    /// Finds the current true position of a marker by its ID. Performance: O(log n)
230    pub fn get_position(&self, id: MarkerId) -> Option<(u64, u64)> {
231        let node_rc = self.marker_map.get(&id)?;
232        let mut node_opt = Some(Rc::clone(node_rc));
233        let mut current_delta: i64 = 0;
234
235        // Walk up the tree, collecting all deltas that haven't been applied yet.
236        while let Some(current_rc) = node_opt {
237            let current = current_rc.borrow();
238
239            // Add this node's delta (if any)
240            current_delta += current.lazy_delta;
241
242            // Move up to the parent
243            node_opt = current.parent.upgrade();
244        }
245
246        let raw_marker = node_rc.borrow().marker.interval.clone();
247
248        let start = (raw_marker.start as i64 + current_delta) as u64;
249        let end = (raw_marker.end as i64 + current_delta) as u64;
250
251        Some((start, end))
252    }
253
254    /// Deletes a marker by its ID. Performance: O(log n)
255    pub fn delete(&mut self, id: MarkerId) -> bool {
256        let (start, _) = match self.get_position(id) {
257            Some(pos) => pos,
258            None => return false,
259        };
260
261        if !self.marker_map.contains_key(&id) {
262            return false;
263        }
264
265        self.root = Self::delete_recursive(self.root.take(), start, id);
266
267        self.marker_map.remove(&id).is_some()
268    }
269
270    /// Move a marker to a new position, preserving its ID and type.
271    /// Implemented as delete + reinsert with the same ID.
272    /// Returns false if the marker doesn't exist.
273    /// Performance: O(log n)
274    pub fn set_position(&mut self, id: MarkerId, new_start: u64, new_end: u64) -> bool {
275        // Get the marker's type before deleting
276        let marker_type = match self.get_marker(id) {
277            Some(m) => m.marker_type,
278            None => return false,
279        };
280
281        // Delete from tree
282        if !self.delete(id) {
283            return false;
284        }
285
286        // Reinsert with same ID
287        self.insert_with_id(id, new_start, new_end, marker_type);
288        true
289    }
290
291    /// Adjusts all markers for a text edit (insertion or deletion).
292    /// Performance: O(log n) due to lazy delta propagation.
293    pub fn adjust_for_edit(&mut self, pos: u64, delta: i64) {
294        Self::adjust_recursive(&mut self.root, pos, delta);
295    }
296
297    /// Finds all markers that overlap a given query range.
298    /// Performance: O(log n + k)
299    pub fn query(&self, query_start: u64, query_end: u64) -> Vec<Marker> {
300        let mut results = Vec::new();
301        Self::query_recursive(&self.root, query_start, query_end, &mut results);
302        results
303    }
304
305    /// Get the marker data for a given marker ID
306    pub fn get_marker(&self, id: MarkerId) -> Option<Marker> {
307        let node_rc = self.marker_map.get(&id)?;
308        Some(node_rc.borrow().marker.clone())
309    }
310
311    /// Update a line anchor's estimated line number and confidence
312    pub fn update_line_anchor(
313        &mut self,
314        id: MarkerId,
315        estimated_line: usize,
316        confidence: AnchorConfidence,
317    ) -> bool {
318        if let Some(node_rc) = self.marker_map.get(&id) {
319            let mut node = node_rc.borrow_mut();
320            node.marker.marker_type = MarkerType::LineAnchor {
321                estimated_line,
322                confidence,
323            };
324            true
325        } else {
326            false
327        }
328    }
329
330    /// Query only line anchors in a range
331    pub fn query_line_anchors(&self, query_start: u64, query_end: u64) -> Vec<Marker> {
332        self.query(query_start, query_end)
333            .into_iter()
334            .filter(|m| matches!(m.marker_type, MarkerType::LineAnchor { .. }))
335            .collect()
336    }
337}
338
339// ---
340// 4. Recursive Implementation Details (Insert, Delete, Adjust)
341// ---
342
343impl IntervalTree {
344    /// Recursive helper for insert
345    fn insert_recursive(root: NodePtr, new_node: Rc<RefCell<Node>>) -> NodePtr {
346        // Remove unnecessary 'mut'
347        let root = match root {
348            Some(r) => r,
349            None => return Some(new_node),
350        };
351
352        Node::push_delta(&root);
353
354        let (start, id) = (
355            new_node.borrow().marker.interval.start,
356            new_node.borrow().marker.id,
357        );
358
359        let mut root_mut = root.borrow_mut();
360        let (root_start, root_id) = (root_mut.marker.interval.start, root_mut.marker.id);
361
362        if start < root_start || (start == root_start && id < root_id) {
363            root_mut.left = Self::insert_recursive(root_mut.left.take(), Rc::clone(&new_node));
364            root_mut.left.as_ref().unwrap().borrow_mut().parent = Rc::downgrade(&root);
365        } else {
366            root_mut.right = Self::insert_recursive(root_mut.right.take(), Rc::clone(&new_node));
367            root_mut.right.as_ref().unwrap().borrow_mut().parent = Rc::downgrade(&root);
368        }
369
370        drop(root_mut);
371        Node::update_stats(&root);
372        Self::balance(root)
373    }
374
375    /// Recursive helper for delete
376    fn delete_recursive(root: NodePtr, start: u64, id: MarkerId) -> NodePtr {
377        // Remove unnecessary 'mut'
378        let root = root?;
379
380        Node::push_delta(&root);
381
382        let mut root_mut = root.borrow_mut();
383        let (root_start, root_id) = (root_mut.marker.interval.start, root_mut.marker.id);
384
385        match start.cmp(&root_start) {
386            Ordering::Less => {
387                root_mut.left = Self::delete_recursive(root_mut.left.take(), start, id);
388            }
389            Ordering::Greater => {
390                root_mut.right = Self::delete_recursive(root_mut.right.take(), start, id);
391            }
392            Ordering::Equal => match id.cmp(&root_id) {
393                Ordering::Less => {
394                    root_mut.left = Self::delete_recursive(root_mut.left.take(), start, id);
395                }
396                Ordering::Greater => {
397                    root_mut.right = Self::delete_recursive(root_mut.right.take(), start, id);
398                }
399                Ordering::Equal => {
400                    return Self::perform_node_deletion(root_mut, Rc::clone(&root));
401                }
402            },
403        }
404
405        drop(root_mut);
406        Node::update_stats(&root);
407        Self::balance(root)
408    }
409
410    /// Handles the actual structural changes for deletion.
411    fn perform_node_deletion(mut node: RefMut<Node>, node_rc: Rc<RefCell<Node>>) -> NodePtr {
412        if node.left.is_none() {
413            let right = node.right.take();
414            if let Some(ref r) = right {
415                r.borrow_mut().parent = node.parent.clone();
416            }
417            right
418        } else if node.right.is_none() {
419            let left = node.left.take();
420            if let Some(ref l) = left {
421                l.borrow_mut().parent = node.parent.clone();
422            }
423            left
424        } else {
425            let successor_rc = Self::min_node(node.right.as_ref().unwrap());
426
427            let (successor_start, successor_id) = {
428                let s = successor_rc.borrow();
429                (s.marker.interval.start, s.marker.id)
430            };
431
432            mem::swap(&mut node.marker, &mut successor_rc.borrow_mut().marker);
433
434            node.right = Self::delete_recursive(node.right.take(), successor_start, successor_id);
435
436            drop(node);
437            Node::update_stats(&node_rc);
438            Self::balance(node_rc)
439        }
440    }
441
442    /// Finds the minimum node in a subtree (for deletion)
443    fn min_node(node_rc: &Rc<RefCell<Node>>) -> Rc<RefCell<Node>> {
444        let mut current = Rc::clone(node_rc);
445        loop {
446            Node::push_delta(&current);
447
448            // Fix E0506: Clone the next node pointer before the borrow (Ref<Node>) on
449            // `current` is dropped and potentially prevents reassignment.
450            let next_left_opt = current.borrow().left.clone();
451
452            if let Some(next) = next_left_opt {
453                current = next;
454            } else {
455                break current;
456            }
457        }
458    }
459
460    /// CORRECTED Recursive helper for `adjust_for_edit` (O(log n) lazy update)
461    fn adjust_recursive(node_opt: &mut NodePtr, pos: u64, delta: i64) {
462        let node_rc = match node_opt {
463            Some(n) => n,
464            None => return,
465        };
466
467        Node::push_delta(node_rc);
468
469        let mut node = node_rc.borrow_mut();
470        let start = node.marker.interval.start;
471
472        if pos <= start {
473            // CASE 1: Edit is at or before this node's start.
474            // This node and everything to its right must be shifted.
475
476            // 1. Shift the current node's start position directly, clamping at `pos` if needed.
477            if delta < 0 {
478                node.marker.interval.start = (start as i64 + delta).max(pos as i64) as u64;
479            } else {
480                node.marker.interval.start = (start as i64 + delta) as u64;
481            }
482
483            // 2. Handle the right subtree.
484            // For insertions (delta > 0): can use lazy propagation since all nodes shift uniformly
485            // For deletions (delta < 0): must recurse to provide position-aware clamping
486            if delta < 0 {
487                // Deletion: recurse immediately so nodes can clamp to `pos`
488                Self::adjust_recursive(&mut node.right, pos, delta);
489            } else {
490                // Insertion: lazy propagation is safe and efficient
491                if let Some(ref right) = node.right {
492                    right.borrow_mut().lazy_delta += delta;
493                }
494            }
495
496            // 3. Recurse left, as it may contain markers spanning the edit pos.
497            Self::adjust_recursive(&mut node.left, pos, delta);
498        } else {
499            // pos > start
500            // CASE 2: This node's start is BEFORE the edit.
501            // Its start is unaffected. We only need to check the right subtree
502            // for nodes that might be affected.
503            Self::adjust_recursive(&mut node.right, pos, delta);
504        }
505
506        // Always handle the interval span case (where end >= pos)
507        if node.marker.interval.end >= pos {
508            node.marker.interval.end = (node.marker.interval.end as i64 + delta)
509                .max(node.marker.interval.start as i64)
510                as u64;
511        }
512
513        drop(node);
514        Node::update_stats(node_rc);
515    }
516
517    /// Recursive helper for query
518    fn query_recursive(
519        node_opt: &NodePtr,
520        query_start: u64,
521        query_end: u64,
522        results: &mut Vec<Marker>,
523    ) {
524        let node_rc = match node_opt {
525            Some(n) => n,
526            None => return,
527        };
528
529        Node::push_delta(node_rc);
530        let node = node_rc.borrow();
531
532        let i = &node.marker.interval;
533        if i.start <= query_end && i.end >= query_start {
534            results.push(node.marker.clone());
535        }
536
537        if node.left.is_some() && node.left.as_ref().unwrap().borrow().max_end >= query_start {
538            Self::query_recursive(&node.left, query_start, query_end, results);
539        }
540
541        if node.right.is_some() && node.marker.interval.start <= query_end {
542            Self::query_recursive(&node.right, query_start, query_end, results);
543        }
544    }
545
546    // --- AVL Balancing ---
547
548    fn balance(node: Rc<RefCell<Node>>) -> NodePtr {
549        let bf = Node::balance_factor(&node);
550
551        if bf > 1 {
552            let left_rc = node.borrow().left.as_ref().unwrap().clone();
553            if Node::balance_factor(&left_rc) < 0 {
554                // Fix RefCell borrow issue: extract left child before rotating
555                let left_child = node.borrow_mut().left.take().unwrap();
556                node.borrow_mut().left = Self::rotate_left(left_child);
557            }
558            Self::rotate_right(node)
559        } else if bf < -1 {
560            let right_rc = node.borrow().right.as_ref().unwrap().clone();
561            if Node::balance_factor(&right_rc) > 0 {
562                // Fix RefCell borrow issue: extract right child before rotating
563                let right_child = node.borrow_mut().right.take().unwrap();
564                node.borrow_mut().right = Self::rotate_right(right_child);
565            }
566            Self::rotate_left(node)
567        } else {
568            Some(node)
569        }
570    }
571
572    fn rotate_left(node_rc: Rc<RefCell<Node>>) -> NodePtr {
573        Node::push_delta(&node_rc);
574        let x_rc = node_rc.borrow_mut().right.take().unwrap();
575        Node::push_delta(&x_rc);
576
577        let mut y = node_rc.borrow_mut();
578        let mut x = x_rc.borrow_mut();
579
580        y.right = x.left.take();
581        if let Some(ref r) = y.right {
582            r.borrow_mut().parent = Rc::downgrade(&node_rc);
583        }
584        x.left = Some(Rc::clone(&node_rc));
585        x.parent = y.parent.clone();
586        y.parent = Rc::downgrade(&x_rc);
587
588        drop(x);
589        drop(y);
590
591        Node::update_stats(&node_rc);
592        Node::update_stats(&x_rc);
593        Some(x_rc)
594    }
595
596    fn rotate_right(node_rc: Rc<RefCell<Node>>) -> NodePtr {
597        Node::push_delta(&node_rc);
598        let x_rc = node_rc.borrow_mut().left.take().unwrap();
599        Node::push_delta(&x_rc);
600
601        let mut y = node_rc.borrow_mut();
602        let mut x = x_rc.borrow_mut();
603
604        y.left = x.right.take();
605        if let Some(ref l) = y.left {
606            l.borrow_mut().parent = Rc::downgrade(&node_rc);
607        }
608        x.right = Some(Rc::clone(&node_rc));
609        x.parent = y.parent.clone();
610        y.parent = Rc::downgrade(&x_rc);
611
612        drop(x);
613        drop(y);
614
615        Node::update_stats(&node_rc);
616        Node::update_stats(&x_rc);
617        Some(x_rc)
618    }
619}
620
621#[cfg(test)]
622mod tests {
623    use super::*;
624
625    /// Helper to insert and return the ID, making test setup cleaner.
626    fn insert_marker(tree: &mut IntervalTree, start: u64, end: u64) -> MarkerId {
627        tree.insert(start, end)
628    }
629
630    /// Helper to get position and unwrap, or panic with a clear message.
631    fn get_pos(tree: &IntervalTree, id: MarkerId) -> (u64, u64) {
632        tree.get_position(id)
633            .unwrap_or_else(|| panic!("Marker ID {} not found.", id))
634    }
635
636    #[test]
637    fn test_initial_insert_and_delete() {
638        let mut tree = IntervalTree::new();
639        let id1 = insert_marker(&mut tree, 10, 20);
640        let id2 = insert_marker(&mut tree, 30, 40);
641
642        assert_eq!(get_pos(&tree, id1), (10, 20));
643        assert_eq!(get_pos(&tree, id2), (30, 40));
644
645        assert!(tree.delete(id1));
646        assert_eq!(tree.get_position(id1), None);
647        assert_eq!(get_pos(&tree, id2), (30, 40));
648    }
649
650    #[test]
651    fn test_basic_edit_adjustment() {
652        let mut tree = IntervalTree::new();
653        let id1 = insert_marker(&mut tree, 10, 20); // Before edit
654        let id2 = insert_marker(&mut tree, 30, 40); // At/After edit
655
656        // Insert 5 characters at position 30
657        tree.adjust_for_edit(30, 5);
658
659        // id1 (10-20) should not move
660        assert_eq!(
661            get_pos(&tree, id1),
662            (10, 20),
663            "Marker before edit should not move."
664        );
665
666        // id2 (30-40) should move to (35-45)
667        assert_eq!(
668            get_pos(&tree, id2),
669            (35, 45),
670            "Marker at/after edit should move."
671        );
672
673        // Delete 10 characters at position 5
674        tree.adjust_for_edit(5, -10); // All markers are after position 5
675
676        // id1 (10-20) is inside the deletion [5, 15) and should be clamped and shrunk.
677        assert_eq!(
678            get_pos(&tree, id1),
679            (5, 10),
680            "Marker moved back by deletion."
681        );
682
683        // id2 (35-45) -> (25-35)
684        assert_eq!(
685            get_pos(&tree, id2),
686            (25, 35),
687            "Marker moved back by deletion."
688        );
689    }
690
691    #[test]
692    fn test_problematic_lazy_delta_scenario() {
693        // This test replicates the tricky tree structure to ensure the O(log n) lazy
694        // delta propagation works correctly and doesn't over-propagate to left children.
695
696        let mut tree = IntervalTree::new();
697
698        // Setup the tree with specific positions to force a parent/child relationship
699        // that caused the previous bug:
700        // L(100) -> P(200) <- R(300)
701        let id_p = insert_marker(&mut tree, 200, 250); // Parent node (P)
702        let id_r = insert_marker(&mut tree, 300, 350); // Right child (R)
703        let id_l = insert_marker(&mut tree, 100, 150); // Left child (L)
704
705        // --- Verify initial state ---
706        assert_eq!(
707            get_pos(&tree, id_l),
708            (100, 150),
709            "L initial position incorrect."
710        );
711        assert_eq!(
712            get_pos(&tree, id_p),
713            (200, 250),
714            "P initial position incorrect."
715        );
716        assert_eq!(
717            get_pos(&tree, id_r),
718            (300, 350),
719            "R initial position incorrect."
720        );
721
722        // --- Apply the problematic edit ---
723        // Edit: Insert 50 characters at position 150 (P=150, delta=+50)
724        // L(100) should NOT move (100 < 150).
725        // P(200) and R(300) should move (+50).
726        tree.adjust_for_edit(150, 50);
727
728        // --- Verify corrected final state ---
729
730        // L(100) should have its end expanded (100 < 150, but 150 >= 150).
731        assert_eq!(
732            get_pos(&tree, id_l),
733            (100, 200),
734            "L(100) should expand to (100, 200)."
735        );
736
737        // P(200) should be shifted (200 >= 150) -> 250
738        assert_eq!(
739            get_pos(&tree, id_p),
740            (250, 300),
741            "P(200) did not shift correctly. Should be 250."
742        );
743
744        // R(300) should be shifted (300 >= 150) -> 350
745        assert_eq!(
746            get_pos(&tree, id_r),
747            (350, 400),
748            "R(300) did not shift correctly. Should be 350."
749        );
750    }
751
752    #[test]
753    fn test_interval_spanning_edit() {
754        let mut tree = IntervalTree::new();
755        // Marker S starts before edit, but spans it.
756        let id_s = insert_marker(&mut tree, 50, 200);
757
758        // Edit: Insert 10 characters at position 100 (P=100, delta=+10)
759        tree.adjust_for_edit(100, 10);
760
761        // S(50, 200) starts before 100, so its start (50) is fixed.
762        // Its end (200) is at/after 100, so its end should move to 210.
763        assert_eq!(
764            get_pos(&tree, id_s),
765            (50, 210),
766            "Spanning marker end did not move correctly."
767        );
768    }
769
770    #[test]
771    fn test_deletion_engulfing_marker_start() {
772        let mut tree = IntervalTree::new();
773        let id1 = insert_marker(&mut tree, 8, 20);
774
775        // Delete 10 chars at pos 5. Deletion is on [5, 15).
776        // Marker is on [8, 20). The part [8, 15) is deleted.
777        // New start should be clamped at the deletion position: 5.
778        // End is adjusted by delta: 20 - 10 = 10.
779        // So new interval should be (5, 10).
780        tree.adjust_for_edit(5, -10);
781
782        assert_eq!(
783            get_pos(&tree, id1),
784            (5, 10),
785            "Marker should be clamped and shrunk."
786        );
787    }
788
789    #[test]
790    fn test_zero_length_marker() {
791        let mut tree = IntervalTree::new();
792        let id1 = insert_marker(&mut tree, 10, 10);
793
794        // Insertion at the marker's position should push it.
795        tree.adjust_for_edit(10, 5);
796        assert_eq!(
797            get_pos(&tree, id1),
798            (15, 15),
799            "Insertion at zero-length marker."
800        );
801
802        // Insertion before should also push it.
803        tree.adjust_for_edit(5, 5);
804        assert_eq!(
805            get_pos(&tree, id1),
806            (20, 20),
807            "Insertion before zero-length marker."
808        );
809
810        // Deletion after should not affect it.
811        tree.adjust_for_edit(25, -5);
812        assert_eq!(
813            get_pos(&tree, id1),
814            (20, 20),
815            "Deletion after zero-length marker."
816        );
817
818        // Deletion that contains the marker.
819        tree.adjust_for_edit(15, -10);
820        // Marker at 20. Deletion on [15, 25).
821        // Start becomes max(15, 20-10) = 15.
822        // End becomes max(new_start, 20-10) = max(15, 10) = 15.
823        assert_eq!(
824            get_pos(&tree, id1),
825            (15, 15),
826            "Deletion containing zero-length marker."
827        );
828    }
829
830    #[test]
831    fn test_edit_at_pos_zero() {
832        let mut tree = IntervalTree::new();
833        let id1 = insert_marker(&mut tree, 10, 20);
834
835        // Insertion at pos 0
836        tree.adjust_for_edit(0, 5);
837        assert_eq!(get_pos(&tree, id1), (15, 25), "Insertion at pos 0.");
838
839        // Deletion at pos 0
840        tree.adjust_for_edit(0, -5);
841        assert_eq!(get_pos(&tree, id1), (10, 20), "Deletion at pos 0.");
842
843        // Deletion at pos 0 that engulfs the start.
844        tree.adjust_for_edit(0, -15);
845        // Marker at (10, 20). Deletion on [0, 15).
846        // New start becomes max(0, 10-15) = 0.
847        // New end becomes max(new_start, 20-15) = max(0, 5) = 5.
848        assert_eq!(get_pos(&tree, id1), (0, 5), "Engulfing deletion at pos 0.");
849    }
850
851    #[test]
852    fn test_deletion_preserves_marker_ordering() {
853        // This test reproduces the bug found in prop_marker_ordering_preserved
854        // where lazy delta propagation causes ordering violations.
855        let mut tree = IntervalTree::new();
856
857        // Create markers in order: [0, 10, 20, 30, 40] (spacing=10)
858        let id0 = insert_marker(&mut tree, 0, 0);
859        let id1 = insert_marker(&mut tree, 10, 10);
860        let id2 = insert_marker(&mut tree, 20, 20);
861        let id3 = insert_marker(&mut tree, 30, 30);
862        let id4 = insert_marker(&mut tree, 40, 40);
863
864        // Verify initial state
865        assert_eq!(get_pos(&tree, id0), (0, 0));
866        assert_eq!(get_pos(&tree, id1), (10, 10));
867        assert_eq!(get_pos(&tree, id2), (20, 20));
868        assert_eq!(get_pos(&tree, id3), (30, 30));
869        assert_eq!(get_pos(&tree, id4), (40, 40));
870
871        // Delete 16 bytes starting at position 5
872        // This deletes range [5, 21)
873        // Expected positions after: [0, 5, 5, 14, 24]
874        tree.adjust_for_edit(5, -16);
875
876        // Get all positions
877        let positions = vec![
878            get_pos(&tree, id0).0,
879            get_pos(&tree, id1).0,
880            get_pos(&tree, id2).0,
881            get_pos(&tree, id3).0,
882            get_pos(&tree, id4).0,
883        ];
884
885        // Verify ordering is preserved (no inversions)
886        for i in 0..positions.len() - 1 {
887            assert!(
888                positions[i] <= positions[i + 1],
889                "Ordering violated at index {}: {:?}[{}]={} > {:?}[{}]={}",
890                i,
891                positions,
892                i,
893                positions[i],
894                positions,
895                i + 1,
896                positions[i + 1]
897            );
898        }
899
900        // Verify specific expected positions
901        assert_eq!(get_pos(&tree, id0), (0, 0), "Marker at 0 should stay at 0");
902        assert_eq!(
903            get_pos(&tree, id1),
904            (5, 5),
905            "Marker at 10 should clamp to 5"
906        );
907        assert_eq!(
908            get_pos(&tree, id2),
909            (5, 5),
910            "Marker at 20 should clamp to 5"
911        );
912        assert_eq!(
913            get_pos(&tree, id3),
914            (14, 14),
915            "Marker at 30 should shift to 14"
916        );
917        assert_eq!(
918            get_pos(&tree, id4),
919            (24, 24),
920            "Marker at 40 should shift to 24"
921        );
922    }
923}