Skip to main content

piece_tree/
lib.rs

1#![cfg_attr(not(feature = "write"), no_std)]
2
3#![cfg_attr(all(not(feature = "runtime-dispatch-simd"), feature = "generic-simd"), feature(portable_simd))]
4
5#![warn(clippy::all, clippy::pedantic, dead_code, clippy::cargo)]
6#![allow(
7    unused_assignments,
8    clippy::inline_always,
9    clippy::uninlined_format_args, // ?...
10    clippy::borrow_as_ptr,
11    clippy::negative_feature_names,
12    clippy::redundant_closure_for_method_calls,
13    clippy::sliced_string_as_bytes,
14    clippy::should_implement_trait,
15    clippy::collapsible_if,
16    clippy::new_without_default,
17    clippy::comparison_chain,
18    clippy::redundant_field_names,
19    clippy::semicolon_if_nothing_returned,
20    clippy::pub_underscore_fields,
21    clippy::struct_field_names,
22    clippy::ptr_as_ptr,
23    clippy::missing_transmute_annotations,
24    clippy::multiple_crate_versions,
25    clippy::cast_precision_loss,
26    clippy::cast_possible_truncation,
27    clippy::similar_names,
28    clippy::cast_sign_loss,
29    clippy::cast_possible_wrap,
30    clippy::used_underscore_binding,
31    clippy::nonstandard_macro_braces,
32    clippy::used_underscore_items,
33    clippy::enum_glob_use,
34    clippy::cast_lossless,
35    clippy::match_same_arms,
36    clippy::too_many_lines,
37    clippy::unnested_or_patterns,
38    clippy::blocks_in_conditions,
39    clippy::missing_errors_doc,
40    clippy::missing_panics_doc,
41)]
42
43#[cfg(feature = "write")]
44extern crate std;
45
46extern crate alloc;
47
48#[allow(unused)]
49use alloc::vec;
50use alloc::vec::Vec;
51use alloc::sync::Arc;
52use alloc::string::{String, ToString};
53
54use core::str;
55use core::cmp::Ordering;
56use core::ops::{Bound, Deref, RangeBounds};
57
58#[cfg(not(feature = "dont_vendor"))]
59mod cranelift_entity_vendor;
60#[cfg(not(feature = "dont_vendor"))]
61use cranelift_entity_vendor as cranelift_entity;
62
63#[cfg(not(feature = "dont_vendor"))]
64mod smallvec_vendor;
65#[cfg(not(feature = "dont_vendor"))]
66use smallvec_vendor as smallvec;
67
68#[cfg(not(feature = "dont_vendor"))]
69mod bytecount_vendor;
70#[cfg(not(feature = "dont_vendor"))]
71use bytecount_vendor as bytecount;
72
73use smallvec::SmallVec;
74use cranelift_entity::{EntityRef, PrimaryMap};
75#[cfg(feature = "dont_vendor")]
76use cranelift_entity::entity_impl;
77
78#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
79pub struct BufferRef(pub u32);
80entity_impl!(BufferRef);
81
82#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
83pub struct NodeRef(pub u32);
84entity_impl!(NodeRef);
85
86pub const NIL: NodeRef = NodeRef(0);
87
88pub const MOD_BUFFER: BufferRef = BufferRef(u32::MAX >> 1);
89
90pub const CHECKPOINT_INTERVAL: u32 = 64;
91
92#[derive(Clone, Copy, PartialEq, Eq, Debug)]
93pub enum Color { Black = 0, Red = 1 }
94
95#[derive(Clone, Copy, Debug)]
96pub struct HistoryEntry {
97    pub root:          NodeRef,
98    pub cursor_offset: u32,
99}
100
101#[derive(Default, Clone, Copy, Debug, PartialEq, Eq)]
102pub struct Piece {
103    pub buffer:            BufferRef,
104
105    pub byte_offset:       u32,
106    pub byte_length:       u32,
107
108    pub newline_count:     u32,
109    pub char_count:        u32,
110
111    pub buffer_start_line: u32,  // Index into that buffer's `newline_offsets` array of this piece's first '\n'
112
113    pub piece_start_char:  u32,  // Absolute char index of p.offset in its buffer
114}
115
116// For tests and other stuff
117#[derive(Clone, Copy, Debug)]
118pub enum Edit {
119    Insert { offset: u32, text: &'static str },
120    Remove { offset: u32, length: u32 },
121}
122
123impl Edit {
124    #[inline(always)]
125    #[must_use]
126    pub fn offset(&self) -> u32 {
127        match self {
128            Edit::Insert { offset, .. } => *offset,
129            Edit::Remove { offset, .. } => *offset,
130        }
131    }
132}
133
134#[derive(Clone, Copy, Debug)]
135#[repr(C)]
136pub struct Node {
137    pub left:              NodeRef, // 4 bytes
138    pub right:             NodeRef, // 4 bytes
139    pub offset:            u32,     // 4 bytes
140    pub subtree_len:       u32,     // 4 bytes
141    pub subtree_chars:     u32,     // 4 bytes
142    pub subtree_newlines:  u32,     // 4 bytes
143    pub meta:              u32,     // 4 bytes (Bit 0: Color, Bits 1..31: BufferIndex)
144    pub buffer_start_line: u32,     // 4 bytes
145    pub piece_start_char:  u32,     // 4 bytes
146}
147
148const _: () = assert!(size_of::<Node>() == 36);
149
150impl Node {
151    #[inline(always)]
152    #[must_use]
153    pub fn color(&self) -> Color {
154        if (self.meta & 1) == 1 { Color::Red } else { Color::Black }
155    }
156
157    #[inline(always)]
158    pub fn set_color(&mut self, color: Color) {
159        self.meta = (self.meta & !1) | (color as u32);
160    }
161
162    #[inline(always)]
163    #[must_use]
164    pub fn buffer_index(&self) -> BufferRef {
165        BufferRef(self.meta >> 1)
166    }
167
168    #[inline(always)]
169    pub fn set_buffer(&mut self, buffer: BufferRef) {
170        self.meta = (buffer.as_u32() << 1) | (self.meta & 1);
171    }
172}
173
174#[derive(Debug, Clone)]
175pub struct OriginalBuffer {
176    pub text:             Arc<str>,
177    pub newline_offsets:  Arc<[u32]>,
178    pub char_checkpoints: Arc<[(u32, u32)]>,
179}
180
181impl Deref for OriginalBuffer {
182    type Target = str;
183
184    #[inline(always)]
185    fn deref(&self) -> &Self::Target {
186        self.text.as_ref()
187    }
188}
189
190#[derive(Debug, Clone)]
191pub struct Buffers {
192    pub original_buffers: PrimaryMap<BufferRef, OriginalBuffer>,
193
194    pub modifications_char_count:       u32,
195    pub modifications_buffer:           String,
196    pub modifications_newline_offsets:  Vec<u32>,
197    pub modifications_char_checkpoints: Vec<(u32, u32)>,
198}
199
200impl Default for Buffers {
201    #[inline(always)]
202    fn default() -> Self {
203        Self {
204            original_buffers: PrimaryMap::new(),
205            modifications_char_count: 0,
206            modifications_newline_offsets: Vec::with_capacity(1024),
207            modifications_char_checkpoints: Vec::with_capacity(128),
208            modifications_buffer: String::with_capacity(1024 * 64),
209        }
210    }
211}
212
213#[must_use]
214#[inline(always)]
215pub fn count_chars_and_newlines(bytes: &[u8]) -> (u32, u32) {
216    let mut chars    = 0u32;
217    let mut newlines = 0u32;
218
219    for &b in bytes {
220        newlines += (b == b'\n')         as u32;
221        chars    += ((b & 0xC0) != 0x80) as u32;
222    }
223
224    (chars, newlines)
225}
226
227#[must_use]
228#[inline(always)]
229pub fn count_chars_and_newlines_with_offsets_and_checkpoints(
230    bytes: &[u8],
231    offsets: &mut Vec<u32>,
232    checkpoints: &mut Vec<(u32, u32)>,
233) -> (u32, u32) {
234    let mut chars    = 0u32;
235    let mut newlines = 0u32;
236
237    let mut next_checkpoint = CHECKPOINT_INTERVAL;
238
239    for (i, &b) in bytes.iter().enumerate() {
240        if (b as i8) >= -0x40 {
241            if chars == next_checkpoint {
242                checkpoints.push((chars, i as u32));
243                next_checkpoint += CHECKPOINT_INTERVAL;
244            }
245            chars += 1;
246        }
247
248        if b == b'\n' {
249            offsets.push(i as u32);
250            newlines += 1;
251        }
252    }
253
254    (chars, newlines)
255}
256
257impl Buffers {
258    #[inline(always)]
259    #[must_use]
260    pub fn new() -> Self { Self::default() }
261
262    #[inline(always)]
263    #[must_use]
264    pub fn get(&self, buffer: BufferRef) -> &str {
265        if buffer == MOD_BUFFER {
266            &self.modifications_buffer
267        } else {
268            &self.original_buffers[buffer]
269        }
270    }
271
272    #[inline(always)]
273    #[must_use]
274    pub fn get_slice(&self, buffer: BufferRef, offset: u32, len: u32) -> &str {
275        let buf = self.get(buffer);
276        let start = offset as usize;
277        let end = start + len as usize;
278        unsafe { str::from_utf8_unchecked(buf.as_bytes().get_unchecked(start..end)) }
279    }
280
281    #[inline]
282    #[must_use]
283    pub fn count_chars_and_newlines(&self, buffer: BufferRef, start_offset: u32, len: u32) -> (u32, u32) {
284        if len == 0 { return (0, 0) }
285
286        let end_offset = start_offset + len;
287
288        //
289        // O(log N) newlines count
290        //
291        let nl_offsets = self.get_newlines(buffer);
292        let start_nl_index = nl_offsets.binary_search(&start_offset).unwrap_or_else(|x| x);
293        let end_nl_index = nl_offsets.binary_search(&end_offset).unwrap_or_else(|x| x);
294        let newlines = (end_nl_index - start_nl_index) as u32;
295
296        //
297        // O(log N) char count
298        //
299
300        let checkpoints = self.get_checkpoints(buffer);
301        let buffer_text = self.get(buffer);
302
303        //
304        // Gets absolute char count from start of buffer to `target_offset`
305        //
306        let chars_up_to = |target_offset: u32| -> u32 {
307            if target_offset == 0 { return 0; }
308
309            //
310            // Find the index of the first checkpoint that is strictly strictly greater than our target
311            //
312            let partition_index = checkpoints.partition_point(|&(_char_cnt, byte_offset)| byte_offset <= target_offset);
313
314            let (base_chars, base_bytes) = if partition_index > 0 {
315                checkpoints[partition_index - 1]
316            } else {
317                (0, 0)
318            };
319
320            //
321            // Linearly scan only the remaining bytes from the checkpoint to the target
322            //
323            let tail_bytes = &buffer_text[base_bytes as usize .. target_offset as usize];
324            base_chars + bytecount::num_chars(tail_bytes.as_bytes()) as u32
325        };
326
327        let chars = chars_up_to(end_offset) - chars_up_to(start_offset);
328
329        (chars, newlines)
330    }
331
332    #[inline(always)]
333    #[must_use]
334    pub fn count_chars(&self, buffer: BufferRef, offset: u32, len: u32) -> u32 {
335        bytecount::num_chars(self.get_slice(buffer, offset, len).as_bytes()) as u32
336    }
337
338    #[inline(always)]
339    #[must_use]
340    pub fn count_newlines(&self, buffer: BufferRef, offset: u32, len: u32) -> u32 {
341        bytecount::count(self.get_slice(buffer, offset, len).as_bytes(), b'\n') as _
342    }
343
344    #[inline(always)]
345    fn get_newlines(&self, buffer: BufferRef) -> &[u32] {
346        if buffer == MOD_BUFFER {
347            &self.modifications_newline_offsets
348        } else {
349            &self.original_buffers[buffer].newline_offsets
350        }
351    }
352
353    #[inline(always)]
354    fn get_checkpoints(&self, buffer: BufferRef) -> &[(u32, u32)] {
355        if buffer == MOD_BUFFER {
356            &self.modifications_char_checkpoints
357        } else {
358            &self.original_buffers[buffer].char_checkpoints
359        }
360    }
361
362    /// Converts an absolute char index to an absolute byte offset for a specific buffer
363    #[must_use]
364    #[inline]
365    pub fn char_to_byte_absolute(&self, buffer: BufferRef, target_char: u32) -> u32 {
366        if target_char == 0 { return 0; }
367
368        let checkpoints = self.get_checkpoints(buffer);
369        let cp_index = checkpoints.partition_point(|&(c, _)| c <= target_char);
370
371        let (current_char, current_byte) = if cp_index == 0 {
372            (0, 0)
373        } else {
374            unsafe { *checkpoints.get_unchecked(cp_index - 1) }
375        };
376
377        let remainder_chars = target_char - current_char;
378        if remainder_chars == 0 { return current_byte; }
379
380        let text = self.get(buffer);
381        let slice = unsafe { text.get_unchecked(current_byte as usize..) };
382
383        let additional_bytes = slice
384            .char_indices()
385            .nth(remainder_chars as usize).map_or_else(|| slice.len() as u32, |(b, _)| b as u32);  // Fallback to end if out of bounds
386
387        current_byte + additional_bytes
388    }
389
390    /// Converts an absolute byte offset to an absolute char index for a specific buffer
391    #[must_use]
392    #[inline]
393    pub fn byte_to_char_absolute(&self, buffer: BufferRef, target_byte: u32) -> u32 {
394        if target_byte == 0 { return 0; }
395
396        let checkpoints = self.get_checkpoints(buffer);
397        let cp_index = checkpoints.partition_point(|&(_, b)| b <= target_byte);
398
399        let (current_char, current_byte) = if cp_index == 0 {
400            (0, 0)
401        } else {
402            unsafe { *checkpoints.get_unchecked(cp_index - 1) }
403        };
404
405        let remainder_bytes = target_byte - current_byte;
406        if remainder_bytes == 0 { return current_char; }
407
408        let text = self.get(buffer);
409        let slice = unsafe { text.get_unchecked(current_byte as usize..target_byte as usize) };
410        let additional_chars = bytecount::num_chars(slice.as_bytes()) as u32;
411
412        current_char + additional_chars
413    }
414}
415
416#[derive(Debug, Clone)]
417pub struct Pieces {
418    pub nodes: PrimaryMap<NodeRef, Node>,
419}
420
421impl Default for Pieces {
422    #[inline(always)]
423    fn default() -> Self {
424        Self::new()
425    }
426}
427
428impl Pieces {
429    #[inline(always)]
430    #[must_use]
431    pub fn new() -> Self {
432        let mut nodes = PrimaryMap::new();
433        nodes.push(Node {
434            left: NIL, right: NIL, offset: 0,
435            subtree_len: 0, subtree_chars: 0, subtree_newlines: 0,
436            meta: 0, buffer_start_line: 0,
437            piece_start_char: 0
438        });
439        Self { nodes }
440    }
441
442    #[inline(always)]
443    #[must_use]
444    pub fn len(&self) -> usize { self.nodes.len() }
445
446    #[inline(always)]
447    #[must_use]
448    pub fn is_empty(&self) -> bool { self.nodes.is_empty() }
449
450    #[inline(always)]
451    #[must_use]
452    pub fn get(&self, index: NodeRef) -> &Node { &self.nodes[index] }
453
454    #[inline(always)]
455    #[must_use]
456    pub fn get_piece(&self, index: NodeRef) -> Piece {
457        if index == NIL { return Piece::default(); }
458
459        let node = &self.nodes[index];
460        let l = &self.nodes[node.left];
461        let r = &self.nodes[node.right];
462
463        Piece {
464            buffer: node.buffer_index(),
465            byte_offset: node.offset,
466            byte_length: node.subtree_len - l.subtree_len - r.subtree_len,
467            char_count: node.subtree_chars - l.subtree_chars - r.subtree_chars,
468            newline_count: node.subtree_newlines - l.subtree_newlines - r.subtree_newlines,
469            buffer_start_line: node.buffer_start_line,
470            piece_start_char: node.piece_start_char,
471        }
472    }
473
474    #[inline(always)]
475    pub fn alloc(&mut self, color: Color, left: NodeRef, piece: Piece, right: NodeRef) -> NodeRef {
476        let l = &self.nodes[left];
477        let r = &self.nodes[right];
478
479        let mut node = Node {
480            left, right,
481            offset: piece.byte_offset,
482            subtree_len: l.subtree_len + piece.byte_length + r.subtree_len,
483            subtree_chars: l.subtree_chars + piece.char_count + r.subtree_chars,
484            subtree_newlines: l.subtree_newlines + piece.newline_count + r.subtree_newlines,
485            buffer_start_line: piece.buffer_start_line,
486            piece_start_char: piece.piece_start_char,
487            meta: 0,
488        };
489        node.set_color(color);
490        node.set_buffer(piece.buffer);
491
492        self.nodes.push(node)
493    }
494
495    /// Extends a piece without triggering Red-Black structural changes.
496    /// It creates a single new path to the root to maintain persistence.
497    pub fn extend_piece(
498        &mut self,
499        root: NodeRef,
500        piece_start_offset: u32,
501        add_len: u32,
502        add_chars: u32,
503        add_nl: u32,
504    ) -> NodeRef {
505        if root == NIL { return NIL }
506
507        let node = self.nodes[root];
508        let mut new_node = node;
509
510        let left_len = self.nodes[node.left].subtree_len;
511        let piece_len = node.subtree_len - left_len - self.nodes[node.right].subtree_len;
512
513        if piece_start_offset < left_len {
514            new_node.left  = self.extend_piece(node.left, piece_start_offset, add_len, add_chars, add_nl);
515        } else if piece_start_offset > left_len {
516            new_node.right = self.extend_piece(node.right, piece_start_offset - (left_len + piece_len), add_len, add_chars, add_nl);
517        } else {
518            // piece_start_offset == left_len
519            // We found the exact node! No further recursion needed.
520        }
521
522        new_node.subtree_len      += add_len;
523        new_node.subtree_chars    += add_chars;
524        new_node.subtree_newlines += add_nl;
525
526        self.nodes.push(new_node)
527    }
528
529    #[inline]
530    pub fn insert_node(&mut self, root: NodeRef, piece: Piece, at: u32) -> NodeRef {
531        let new_root = self.ins(root, piece, at, 0);
532        let r_node = self.nodes[new_root];
533        let p = self.get_piece(new_root);
534        self.alloc(Color::Black, r_node.left, p, r_node.right)
535    }
536
537    #[inline]
538    pub fn remove_node(&mut self, root: NodeRef, at: u32) -> NodeRef {
539        let new_root = self.rem(root, at, 0);
540        if new_root == NIL { return NIL }
541
542        let r_node = self.nodes[new_root];
543        self.alloc(Color::Black, r_node.left, self.get_piece(new_root), r_node.right)
544    }
545
546    #[inline]
547    fn rem(&mut self, root: NodeRef, at: u32, total: u32) -> NodeRef {
548        if root == NIL { return NIL }
549
550        let node = self.nodes[root];
551        let node_piece = self.get_piece(root);
552        let left_len = self.nodes[node.left].subtree_len;
553
554        match at.cmp(&(total + left_len)) {
555            Ordering::Less => self.remove_left(root, at, total),
556            Ordering::Equal => self.fuse(node.left, node.right),
557            Ordering::Greater => {
558                let next_total = total + left_len + node_piece.byte_length;
559                self.remove_right(root, at, next_total)
560            }
561        }
562    }
563
564    #[inline]
565    fn remove_left(&mut self, root: NodeRef, at: u32, total: u32) -> NodeRef {
566        let node = self.nodes[root];
567        let new_left = self.rem(node.left, at, total);
568        let new_node = self.alloc(Color::Red, new_left, self.get_piece(root), node.right);
569        if self.nodes[node.left].color() == Color::Black {
570            self.balance_left(new_node)
571        } else {
572            new_node
573        }
574    }
575
576    #[inline]
577    fn remove_right(&mut self, root: NodeRef, at: u32, total: u32) -> NodeRef {
578        let node = self.nodes[root];
579        let new_right = self.rem(node.right, at, total);
580        let new_node = self.alloc(Color::Red, node.left, self.get_piece(root), new_right);
581        if self.nodes[node.right].color() == Color::Black {
582            self.balance_right(new_node)
583        } else {
584            new_node
585        }
586    }
587
588    #[inline]
589    fn ins(&mut self, root: NodeRef, p: Piece, at: u32, total_offset: u32) -> NodeRef {
590        if root == NIL { return self.alloc(Color::Red, NIL, p, NIL); }
591
592        let node = self.nodes[root];
593        let node_piece = self.get_piece(root);
594        let left_len = self.nodes[node.left].subtree_len;
595
596        if at < total_offset + left_len + node_piece.byte_length {
597            let lft = self.ins(node.left, p, at, total_offset);
598            self.balance(node.color(), lft, node_piece, node.right)
599        } else {
600            let next_offset = total_offset + left_len + node_piece.byte_length;
601            let rgt = self.ins(node.right, p, at, next_offset);
602            self.balance(node.color(), node.left, node_piece, rgt)
603        }
604    }
605
606    #[inline]
607    fn balance(&mut self, c: Color, l_index: NodeRef, p: Piece, r_index: NodeRef) -> NodeRef {
608        let l = self.nodes[l_index];
609        let r = self.nodes[r_index];
610
611        if c == Color::Black {
612            if l.color() == Color::Red {
613                let ll = self.nodes[l.left];
614                let lr = self.nodes[l.right];
615                if ll.color() == Color::Red {
616                    let new_l = self.alloc(Color::Black, ll.left, self.get_piece(l.left), ll.right);
617                    let new_r = self.alloc(Color::Black, l.right, p, r_index);
618                    return self.alloc(Color::Red, new_l, self.get_piece(l_index), new_r);
619                } else if lr.color() == Color::Red {
620                    let new_l = self.alloc(Color::Black, l.left, self.get_piece(l_index), lr.left);
621                    let new_r = self.alloc(Color::Black, lr.right, p, r_index);
622                    return self.alloc(Color::Red, new_l, self.get_piece(l.right), new_r);
623                }
624            }
625
626            if r.color() == Color::Red {
627                let rl = self.nodes[r.left];
628                let rr = self.nodes[r.right];
629                if rl.color() == Color::Red {
630                    let new_l = self.alloc(Color::Black, l_index, p, rl.left);
631                    let new_r = self.alloc(Color::Black, rl.right, self.get_piece(r_index), r.right);
632                    return self.alloc(Color::Red, new_l, self.get_piece(r.left), new_r);
633                } else if rr.color() == Color::Red {
634                    let new_l = self.alloc(Color::Black, l_index, p, r.left);
635                    let new_r = self.alloc(Color::Black, rr.left, self.get_piece(r.right), rr.right);
636                    return self.alloc(Color::Red, new_l, self.get_piece(r_index), new_r);
637                }
638            }
639        }
640
641        self.alloc(c, l_index, p, r_index)
642    }
643
644    #[inline]
645    fn fuse(&mut self, left: NodeRef, right: NodeRef) -> NodeRef {
646        // match: (left, right)
647
648        // case: (None, r)
649        if left  == NIL { return right }
650        if right == NIL { return left }
651
652        let l_node = self.nodes[left];
653        let r_node = self.nodes[right];
654
655        // match: (left.color, right.color)
656
657        // case: (B, R)
658        if l_node.color() == Color::Black && r_node.color() == Color::Red {
659            let fused = self.fuse(left, r_node.left);
660            return self.alloc(Color::Red, fused, self.get_piece(right), r_node.right);
661        }
662
663        // case: (R, B)
664        if l_node.color() == Color::Red && r_node.color() == Color::Black {
665            let fused = self.fuse(l_node.right, right);
666            return self.alloc(Color::Red, l_node.left, self.get_piece(left), fused);
667        }
668
669        // case: (R, R)
670        if l_node.color() == Color::Red && r_node.color() == Color::Red {
671            let fused = self.fuse(l_node.right, r_node.left);
672            let f_node = self.nodes[fused];
673            if fused != NIL && f_node.color() == Color::Red {
674                let new_l = self.alloc(Color::Red, l_node.left, self.get_piece(left), f_node.left);
675                let new_r = self.alloc(Color::Red, f_node.right, self.get_piece(right), r_node.right);
676                return self.alloc(Color::Red, new_l, self.get_piece(fused), new_r);
677            }
678            let new_r = self.alloc(Color::Red, fused, self.get_piece(right), r_node.right);
679            return self.alloc(Color::Red, l_node.left, self.get_piece(left), new_r);
680        }
681
682        // case: (B, B)
683
684        let fused = self.fuse(l_node.right, r_node.left);
685        let f_node = self.nodes[fused];
686        if fused != NIL && f_node.color() == Color::Red {
687            let new_l = self.alloc(Color::Black, l_node.left, self.get_piece(left), f_node.left);
688            let new_r = self.alloc(Color::Black, f_node.right, self.get_piece(right), r_node.right);
689            return self.alloc(Color::Red, new_l, self.get_piece(fused), new_r);
690        }
691
692        let new_r = self.alloc(Color::Black, fused, self.get_piece(right), r_node.right);
693        let new_node = self.alloc(Color::Red, l_node.left, self.get_piece(left), new_r);
694        self.balance_left(new_node)
695    }
696
697    #[inline]
698    fn balance_left(&mut self, left: NodeRef) -> NodeRef {
699        let l_node = self.nodes[left];
700        let ll_node = self.nodes[l_node.left];
701        let lr_node = self.nodes[l_node.right];
702
703        // match: (color_l, color_r, color_r_l)
704
705        // case: (Some(R), ..)
706        if l_node.left != NIL && ll_node.color() == Color::Red {
707            let new_ll = self.alloc(Color::Black, ll_node.left, self.get_piece(l_node.left), ll_node.right);
708            return self.alloc(Color::Red, new_ll, self.get_piece(left), l_node.right);
709        }
710
711        // case: (_, Some(B), _)
712        if l_node.right != NIL && lr_node.color() == Color::Black {
713            let new_lr = self.alloc(Color::Red, lr_node.left, self.get_piece(l_node.right), lr_node.right);
714            let new_l = self.alloc(Color::Black, l_node.left, self.get_piece(left), new_lr);
715            let nl = self.nodes[new_l];
716            return self.balance(Color::Black, nl.left, self.get_piece(new_l), nl.right);
717        }
718
719        // case: (_, Some(R), Some(B))
720        if l_node.right != NIL && lr_node.color() == Color::Red {
721            let lrl_node = self.nodes[lr_node.left];
722            if lr_node.left != NIL && lrl_node.color() == Color::Black {
723                let lrr_node = self.nodes[lr_node.right];
724                let new_lrr = self.alloc(Color::Red, lrr_node.left, self.get_piece(lr_node.right), lrr_node.right);
725                let unbal_r = self.alloc(Color::Black, lrl_node.right, self.get_piece(l_node.right), new_lrr);
726                let ur_node = self.nodes[unbal_r];
727                let new_r = self.balance(ur_node.color(), ur_node.left, self.get_piece(unbal_r), ur_node.right);
728                let new_l = self.alloc(Color::Black, l_node.left, self.get_piece(left), lrl_node.left);
729                return self.alloc(Color::Red, new_l, self.get_piece(lr_node.left), new_r);
730            }
731        }
732
733        left
734    }
735
736    #[inline]
737    fn balance_right(&mut self, right: NodeRef) -> NodeRef {
738        let r_node = self.nodes[right];
739        let rl_node = self.nodes[r_node.left];
740        let rr_node = self.nodes[r_node.right];
741
742        // match: (color_l, color_l_r, color_r)
743
744        // case: (.., Some(R))
745        if r_node.right != NIL && rr_node.color() == Color::Red {
746            let new_rr = self.alloc(Color::Black, rr_node.left, self.get_piece(r_node.right), rr_node.right);
747            return self.alloc(Color::Red, r_node.left, self.get_piece(right), new_rr);
748        }
749
750        // case: (Some(B), ..)
751        if r_node.left != NIL && rl_node.color() == Color::Black {
752            let new_rl = self.alloc(Color::Red, rl_node.left, self.get_piece(r_node.left), rl_node.right);
753            let new_r = self.alloc(Color::Black, new_rl, self.get_piece(right), r_node.right);
754            let nr = self.nodes[new_r];
755            return self.balance(Color::Black, nr.left, self.get_piece(new_r), nr.right);
756        }
757
758        // case: (Some(R), Some(B), _)
759        if r_node.left != NIL && rl_node.color() == Color::Red {
760            let rlr_node = self.nodes[rl_node.right];
761            if rl_node.right != NIL && rlr_node.color() == Color::Black {
762                let rll_node = self.nodes[rl_node.left];
763                let new_rll = self.alloc(Color::Red, rll_node.left, self.get_piece(rl_node.left), rll_node.right);
764                let unbal_l = self.alloc(Color::Black, new_rll, self.get_piece(r_node.left), rlr_node.left);
765                let ul_node = self.nodes[unbal_l];
766                let new_l = self.balance(ul_node.color(), ul_node.left, self.get_piece(unbal_l), ul_node.right);
767                let new_r = self.alloc(Color::Black, rlr_node.right, self.get_piece(right), r_node.right);
768                return self.alloc(Color::Red, new_l, self.get_piece(rl_node.right), new_r);
769            }
770        }
771
772        right
773    }
774
775    #[inline]
776    #[must_use]
777    pub fn find_offset(
778        &self,
779        mut root: NodeRef,
780        mut target_offset: u32,
781        prefer_left: bool
782    ) -> Option<(NodeRef, u32)> {
783        while root != NIL {
784            let node = &self.nodes[root];
785            let left_len = self.nodes[node.left].subtree_len;
786            let piece_len = self.get_piece(root).byte_length;
787
788            if target_offset < left_len {
789                root = node.left;
790
791            } else if target_offset == left_len + piece_len && prefer_left {
792                // We are perfectly on the boundary and want to merge with the left piece
793                return Some((root, piece_len));
794
795            } else if target_offset < left_len + piece_len {
796                return Some((root, target_offset - left_len));
797
798            } else {
799                target_offset -= left_len + piece_len;
800                root = node.right;
801            }
802        }
803
804        None
805    }
806}
807
808impl PieceTree {
809    /// Slices a tree exactly at `offset`, returning (`LeftTree`, `RightTree`)
810    #[inline]
811    pub fn split(&mut self, root: NodeRef, offset: u32) -> (NodeRef, NodeRef) {
812        if root == NIL {
813            return (NIL, NIL);
814        }
815
816        let node = self.pieces.nodes[root];
817        let p = self.pieces.get_piece(root);
818        let left_len = self.pieces.nodes[node.left].subtree_len;
819
820        if offset < left_len {
821            let (ll, lr) = self.split(node.left, offset);
822
823            // Fast path: Use join_with_middle directly
824            let new_right = self.pieces.join_with_middle(lr, p, node.right);
825            (ll, new_right)
826
827        } else if offset > left_len + p.byte_length {
828            let (rl, rr) = self.split(node.right, offset - left_len - p.byte_length);
829
830            // Fast path: Use join_with_middle directly
831            let new_left = self.pieces.join_with_middle(node.left, p, rl);
832            (new_left, rr)
833
834        } else {
835            let rel_offset = offset - left_len;
836
837            if rel_offset == 0 {
838                (node.left, self.pieces.join_with_middle(NIL, p, node.right))
839
840            } else if rel_offset == p.byte_length {
841                (self.pieces.join_with_middle(node.left, p, NIL), node.right)
842
843            } else {
844                //
845                // We have to slice the Piece exactly in half!
846                //
847                let left_len = rel_offset;
848                let right_len = p.byte_length - rel_offset;
849
850                //
851                // Only scan the smaller half of the piece to avoid O(N) bottlenecks
852                //
853                let (left_chars, left_nl) = if left_len <= right_len {
854                    // Left side is shorter, scan normally
855                    self.buffers.count_chars_and_newlines(p.buffer, p.byte_offset, left_len)
856                } else {
857                    // Right side is shorter, scan it and subtract from the known totals
858                    let (r_chars, r_nl) = self.buffers.count_chars_and_newlines(
859                        p.buffer, p.byte_offset + left_len, right_len
860                    );
861
862                    (p.char_count - r_chars, p.newline_count - r_nl)
863                };
864
865                let left_stump = Piece {
866                    buffer: p.buffer,
867                    byte_offset: p.byte_offset,
868                    byte_length: left_len,
869                    newline_count: left_nl,
870                    char_count: left_chars,
871                    buffer_start_line: p.buffer_start_line,
872                    piece_start_char: p.piece_start_char,
873                };
874
875                let right_stump = Piece {
876                    buffer: p.buffer,
877                    byte_offset: p.byte_offset + left_len,
878                    byte_length: right_len,
879                    newline_count: p.newline_count - left_nl,
880                    char_count: p.char_count - left_chars,
881                    buffer_start_line: p.buffer_start_line + left_nl,
882                    piece_start_char: p.piece_start_char + left_chars,
883                };
884
885                let new_left = self.pieces.join_with_middle(node.left, left_stump, NIL);
886                let new_right = self.pieces.join_with_middle(NIL, right_stump, node.right);
887                (new_left, new_right)
888            }
889        }
890    }
891
892    /// Glues two arbitrary trees together by extracting the max element of the left tree
893    #[inline]
894    pub fn concat(&mut self, left: NodeRef, right: NodeRef) -> NodeRef {
895        //
896        // Group the evaluation so we can force a Black root on the way out!
897        //
898        let new_root = if left == NIL {
899            right
900        } else if right == NIL {
901            left
902        } else {
903            let mut curr = left;
904            while self.pieces.nodes[curr].right != NIL {
905                curr = self.pieces.nodes[curr].right;
906            }
907            let max_piece = self.pieces.get_piece(curr);
908            let max_offset = self.pieces.nodes[left].subtree_len - max_piece.byte_length;
909
910            let left_without_max = self.pieces.remove_node(left, max_offset);
911
912            self.pieces.join_with_middle(left_without_max, max_piece, right)
913        };
914
915        //
916        // Even if we early-returned right, we MUST ensure the final returned root is Black.
917        //
918        if new_root != NIL && self.pieces.nodes[new_root].color() == Color::Red {
919            let p = self.pieces.get_piece(new_root);
920            let r = self.pieces.nodes[new_root];
921            return self.pieces.alloc(Color::Black, r.left, p, r.right);
922        }
923
924        new_root
925    }
926}
927
928impl Pieces {
929    /// Recursively counts the black height of a given subtree
930    #[inline(always)]
931    #[must_use]
932    pub fn black_height(&self, mut node: NodeRef) -> u32 {
933        let mut h = 0;
934        while node != NIL {
935            if self.nodes[node].color() == Color::Black {
936                h += 1;
937            }
938            node = self.nodes[node].left;
939        }
940        h
941    }
942
943    /// Safely joins two arbitrary Red-Black trees using a middle element
944    #[inline(always)]
945    pub fn join_with_middle(&mut self, left: NodeRef, piece: Piece, right: NodeRef) -> NodeRef {
946        let hl = self.black_height(left);
947        let hr = self.black_height(right);
948
949        let new_root = if hl > hr {
950            self.join_right(left, piece, right, hl, hr)
951        } else if hr > hl {
952            self.join_left(left, piece, right, hl, hr)
953        } else {
954            self.alloc(Color::Red, left, piece, right)
955        };
956
957        // Enforce the Red-Black root constraint!
958        if new_root != NIL && self.nodes[new_root].color() == Color::Red {
959            let p = self.get_piece(new_root);
960            let r = self.nodes[new_root];
961            return self.alloc(Color::Black, r.left, p, r.right);
962        }
963
964        new_root
965    }
966
967    #[inline(always)]
968    fn join_right(&mut self, left: NodeRef, piece: Piece, right: NodeRef, hl: u32, hr: u32) -> NodeRef {
969        if hl == hr {
970            return self.alloc(Color::Red, left, piece, right);
971        }
972
973        let l_node = self.nodes[left];
974        let next_hl = if l_node.color() == Color::Black { hl - 1 } else { hl };
975
976        let new_right = self.join_right(l_node.right, piece, right, next_hl, hr);
977        let p = self.get_piece(left);
978
979        self.balance(l_node.color(), l_node.left, p, new_right)
980    }
981
982    #[inline(always)]
983    fn join_left(&mut self, left: NodeRef, piece: Piece, right: NodeRef, hl: u32, hr: u32) -> NodeRef {
984        if hl == hr {
985            return self.alloc(Color::Red, left, piece, right);
986        }
987
988        let r_node = self.nodes[right];
989        let next_hr = if r_node.color() == Color::Black { hr - 1 } else { hr };
990
991        let new_left = self.join_left(left, piece, r_node.left, hl, next_hr);
992        let p = self.get_piece(right);
993
994        self.balance(r_node.color(), new_left, p, r_node.right)
995    }
996}
997
998#[derive(Debug, Clone)]
999pub struct PieceTree {
1000    //
1001    // `last_insert_end`      is the mod-buffer offset one past the last inserted byte.
1002    // `last_insert_tree_end` is the document   offset one past that insertion.
1003    //
1004    // Both are u32::MAX when unset (after removes, undos, or on init).
1005    //
1006    last_mod_end:  u32,  // fredbuf's last_insert     (BufferCursor)
1007    last_tree_end: u32,  // fredbuf's end_last_insert (CharOffset)
1008
1009    pub root: NodeRef,
1010
1011    /// Tracks nested undo groups. 0 if we are outside any group.
1012    pub transaction_depth: usize,
1013
1014    pub undo_stack: Vec<HistoryEntry>,
1015    pub redo_stack: Vec<HistoryEntry>,
1016
1017    pub pieces:  Pieces,
1018    pub buffers: Buffers,
1019
1020    pub scratch_index_map: Vec<u32>,
1021}
1022
1023impl Default for PieceTree {
1024    fn default() -> Self {
1025        Self {
1026            last_mod_end:      u32::MAX,
1027            last_tree_end:     u32::MAX,
1028            root:              NIL,
1029            transaction_depth: 0,
1030            undo_stack:        Vec::new(),
1031            redo_stack:        Vec::new(),
1032            pieces:            Pieces::new(),
1033            buffers:           Buffers::new(),
1034            scratch_index_map: Vec::new(),
1035        }
1036    }
1037}
1038
1039impl core::fmt::Display for PieceTree {
1040    #[inline(always)]
1041    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1042        for chunk in self.slice(..).chunks() {
1043            f.write_str(chunk)?;
1044        }
1045
1046        Ok(())
1047    }
1048}
1049
1050impl<T> From<T> for PieceTree where T: AsRef<str> {
1051    #[inline(always)]
1052    fn from(value: T) -> Self {
1053        Self::from_arc_str(value.as_ref())
1054    }
1055}
1056
1057impl str::FromStr for PieceTree {
1058    type Err = core::convert::Infallible;
1059
1060    #[inline(always)]
1061    fn from_str(s: &str) -> Result<Self, Self::Err> {
1062        Ok(PieceTree::from(s))
1063    }
1064}
1065
1066impl PieceTree {
1067    #[inline(always)]
1068    #[must_use]
1069    pub fn new() -> Self {
1070        Self::default()
1071    }
1072
1073    #[inline(always)]
1074    #[must_use]
1075    pub fn from_arc_str(text: impl Into<Arc<str>>) -> Self {
1076        let text = text.into();
1077
1078        let mut tree = PieceTree::new();
1079        if text.is_empty() { return tree; }
1080
1081        let bytes = text.as_bytes();
1082        let byte_length = bytes.len() as u32;
1083
1084        let mut offsets     = Vec::with_capacity(bytes.len() / 40);
1085        let mut checkpoints = Vec::with_capacity(bytes.len() / 256);
1086
1087        let (char_count, newline_count) =
1088            count_chars_and_newlines_with_offsets_and_checkpoints(
1089                text.as_bytes(),
1090                &mut offsets,
1091                &mut checkpoints,
1092            );
1093
1094        let buffer = tree.buffers.original_buffers.push(OriginalBuffer {
1095            newline_offsets:  offsets.into(),
1096            char_checkpoints: checkpoints.into(),
1097            text:             text.into(),
1098        });
1099
1100        let piece = Piece {
1101            buffer,
1102            byte_offset:       0,
1103            byte_length,
1104            char_count,
1105            newline_count,
1106            buffer_start_line: 0,
1107            piece_start_char:  0,
1108        };
1109
1110        tree.root = tree.pieces.insert_node(NIL, piece, 0);
1111        tree
1112    }
1113
1114    /// Splits the tree at `byte_offset`, returning the right half as a new
1115    /// `PieceTree`.
1116    ///
1117    /// After this call, `self` contains `[0, byte_offset)` and
1118    /// the returned tree contains `[byte_offset, end)`.
1119    ///
1120    /// `byte_offset` must be on a UTF-8 char boundary. Panics if `byte_offset > self.len_bytes()`.
1121    ///
1122    /// Runs in O(log n).
1123    pub fn split_off(&mut self, byte_offset: u32) -> Self {
1124        assert!(
1125            byte_offset <= self.len_bytes(),
1126            "split_off: byte_offset {} out of bounds (len = {})",
1127            byte_offset, self.len_bytes()
1128        );
1129
1130        if byte_offset == 0 {
1131            //
1132            // Everything goes to the right half -> self becomes empty
1133            //
1134            let mut right = Self::default();
1135            right.pieces  = self.pieces.clone();
1136            right.buffers = self.buffers.clone();
1137            right.root    = self.root;
1138            self.root     = NIL;
1139            self.last_mod_end  = u32::MAX;
1140            self.last_tree_end = u32::MAX;
1141
1142            return right;
1143        }
1144
1145        if byte_offset == self.len_bytes() {
1146            //
1147            // Everything stays in self          -> return empty right half
1148            //
1149
1150            let mut right = Self::default();
1151            right.pieces  = self.pieces.clone();
1152            right.buffers = self.buffers.clone();
1153            // right.root stays NIL
1154
1155            return right;
1156        }
1157
1158        //
1159        // Split the tree at the byte boundary
1160        //
1161        let (left_root, right_root) = self.split(self.root, byte_offset);
1162
1163        //
1164        // Self keeps the left half
1165        //
1166        self.root          = left_root;
1167        self.last_mod_end  = u32::MAX;
1168        self.last_tree_end = u32::MAX;
1169        self.undo_stack.clear();
1170        self.redo_stack.clear();
1171
1172        //
1173        // Right half gets a new PieceTree sharing the same arena and buffers
1174        //
1175        let mut right = Self::default();
1176        right.pieces  = self.pieces.clone();
1177        right.buffers = self.buffers.clone();
1178        right.root    = right_root;
1179
1180        right
1181    }
1182
1183    #[cfg(feature = "write")]
1184    pub fn from_reader<R: std::io::Read>(mut reader: R) -> std::io::Result<Self> {
1185        const CHUNK: usize = 64 * 1024;
1186
1187        let mut buf  = [0u8; CHUNK];
1188        let mut text = String::new();
1189        let mut tail = 0usize;
1190
1191        loop {
1192            let n = reader.read(&mut buf[tail..])?;
1193
1194            if n == 0 {
1195                // EOF
1196                if tail > 0 {
1197                    return Err(std::io::Error::new(
1198                        std::io::ErrorKind::InvalidData,
1199                        "stream ended with incomplete UTF-8 sequence",
1200                    ));
1201                }
1202
1203                break;
1204            }
1205
1206            let filled = tail + n;
1207            let slice  = &buf[..filled];
1208
1209            //
1210            // Find how much is valid UTF-8
1211            //
1212            let valid_up_to = match str::from_utf8(slice) {
1213                Ok(_)  => filled,
1214                Err(e) => {
1215                    if e.error_len().is_some() {
1216                        return Err(std::io::Error::new(
1217                            std::io::ErrorKind::InvalidData,
1218                            "stream did not contain valid UTF-8",
1219                        ));
1220                    }
1221                    e.valid_up_to()
1222                }
1223            };
1224
1225            //
1226            // SAFETY: validated above
1227            //
1228            text.push_str(unsafe { std::str::from_utf8_unchecked(&slice[..valid_up_to]) });
1229
1230            //
1231            // Carry over the incomplete sequence (0-3 bytes) to next iteration
1232            //
1233            tail = filled - valid_up_to;
1234            if tail > 0 {
1235                buf.copy_within(valid_up_to..filled, 0);
1236            }
1237        }
1238
1239        Ok(Self::from(text))
1240    }
1241}
1242
1243impl PieceTree {
1244    /// Captures the current state of the document.
1245    #[inline]
1246    #[must_use]
1247    pub fn take_snapshot(&self, current_cursor: u32) -> HistoryEntry {
1248        HistoryEntry {
1249            root: self.root,
1250            cursor_offset: current_cursor,
1251        }
1252    }
1253
1254    /// Restores the tree to a previously saved snapshot.
1255    /// Returns the cursor offset from the snapshot.
1256    #[inline]
1257    #[must_use]
1258    pub fn snap_to(&mut self, snapshot: HistoryEntry, current_cursor: u32) -> u32 {
1259        if self.root == snapshot.root {
1260            return snapshot.cursor_offset;
1261        }
1262
1263        //
1264        // Prevent snapping while in the middle of an active transaction
1265        //
1266        assert!(self.transaction_depth == 0, "Cannot snap_to during an active undo group");
1267
1268        //
1269        // Save the current state to the undo stack so the user can undo the jump
1270        //
1271        self.undo_stack.push(HistoryEntry {
1272            root: self.root,
1273            cursor_offset: current_cursor,
1274        });
1275
1276        //
1277        // Clear the redo stack
1278        //
1279        self.redo_stack.clear();
1280
1281        //
1282        // Invalidate caches
1283        //
1284        self.last_tree_end = u32::MAX;
1285        self.last_mod_end  = u32::MAX;
1286
1287        //
1288        //  Restore the tree
1289        //
1290        self.root = snapshot.root;
1291
1292        snapshot.cursor_offset
1293    }
1294}
1295
1296impl PieceTree {
1297    /// Starts a new undo group, saves the current state if this is the outermost group.
1298    #[inline]
1299    pub fn begin_undo_group(&mut self, cursor_offset: u32) {
1300        if self.transaction_depth == 0 {
1301            self.commit_head(cursor_offset);
1302        }
1303
1304        self.transaction_depth += 1;
1305    }
1306
1307    /// Ends the current undo group
1308    #[inline]
1309    pub fn end_undo_group(&mut self) {
1310        if self.transaction_depth > 0 {
1311            self.transaction_depth -= 1;
1312        }
1313    }
1314
1315    #[inline(always)]
1316    pub fn commit_head(&mut self, cursor_offset: u32) {
1317        if let Some(last) = self.undo_stack.last() {
1318            if last.root == self.root {
1319                return;  // Root hasn't changed, skip duplication
1320            }
1321        }
1322
1323        self.undo_stack.push(HistoryEntry { root: self.root, cursor_offset });
1324        self.redo_stack.clear();
1325    }
1326
1327    #[inline(always)]
1328    pub fn try_undo(&mut self, current_cursor: u32) -> Option<u32> {
1329        if self.transaction_depth > 0 {
1330            return None;
1331        }
1332
1333        if let Some(entry) = self.undo_stack.pop() {
1334            self.last_tree_end = u32::MAX;
1335            self.last_mod_end  = u32::MAX;
1336
1337            self.redo_stack.push(HistoryEntry {
1338                root: self.root, cursor_offset: current_cursor
1339            });
1340            self.root = entry.root;
1341            return Some(entry.cursor_offset);
1342        }
1343
1344        None
1345    }
1346
1347    #[inline(always)]
1348    pub fn try_redo(&mut self, current_cursor: u32) -> Option<u32> {
1349        if let Some(entry) = self.redo_stack.pop() {
1350            self.last_tree_end = u32::MAX;
1351            self.last_mod_end  = u32::MAX;
1352
1353            self.undo_stack.push(HistoryEntry {
1354                root: self.root, cursor_offset: current_cursor
1355            });
1356            self.root = entry.root;
1357            return Some(entry.cursor_offset);
1358        }
1359
1360        None
1361    }
1362
1363    #[inline(always)]
1364    #[must_use]
1365    pub fn total_length(&self) -> u32 {
1366        self.pieces.get(self.root).subtree_len
1367    }
1368
1369    #[inline(always)]
1370    pub fn apply_edits(&mut self, primary_cursor_offset: u32, edits: &mut [Edit]) {
1371        if edits.is_empty() { return }
1372
1373        self.begin_undo_group(primary_cursor_offset);
1374
1375        edits.sort_by_key(|b| core::cmp::Reverse(b.offset()));
1376        for edit in edits {
1377            match edit {
1378                Edit::Insert { offset, text }   => self.insert_no_commit(*offset, text),
1379                Edit::Remove { offset, length } => self.remove_no_commit(*offset, *length),
1380            }
1381        }
1382
1383        self.end_undo_group();
1384    }
1385
1386    /// Inserts a single character at the specified logical byte offset.
1387    #[inline(always)]
1388    pub fn insert_char(&mut self, offset: u32, ch: char) {
1389        self.commit_head(offset);
1390        self.insert_char_no_commit(offset, ch);
1391    }
1392
1393    /// Inserts a single character at the specified logical byte offset.
1394    #[inline(always)]
1395    pub fn insert_char_no_commit(&mut self, offset: u32, ch: char) {
1396        let mut buf = [0; 4];
1397        self.insert_no_commit(offset, ch.encode_utf8(&mut buf));
1398    }
1399
1400    #[inline(always)]
1401    pub fn insert(&mut self, offset: u32, text: &str) {
1402        if text.is_empty() { return }
1403
1404        let auto_group = self.transaction_depth == 0;
1405        if auto_group {
1406            self.begin_undo_group(offset);
1407        }
1408
1409        self.insert_no_commit(offset, text);
1410
1411        if auto_group {
1412            self.end_undo_group();
1413        }
1414    }
1415
1416    #[inline(always)]
1417    pub fn remove_at(&mut self, offset: u32, length: u32) {
1418        if length == 0 || self.root == NIL { return }
1419
1420        let auto_group = self.transaction_depth == 0;
1421        if auto_group {
1422            self.begin_undo_group(offset);
1423        }
1424
1425        self.remove_no_commit(offset, length);
1426
1427        if auto_group {
1428            self.end_undo_group();
1429        }
1430    }
1431
1432    pub fn insert_no_commit(&mut self, offset: u32, text: &str) {
1433        let mod_offset = self.buffers.modifications_buffer.len() as u32;
1434        let start_line_in_buffer = self.buffers.modifications_newline_offsets.len() as u32;
1435
1436        let total_char_count_before = self.buffers.modifications_char_count;
1437        let mut total_char_count = total_char_count_before;
1438
1439        self.buffers.modifications_newline_offsets.reserve(text.len() / 20 + 1);
1440        self.buffers.modifications_char_checkpoints.reserve(text.len() / CHECKPOINT_INTERVAL as usize + 1);
1441
1442        let mut newline_count = 0;
1443        let mut char_count = 0;
1444        {
1445            let rem = total_char_count % CHECKPOINT_INTERVAL;
1446            let mut next_checkpoint = total_char_count + ((CHECKPOINT_INTERVAL - rem) % CHECKPOINT_INTERVAL);
1447
1448            if next_checkpoint == 0 {
1449                next_checkpoint = CHECKPOINT_INTERVAL;
1450            }
1451
1452            //
1453            // @Cutnpaste from count_chars_and_newlines_with_offsets_and_checkpoints
1454            //
1455            for (i, b) in text.bytes().enumerate() {
1456                if (b as i8) >= -0x40 {
1457                    if total_char_count == next_checkpoint {
1458                        self.buffers.modifications_char_checkpoints.push((total_char_count, mod_offset + i as u32));
1459                        next_checkpoint += CHECKPOINT_INTERVAL;
1460                    }
1461
1462                    total_char_count += 1;
1463                    char_count += 1;
1464                }
1465
1466                if b == b'\n' {
1467                    self.buffers.modifications_newline_offsets.push(mod_offset + i as u32);
1468                    newline_count += 1;
1469                }
1470            }
1471        }
1472
1473        self.buffers.modifications_char_count = total_char_count;
1474        self.buffers.modifications_buffer.push_str(text);
1475        let text_len = text.len() as u32;
1476
1477        let new_mod_end  = mod_offset + text_len;
1478        let new_tree_end = offset + text_len;
1479
1480        //
1481        // Fast path for sequential typing
1482        //
1483        if offset > 0
1484        && self.last_tree_end == offset
1485        && self.last_mod_end == mod_offset
1486        && let Some((prev_index, prev_rel)) = self.find_position(offset - 1, false)
1487        {
1488            let prev = self.pieces.get_piece(prev_index);
1489
1490            //
1491            // Predecessor must be a mod-buf piece ending at mod_offset.
1492            //
1493            if prev.buffer == MOD_BUFFER && prev.byte_offset + prev.byte_length == mod_offset {
1494                let prev_start = (offset - 1) - prev_rel;
1495
1496                self.root = self.pieces.extend_piece(
1497                    self.root,
1498                    prev_start,
1499                    text_len,
1500                    char_count,
1501                    newline_count
1502                );
1503
1504                self.last_mod_end  = new_mod_end;
1505                self.last_tree_end = new_tree_end;
1506                return;
1507            }
1508        }
1509
1510        let new_piece = Piece {
1511            buffer: MOD_BUFFER,
1512            byte_offset: mod_offset,
1513            byte_length: text_len,
1514            newline_count,
1515            char_count,
1516            buffer_start_line: start_line_in_buffer,
1517            piece_start_char:  total_char_count - char_count,
1518        };
1519
1520        if self.root == NIL {
1521            self.root = self.pieces.insert_node(self.root, new_piece, offset);
1522        } else {
1523            //
1524            // Snip the tree exactly at the insertion offset
1525            //
1526            let (left, right) = self.split(self.root, offset);
1527
1528            //
1529            // Sandwich the new piece directly between the left and right trees!
1530            //
1531            self.root = self.pieces.join_with_middle(left, new_piece, right);
1532
1533            //
1534            // Clean up the resulting seams
1535            //
1536
1537            // Attempt to merge the left side with new_piece
1538            self.try_merge_at(offset);
1539
1540            // Attempt to merge new_piece with the right side
1541            self.try_merge_at(offset + text_len);
1542        }
1543
1544        self.last_mod_end  = new_mod_end;
1545        self.last_tree_end = new_tree_end;
1546    }
1547
1548    pub fn remove_no_commit(&mut self, offset: u32, mut length: u32) {
1549        let total = self.total_length();
1550        if offset >= total { return; }
1551        if offset + length > total { length = total - offset; }
1552        if length == 0 { return }
1553
1554        //
1555        // Snip off the portion of the tree that comes BEFORE the deletion
1556        //
1557        let (left, remainder) = self.split(self.root, offset);
1558
1559        //
1560        // Snip the deleted portion out of the remainder
1561        //
1562        let (_deleted, right) = self.split(remainder, length);
1563
1564        //
1565        // Glue the surviving outer halves back together
1566        //
1567        self.root = self.concat(left, right);
1568
1569        //
1570        // Clean up the resulting seam
1571        //
1572        self.try_merge_at(offset);
1573    }
1574
1575    #[inline]
1576    fn try_merge_at(&mut self, pos: u32) {
1577        if pos == 0 { return }
1578
1579        let Some((right_index, right_rel)) = self.find_position(pos, false) else { return };
1580
1581        if right_rel != 0 { return }
1582
1583        let right = self.pieces.get_piece(right_index);
1584        self.try_merge_right_with_left(pos, right);
1585    }
1586
1587    // Returns Some((merged_start, merged_piece)) if merge happened, None otherwise.
1588    #[inline]
1589    fn try_merge_right_with_left(&mut self, right_start: u32, right: Piece) -> Option<(u32, Piece)> {
1590        if right_start == 0 { return None; }
1591        if right.buffer != MOD_BUFFER { return None; }
1592
1593        let (left_index, left_rel) = self.find_position(right_start - 1, false)?;
1594        let left = self.pieces.get_piece(left_index);
1595
1596        if left.buffer != MOD_BUFFER { return None; }
1597        if left.byte_offset + left.byte_length != right.byte_offset { return None; }
1598
1599        let left_start = (right_start - 1) - left_rel;
1600
1601        self.root = self.pieces.remove_node(self.root, left_start);
1602        self.root = self.pieces.remove_node(self.root, left_start);
1603
1604        let merged = Piece {
1605            buffer:  MOD_BUFFER,
1606            byte_offset:        left.byte_offset,
1607            byte_length:        left.byte_length        + right.byte_length,
1608            newline_count: left.newline_count + right.newline_count,
1609            char_count:    left.char_count    + right.char_count,
1610            buffer_start_line: left.buffer_start_line,
1611            piece_start_char: left.piece_start_char,  // right side extends, left start unchanged
1612        };
1613        self.root = self.pieces.insert_node(self.root, merged, left_start);
1614        Some((left_start, merged))
1615    }
1616
1617    #[inline(always)]
1618    #[must_use]
1619    pub fn get_piece(&self, index: NodeRef) -> Piece {
1620        self.pieces.get_piece(index)
1621    }
1622
1623    #[inline]
1624    #[must_use]
1625    pub fn find_position(&self, offset: u32, prefer_left: bool) -> Option<(NodeRef, u32)> {
1626        let total = self.total_length();
1627        if offset > total { return None; }
1628
1629        if offset == total && total > 0 {
1630            let mut current = self.root;
1631            let mut last_valid = NIL;
1632            while current != NIL {
1633                last_valid = current;
1634                current = self.pieces.get(current).right;
1635            }
1636            let len = self.pieces.get_piece(last_valid).byte_length;
1637            return Some((last_valid, len));
1638        }
1639
1640        self.pieces.find_offset(self.root, offset, prefer_left)
1641    }
1642
1643    #[cfg(feature = "write")]
1644    #[inline]
1645    pub fn write_to<W: std::io::Write>(&self, mut writer: W) -> std::io::Result<()> {
1646        if self.root == NIL {
1647            return Ok(());
1648        }
1649
1650        for (_, piece) in self.pieces() {
1651            let slice = self.buffers.get_slice(piece.buffer, piece.byte_offset, piece.byte_length);
1652            writer.write_all(slice.as_bytes())?;
1653        }
1654
1655        writer.flush()
1656    }
1657}
1658
1659impl PieceTree {
1660    #[inline]
1661    pub fn compact(&mut self) {
1662        #[inline(always)]
1663        fn copy_node(
1664            old_index: NodeRef, old_arena: &Pieces,
1665            new_arena: &mut Pieces, index_map: &mut [u32]
1666        ) -> NodeRef {
1667            if old_index == NIL { return NIL }
1668
1669            if index_map[old_index.index()] != 0 {
1670                return NodeRef::new(index_map[old_index.index()] as usize);
1671            }
1672
1673            let node = old_arena.get(old_index);
1674            let left_new = copy_node(node.left, old_arena, new_arena, index_map);
1675            let right_new = copy_node(node.right, old_arena, new_arena, index_map);
1676
1677            let new_index = NodeRef::new(new_arena.nodes.len());
1678            new_arena.nodes.push(Node {
1679                left: left_new,
1680                right: right_new,
1681                offset: node.offset,
1682                subtree_len: node.subtree_len,
1683                subtree_chars: node.subtree_chars,
1684                subtree_newlines: node.subtree_newlines,
1685                piece_start_char: node.piece_start_char,
1686                meta: node.meta,
1687                buffer_start_line: node.buffer_start_line
1688            });
1689
1690            index_map[old_index.index()] = new_index.index() as u32;
1691            new_index
1692        }
1693
1694        let mut new_pieces = Pieces::new();
1695
1696        self.scratch_index_map.clear();
1697        self.scratch_index_map.resize(self.pieces.nodes.len(), 0);
1698
1699        self.root = copy_node(self.root, &self.pieces, &mut new_pieces, &mut self.scratch_index_map);
1700        for entry in &mut self.undo_stack {
1701            entry.root = copy_node(entry.root, &self.pieces, &mut new_pieces, &mut self.scratch_index_map);
1702        }
1703        for entry in &mut self.redo_stack {
1704            entry.root = copy_node(entry.root, &self.pieces, &mut new_pieces, &mut self.scratch_index_map);
1705        }
1706
1707        self.pieces = new_pieces;
1708    }
1709
1710    #[inline]
1711    pub fn squash(&mut self) {  // @Memory
1712        if self.root == NIL { return }
1713
1714        let squashed_text = self.to_string();  // @Memory
1715        let bytes  = squashed_text.as_bytes();
1716        let length = squashed_text.len() as u32;
1717
1718        let mut offsets     = Vec::with_capacity(bytes.len() / 40);
1719        let mut checkpoints = Vec::with_capacity(bytes.len() / 256);
1720
1721        let (char_count, newline_count) =
1722            count_chars_and_newlines_with_offsets_and_checkpoints(
1723                squashed_text.as_bytes(),
1724                &mut offsets,
1725                &mut checkpoints
1726            );
1727
1728        self.buffers = Buffers::new();
1729        let buffer = self.buffers.original_buffers.push(OriginalBuffer {
1730            newline_offsets: offsets.into(),
1731            char_checkpoints: checkpoints.into(),
1732            text: squashed_text.into()
1733        });
1734        self.pieces = Pieces::new();
1735
1736        let piece = Piece {
1737            byte_length: length, newline_count, char_count,
1738            buffer, byte_offset: 0,
1739            buffer_start_line: 0, piece_start_char: 0
1740        };
1741        self.root = self.pieces.insert_node(NIL, piece, 0);
1742
1743        self.undo_stack.clear();
1744        self.redo_stack.clear();
1745    }
1746}
1747
1748#[derive(Debug, Clone, Copy)]
1749pub struct MemoryUsage {
1750    pub node_arena:       u32,
1751    pub mod_buffer:       u32,
1752    pub original_buffers: u32,
1753    pub history:          u32,
1754}
1755
1756impl MemoryUsage {
1757    #[inline(always)]
1758    #[must_use]
1759    pub const fn total(&self) -> u32 {
1760        self.node_arena + self.mod_buffer + self.original_buffers + self.history
1761    }
1762
1763    /// Overhead = everything except the actual document content in buffers.
1764    #[inline(always)]
1765    #[must_use]
1766    pub const fn overhead(&self) -> u32 {
1767        self.node_arena + self.history
1768    }
1769}
1770
1771impl PieceTree {
1772    /// Total bytes allocated for the node arena (includes NIL sentinel and
1773    /// all historical nodes retained for undo/redo).
1774    #[inline(always)]
1775    #[must_use]
1776    pub fn node_arena_bytes(&self) -> u32 {
1777        (self.pieces.nodes.len() * size_of::<Node>()) as _
1778    }
1779
1780    /// Bytes consumed by the modifications buffer (append-only, never shrinks).
1781    #[inline(always)]
1782    #[must_use]
1783    pub fn mod_buffer_bytes(&self) -> u32 {
1784        self.buffers.modifications_buffer.len() as u32 +
1785            (self.buffers.modifications_char_checkpoints.len() * size_of::<(u32, u32)>()) as u32 +
1786            (self.buffers.modifications_newline_offsets.len() * size_of::<u32>()) as u32
1787    }
1788
1789    /// Bytes consumed by all original (read) buffers.
1790    #[inline(always)]
1791    #[must_use]
1792    pub fn original_buffers_bytes(&self) -> u32 {
1793        self.buffers.original_buffers.values().map(|s| {
1794            s.len() +
1795                s.char_checkpoints.len() * size_of::<(u32, u32)>() +
1796                s.newline_offsets.len() * size_of::<u32>()
1797        }).sum::<usize>() as _
1798    }
1799
1800    /// Bytes consumed by undo + redo history entries.
1801    #[inline(always)]
1802    #[must_use]
1803    pub fn history_bytes(&self) -> u32 {
1804        ((self.undo_stack.len() + self.redo_stack.len()) * size_of::<HistoryEntry>()) as _
1805    }
1806
1807    /// Number of live nodes in the arena (includes NIL and all historical nodes).
1808    #[inline(always)]
1809    #[must_use]
1810    pub fn node_count(&self) -> u32 {
1811        self.pieces.nodes.len() as _
1812    }
1813
1814    /// Aggregate memory usage breakdown.
1815    #[inline(always)]
1816    #[must_use]
1817    pub fn memory_usage(&self) -> MemoryUsage {
1818        MemoryUsage {
1819            node_arena:       self.node_arena_bytes(),
1820            mod_buffer:       self.mod_buffer_bytes(),
1821            original_buffers: self.original_buffers_bytes(),
1822            history:          self.history_bytes(),
1823        }
1824    }
1825}
1826
1827#[derive(Debug)]
1828pub struct LinesIter<'a> {
1829    tree: &'a PieceTree,
1830    current_line: u32,
1831    total_lines: u32,
1832}
1833
1834impl Iterator for LinesIter<'_> {
1835    type Item = String;
1836
1837    fn next(&mut self) -> Option<Self::Item> {
1838        if self.current_line >= self.total_lines { return None }
1839
1840        let line = self.tree.get_line_content_allocating(self.current_line)?;
1841        self.current_line += 1;
1842        Some(line)
1843    }
1844}
1845
1846/// A lazy, non-allocating slice view over a byte range of the tree
1847#[derive(Debug)]
1848pub struct ChunkIter<'a> {
1849    tree:       &'a PieceTree,
1850    pieces:     PieceTreeIter<'a>,
1851    // Byte range we care about
1852    start:      u32,
1853    end:        u32,
1854    // Bytes consumed so far across all pieces
1855    piece_start: u32,
1856}
1857
1858impl<'a> ChunkIter<'a> {
1859    #[inline]
1860    #[must_use]
1861    pub fn new(tree: &'a PieceTree, start: u32, end: u32) -> Self {
1862        Self {
1863            tree,
1864            pieces: PieceTreeIter::new(&tree.pieces, tree.root),
1865            start,
1866            end,
1867            piece_start: 0,
1868        }
1869    }
1870
1871    /// Returns the total number of characters within this chunk view boundary.
1872    #[inline]
1873    #[must_use]
1874    pub fn len_chars(&self) -> u32 {
1875        let start_char = self.tree.try_byte_to_char(self.start).unwrap_or(0);
1876        let end_char = self.tree.try_byte_to_char(self.end).unwrap_or_else(|| self.tree.len_chars());
1877        end_char.saturating_sub(start_char)
1878    }
1879
1880    /// Returns the total number of characters within this chunk view boundary.
1881    #[inline]
1882    #[must_use]
1883    pub fn len_bytes(&self) -> u32 {
1884        self.end.saturating_sub(self.start)
1885    }
1886}
1887
1888impl<'a> Iterator for ChunkIter<'a> {
1889    type Item = &'a str;
1890
1891    #[inline]
1892    fn next(&mut self) -> Option<&'a str> {
1893        loop {
1894            let (_, p) = self.pieces.next()?;
1895            let piece_end = self.piece_start + p.byte_length;
1896
1897            // Skip pieces entirely before our window
1898            if piece_end <= self.start {
1899                self.piece_start = piece_end;
1900                continue;
1901            }
1902            // Stop once we're past our window
1903            if self.piece_start >= self.end {
1904                return None;
1905            }
1906
1907            let slice_start = self.start.saturating_sub(self.piece_start);
1908            let slice_end   = (self.end - self.piece_start).min(p.byte_length);
1909
1910            self.piece_start = piece_end;
1911
1912            let text = self.tree.buffers.get_slice(p.buffer, p.byte_offset + slice_start, slice_end - slice_start);
1913            if text.is_empty() { continue; }
1914            return Some(text);
1915        }
1916    }
1917}
1918
1919/// A zero-copy iterator that yields lines as perfectly bounded `TreeSlice`s.
1920#[derive(Debug, Clone)]
1921pub struct SliceLines<'a> {
1922    slice: TreeSlice<'a>,
1923    current_abs_line: u32,
1924    end_abs_line: u32,
1925    yielded_all: bool,
1926}
1927
1928impl<'a> Iterator for SliceLines<'a> {
1929    type Item = TreeSlice<'a>;
1930
1931    #[inline]
1932    fn next(&mut self) -> Option<Self::Item> {
1933        if self.yielded_all { return None; }
1934
1935        // Fetch the absolute start byte of the current line from the tree
1936        let line_start = self.slice.tree.try_line_to_byte(self.current_abs_line).unwrap_or(self.slice.start);
1937
1938        //
1939        // If we are on the very last line that this slice overlaps
1940        //
1941        if self.current_abs_line >= self.end_abs_line {
1942            self.yielded_all = true;
1943
1944            // Clamp the start byte between the slice start and end boundaries
1945            let start_byte = line_start.max(self.slice.start).min(self.slice.end);
1946
1947            return Some(TreeSlice {
1948                tree: self.slice.tree,
1949                start: start_byte,
1950                end: self.slice.end,
1951            });
1952        }
1953
1954        // We are on an intermediate line, find where the next line starts.
1955        let next_line_start = self.slice.tree.try_line_to_byte(self.current_abs_line + 1).unwrap_or(self.slice.end);
1956
1957        // Clamp boundaries to ensure we never bleed outside the TreeSlice
1958        let start_byte = line_start.max(self.slice.start).min(self.slice.end);
1959        let end_byte = next_line_start.min(self.slice.end);
1960
1961        self.current_abs_line += 1;
1962
1963        Some(TreeSlice {
1964            tree: self.slice.tree,
1965            start: start_byte,
1966            end: end_byte,
1967        })
1968    }
1969}
1970
1971#[derive(Debug)]
1972pub struct SliceCharsRev<'a> {
1973    walker: ReverseTreeWalker<'a>,
1974    current_byte: u32,
1975    start_byte: u32,
1976}
1977
1978impl<'a> Iterator for SliceCharsRev<'a> {
1979    type Item = char;
1980
1981    #[inline]
1982    fn next(&mut self) -> Option<char> {
1983        // If we've hit or crossed the start boundary, stop
1984        if self.current_byte <= self.start_byte {
1985            return None;
1986        }
1987
1988        let c = self.walker.next()?;
1989
1990        // Subtract the exact byte width of the character we just yielded
1991        self.current_byte = self.current_byte.saturating_sub(c.len_utf8() as u32);
1992
1993        // If yielding this character pushed us before the slice's start
1994        // boundary, we discard it and end the iterator.
1995        if self.current_byte < self.start_byte {
1996            return None;
1997        }
1998
1999        Some(c)
2000    }
2001}
2002
2003impl core::fmt::Display for SliceCharsRev<'_> {
2004    #[inline]
2005    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2006        let mut chars = Vec::new();
2007        let mut temp_walker = ReverseTreeWalker::new_at(self.walker.tree, self.current_byte);
2008
2009        let mut temp_byte = self.current_byte;
2010        while temp_byte > self.start_byte {
2011            let Some(c) = temp_walker.next() else { break };
2012            let new_byte = temp_byte.saturating_sub(c.len_utf8() as u32);
2013            if new_byte < self.start_byte { break; }
2014            temp_byte = new_byte;
2015            chars.push(c);
2016        }
2017
2018        chars.reverse();
2019
2020        let mut buf = Vec::with_capacity(chars.iter().map(|c| c.len_utf8()).sum());
2021        let mut tmp = [0u8; 4];
2022        for c in &chars {
2023            buf.extend_from_slice(c.encode_utf8(&mut tmp).as_bytes());
2024        }
2025
2026        f.write_str(unsafe { core::str::from_utf8_unchecked(&buf) })
2027    }
2028}
2029
2030/// Non-allocating char iterator over a byte-bounded window of the tree.
2031#[derive(Debug)]
2032pub struct SliceChars<'a> {
2033    walker:   TreeWalker<'a>,
2034    byte_end: u32,
2035}
2036
2037impl Iterator for SliceChars<'_> {
2038    type Item = char;
2039    #[inline]
2040    fn next(&mut self) -> Option<char> {
2041        if self.walker.offset >= self.byte_end { return None; }
2042        self.walker.next()
2043    }
2044}
2045
2046impl core::fmt::Display for SliceChars<'_> {
2047    #[inline]
2048    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2049        // Grab the current absolute byte offset from the existing walker
2050        let current_offset = self.walker.offset;
2051
2052        // Spawn a transient walker and seek it to the exact current offset
2053        let mut temp_walker = TreeWalker::<32>::new(self.walker.tree);
2054        temp_walker.seek(current_offset);
2055
2056        while temp_walker.offset < self.byte_end {
2057            let chunk = temp_walker.current_str.as_str();
2058            if chunk.is_empty() {
2059                if temp_walker.stack.is_empty() { break; }
2060                temp_walker.populate_chars();
2061                continue;
2062            }
2063
2064            // Clamp chunk to byte_end
2065            let remaining = (self.byte_end - temp_walker.offset) as usize;
2066            let chunk = &chunk[..remaining.min(chunk.len())];
2067            f.write_str(chunk)?;
2068            temp_walker.offset += chunk.len() as u32;
2069            temp_walker.current_str = "".chars();
2070            temp_walker.populate_chars();
2071        }
2072
2073        Ok(())
2074    }
2075}
2076
2077/// A zero-copy borrowed view over a byte range of the tree.
2078/// All offsets are relative to the slice start.
2079#[derive(Debug, Clone, Copy)]
2080pub struct TreeSlice<'a> {
2081    tree:  &'a PieceTree,
2082    start: u32,   // byte offset into tree (inclusive)
2083    end:   u32,   // byte offset into tree (exclusive)
2084}
2085
2086impl PartialEq<&str> for TreeSlice<'_> {
2087    #[inline]
2088    fn eq(&self, other: &&str) -> bool {
2089        let mut remaining = other.as_bytes();
2090
2091        for chunk in self.chunks() {
2092            let chunk_bytes = chunk.as_bytes();
2093
2094            // If the chunk is longer than the remaining string, they don't match
2095            if remaining.len() < chunk_bytes.len() {
2096                return false;
2097            }
2098
2099            // If the bytes don't match, fail fast
2100            if !remaining.starts_with(chunk_bytes) {
2101                return false;
2102            }
2103
2104            remaining = &remaining[chunk_bytes.len()..];
2105        }
2106
2107        // If we exhausted all chunks and have no remaining bytes, it's a perfect match
2108        remaining.is_empty()
2109    }
2110}
2111
2112impl PartialEq<str> for TreeSlice<'_> {
2113    #[inline]
2114    fn eq(&self, other: &str) -> bool {
2115        self == &other
2116    }
2117}
2118
2119impl core::fmt::Display for TreeSlice<'_> {
2120    #[inline(always)]
2121    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2122        for chunk in self.chunks() {
2123            f.write_str(chunk)?;
2124        }
2125        Ok(())
2126    }
2127}
2128
2129/// Slice Iterators
2130impl<'a> TreeSlice<'a> {
2131    #[inline]
2132    pub fn chunks(self) -> ChunkIter<'a> {
2133        ChunkIter::new(self.tree, self.start, self.end)
2134    }
2135
2136    #[inline]
2137    pub fn bytes(self) -> impl Iterator<Item = u8> + 'a {
2138        self.chunks().flat_map(|chunk| chunk.bytes())
2139    }
2140
2141    #[inline]
2142    pub fn chars(self) -> impl Iterator<Item = char> + 'a {
2143        self.chunks().flat_map(|chunk| chunk.chars())
2144    }
2145
2146    #[inline]
2147    pub fn chars_rev(self) -> SliceCharsRev<'a> {
2148        SliceCharsRev {
2149            walker: ReverseTreeWalker::new_at(self.tree, self.end),
2150            current_byte: self.end,
2151            start_byte: self.start,
2152        }
2153    }
2154
2155    #[inline]
2156    pub fn lines(self) -> SliceLines<'a> {
2157        // Query the tree directly for the absolute line overlap
2158        let start_line = self.tree.byte_to_line(self.start);
2159        let end_line = self.tree.byte_to_line(self.end);
2160
2161        SliceLines {
2162            slice: self,
2163            current_abs_line: start_line,
2164            end_abs_line: end_line,
2165            yielded_all: false,
2166        }
2167    }
2168
2169    #[inline]
2170    pub fn lines_at(self, line_idx: u32) -> SliceLines<'a> {
2171        let start_line = self.tree.byte_to_line(self.start);
2172        let end_line = self.tree.byte_to_line(self.end);
2173
2174        let target_line = (start_line + line_idx).min(end_line);
2175
2176        SliceLines {
2177            slice: self,
2178            current_abs_line: target_line,
2179            end_abs_line: end_line,
2180            yielded_all: false,
2181        }
2182    }
2183
2184    #[inline]
2185    pub fn chunks_at_byte(self, byte_idx: u32) -> ChunkIter<'a> {
2186        let safe_idx = byte_idx.min(self.len_bytes());
2187        ChunkIter::new(self.tree, self.start + safe_idx, self.end)
2188    }
2189
2190    #[inline]
2191    pub fn bytes_at(self, byte_idx: u32) -> impl Iterator<Item = u8> + 'a {
2192        self.chunks_at_byte(byte_idx).flat_map(|chunk| chunk.bytes())
2193    }
2194
2195    #[inline]
2196    pub fn chars_at(self, char_idx: u32) -> impl Iterator<Item = char> + 'a {
2197        let safe_idx = char_idx.min(self.len_chars());
2198        let byte_offset = self.try_char_to_byte(safe_idx).unwrap_or(self.len_bytes());
2199        self.chunks_at_byte(byte_offset).flat_map(|chunk| chunk.chars())
2200    }
2201}
2202
2203/// Tree Iterators
2204impl PieceTree {
2205    #[inline]
2206    pub fn slice_whole(&self) -> TreeSlice<'_> {
2207        self.slice(0..self.len_bytes())
2208    }
2209
2210    #[inline]
2211    pub fn chunks(&self) -> ChunkIter<'_> { self.slice_whole().chunks() }
2212
2213    #[inline]
2214    pub fn bytes(&self) -> impl Iterator<Item = u8> + '_ { self.slice_whole().bytes() }
2215
2216    #[inline]
2217    pub fn chars(&self) -> impl Iterator<Item = char> + '_ { self.slice_whole().chars() }
2218
2219    #[inline]
2220    pub fn lines(&self) -> SliceLines<'_> { self.slice_whole().lines() }
2221
2222    #[inline(always)]
2223    #[must_use]
2224    pub fn chars_rev(&self) -> ReverseTreeWalker<'_> { ReverseTreeWalker::new(self) }
2225
2226    #[inline(always)]
2227    #[must_use]
2228    pub fn chars_at_rev(&self, char_idx: u32) -> ReverseTreeWalker<'_> { ReverseTreeWalker::new_at(self, char_idx) }
2229
2230    #[inline]
2231    pub fn chunks_at_byte(&self, byte_idx: u32) -> ChunkIter<'_> {
2232        self.slice_whole().chunks_at_byte(byte_idx)
2233    }
2234
2235    #[inline]
2236    pub fn bytes_at(&self, byte_idx: u32) -> impl Iterator<Item = u8> + '_ {
2237        self.slice_whole().bytes_at(byte_idx)
2238    }
2239
2240    #[inline]
2241    pub fn chars_at(&self, char_idx: u32) -> impl Iterator<Item = char> + '_ {
2242        self.slice_whole().chars_at(char_idx)
2243    }
2244
2245    #[inline]
2246    pub fn lines_at(&self, line_idx: u32) -> SliceLines<'_> {
2247        self.slice_whole().lines_at(line_idx)
2248    }
2249}
2250
2251impl<'a> TreeSlice<'a> {
2252    #[inline(always)]
2253    #[must_use]
2254    pub fn new(tree: &'a PieceTree, start: u32, end: u32) -> Self {
2255        let end = end.min(tree.len_bytes());
2256        debug_assert!(start <= end);
2257        Self { tree, start, end }
2258    }
2259
2260    #[inline(always)]
2261    #[must_use]
2262    pub fn len_bytes(&self) -> u32  { self.end - self.start }
2263
2264    #[inline(always)]
2265    #[must_use]
2266    pub fn is_empty(&self)  -> bool { self.start == self.end }
2267
2268    #[inline(always)]
2269    #[must_use]
2270    pub fn len_chars(&self) -> u32 {
2271        let a = self.tree.try_byte_to_char(self.start).unwrap_or(0);
2272        let b = self.tree.try_byte_to_char(self.end).unwrap_or_else(|| self.tree.len_chars());
2273        b - a
2274    }
2275
2276    #[inline]
2277    #[must_use]
2278    pub fn len_lines(&self) -> u32 {
2279        let start_line = self.tree.try_byte_to_line(self.start).unwrap_or(0);
2280        let end_line = self.tree.try_byte_to_line(self.end).unwrap_or_else(|| self.tree.len_lines() - 1);
2281        end_line - start_line + 1
2282    }
2283
2284    #[must_use]
2285    pub fn chunk_at_byte(&self, offset: u32) -> &[u8] {
2286        if offset >= self.len_bytes() { return &[] }
2287
2288        let abs_byte = self.start + offset;
2289        let chunk = self.tree.chunk_at_byte(abs_byte).0;
2290
2291        // Truncate the chunk if it bleeds past the end of the slice
2292        let max_valid_len = (self.end - abs_byte) as usize;
2293        let bounded_len = chunk.len().min(max_valid_len);
2294
2295        &chunk[..bounded_len]
2296    }
2297
2298    #[inline]
2299    #[must_use]
2300    pub fn chunk_at_char(&self, char_offset: u32) -> &[u8] {
2301        if char_offset >= self.len_chars() { return &[] }
2302
2303        let Some(base_char) = self.tree.try_byte_to_char(self.start) else {
2304            return &[];
2305        };
2306        let abs_char = base_char + char_offset;
2307
2308        let chunk = self.tree.chunk_at_char(abs_char).0;
2309
2310        // Truncate the chunk if it bleeds past the end of the slice
2311        let Some(abs_byte) = self.tree.try_char_to_byte(abs_char) else {
2312            return &[];
2313        };
2314
2315        let max_valid_len = (self.end - abs_byte) as usize;
2316        let bounded_len = chunk.len().min(max_valid_len);
2317
2318        &chunk[..bounded_len]
2319    }
2320
2321    #[inline]
2322    #[must_use]
2323    pub fn chunk_at_line_break(&self, break_index: u32) -> &[u8] {
2324        let Some((base_line, _)) = self.tree.try_byte_to_line_col(self.start) else {
2325            return &[];
2326        };
2327
2328        let abs_break_index = base_line + break_index;
2329
2330        let Some(abs_byte) = self.tree.try_line_break_to_byte(abs_break_index) else {
2331            return &[];
2332        };
2333
2334        // Ensure the line break actually falls within the slice bounds
2335        if abs_byte < self.start || abs_byte >= self.end {
2336            return &[];
2337        }
2338
2339        let chunk = self.tree.chunk_at_byte(abs_byte).0;
2340
2341        // Bound the chunk so it doesn't bleed past self.end
2342        let max_valid_len = (self.end - abs_byte) as usize;
2343        let bounded_len = chunk.len().min(max_valid_len);
2344
2345        &chunk[..bounded_len]
2346    }
2347
2348    /// Byte at a slice-relative byte offset.
2349    #[inline(always)]
2350    #[must_use]
2351    pub fn byte(&self, offset: u32) -> u8 {
2352        self.try_byte(offset).unwrap()
2353    }
2354
2355    /// Byte at a slice-relative byte offset.
2356    #[inline(always)]
2357    #[must_use]
2358    pub fn try_byte(&self, offset: u32) -> Option<u8> {
2359        if offset >= self.len_bytes() { return None; }
2360        self.tree.try_byte(self.start + offset)
2361    }
2362
2363    /// Char at a slice-relative char index.
2364    #[inline(always)]
2365    #[must_use]
2366    pub fn char(&self, char_index: u32) -> char {
2367        self.try_char(char_index).unwrap()
2368    }
2369
2370    /// Char at a slice-relative char index.
2371    #[inline(always)]
2372    #[must_use]
2373    pub fn try_char(&self, char_index: u32) -> Option<char> {
2374        if char_index >= self.len_chars() { return None; }
2375        let abs_char = self.tree.try_byte_to_char(self.start)? + char_index;
2376        self.tree.try_char(abs_char)
2377    }
2378
2379    #[inline(always)]
2380    #[must_use]
2381    pub fn line(&self, line: u32) -> ChunkIter<'a> {
2382        self.try_line(line).unwrap()
2383    }
2384
2385    #[inline(always)]
2386    #[must_use]
2387    pub fn try_line(&self, line: u32) -> Option<ChunkIter<'a>> {
2388        let (abs_start, abs_end) = self.abs_line_range(line)?;
2389        // Use ChunkIter directly to enforce the absolute end boundary
2390        Some(ChunkIter::new(self.tree, abs_start, abs_end))
2391    }
2392
2393    /// Returns a sub-slice over a byte range (relative to this slice).
2394    #[inline(always)]
2395    #[must_use]
2396    pub fn slice<R: RangeBounds<u32>>(&self, range: R) -> TreeSlice<'a> {
2397        let s = match range.start_bound() {
2398            Bound::Included(&n) => n,
2399            Bound::Excluded(&n) => n + 1,
2400            Bound::Unbounded    => 0,
2401        };
2402        let e = match range.end_bound() {
2403            Bound::Included(&n) => n + 1,
2404            Bound::Excluded(&n) => n,
2405            Bound::Unbounded    => self.len_bytes(),
2406        };
2407        TreeSlice::new(self.tree, self.start + s, self.start + e)
2408    }
2409
2410    #[inline(always)]
2411    #[must_use]
2412    pub fn byte_to_char(&self, byte_offset: u32) -> u32 {
2413        self.try_byte_to_char(byte_offset).unwrap()
2414    }
2415
2416    #[inline(always)]
2417    #[must_use]
2418    pub fn try_byte_to_char(&self, byte_offset: u32) -> Option<u32> {
2419        let base = self.tree.try_byte_to_char(self.start)?;
2420        let abs  = self.tree.try_byte_to_char(self.start + byte_offset)?;
2421        Some(abs - base)
2422    }
2423
2424    #[inline(always)]
2425    #[must_use]
2426    pub fn char_to_byte(&self, char_index: u32) -> u32 {
2427        self.try_char_to_byte(char_index).unwrap()
2428    }
2429
2430    #[inline(always)]
2431    #[must_use]
2432    pub fn try_char_to_byte(&self, char_index: u32) -> Option<u32> {
2433        let base_char = self.tree.try_byte_to_char(self.start)?;
2434        let abs_byte  = self.tree.try_char_to_byte(base_char + char_index)?;
2435        Some(abs_byte - self.start)
2436    }
2437
2438    #[inline(always)]
2439    #[must_use]
2440    pub fn byte_to_line(&self, byte_offset: u32) -> u32 {
2441        self.try_byte_to_line(byte_offset).unwrap()
2442    }
2443
2444    #[inline(always)]
2445    #[must_use]
2446    pub fn try_byte_to_line(&self, byte_offset: u32) -> Option<u32> {
2447        let (abs_line, _) = self.tree.try_byte_to_line_col(self.start + byte_offset)?;
2448        let base_line     = self.tree.try_byte_to_line_col(self.start).map(|(l, _)| l)?;
2449        Some(abs_line - base_line)
2450    }
2451
2452    #[inline(always)]
2453    #[must_use]
2454    pub fn line_to_byte(&self, line: u32) -> u32 {
2455        self.try_line_to_byte(line).unwrap()
2456    }
2457
2458    #[inline(always)]
2459    #[must_use]
2460    pub fn try_line_to_byte(&self, line: u32) -> Option<u32> {
2461        let (abs_start, _) = self.abs_line_range(line)?;
2462        Some(abs_start - self.start)
2463    }
2464
2465    #[inline]
2466    #[must_use]
2467    pub fn abs_line_range(&self, rel_line: u32) -> Option<(u32, u32)> {
2468        let base_line = self.tree.try_byte_to_line_col(self.start).map(|(l, _)| l)?;
2469        let abs_line  = base_line + rel_line;
2470
2471        let line_start = self.tree.try_line_to_byte(abs_line)?;
2472        let line_end   = self.tree.try_line_to_byte(abs_line + 1)
2473            .unwrap_or_else(|| self.tree.len_bytes());
2474
2475        //
2476        // Clamp to slice bounds.
2477        //
2478        let s = line_start.max(self.start);
2479        let e = line_end.min(self.end);
2480        if s > e { return None; }
2481
2482        Some((s, e))
2483    }
2484}
2485
2486// Allow slicing directly from PieceTree.
2487impl PieceTree {
2488    #[inline]
2489    pub fn slice<R: RangeBounds<u32>>(&self, range: R) -> TreeSlice<'_> {
2490        let s = match range.start_bound() {
2491            Bound::Included(&n) => n,
2492            Bound::Excluded(&n) => n + 1,
2493            Bound::Unbounded    => 0,
2494        };
2495        let e = match range.end_bound() {
2496            Bound::Included(&n) => n + 1,
2497            Bound::Excluded(&n) => n,
2498            Bound::Unbounded    => self.len_bytes(),
2499        };
2500        TreeSlice::new(self, s, e)
2501    }
2502
2503    /// Slice by char range.
2504    #[inline]
2505    pub fn slice_chars_range<R: RangeBounds<u32>>(&self, range: R) -> TreeSlice<'_> {
2506        let sc = match range.start_bound() {
2507            Bound::Included(&n) => n,
2508            Bound::Excluded(&n) => n + 1,
2509            Bound::Unbounded    => 0,
2510        };
2511        let ec = match range.end_bound() {
2512            Bound::Included(&n) => n + 1,
2513            Bound::Excluded(&n) => n,
2514            Bound::Unbounded    => self.len_chars(),
2515        };
2516        let s = self.try_char_to_byte(sc).unwrap_or(0);
2517        let e = self.try_char_to_byte(ec).unwrap_or_else(|| self.len_bytes());
2518        TreeSlice::new(self, s, e)
2519    }
2520}
2521
2522impl PieceTree {
2523    /// Fast-path chunk reader specifically designed for the Tree-sitter C API.
2524    /// Given an absolute byte offset, it returns the largest contiguous byte
2525    /// slice available starting exactly at that offset.
2526    #[inline]
2527    #[must_use]
2528    pub fn read_largest_contigous_chunk_at_byte(&self, offset: u32) -> (&[u8], u32) {
2529        let total = self.total_length();
2530        if offset >= total {
2531            return (&[], offset);
2532        }
2533
2534        let mut current = self.root;
2535        let mut current_offset = offset;
2536        let mut doc_offset = 0u32;
2537
2538        while current != NIL {
2539            let node = self.pieces.get(current);
2540            let p = self.pieces.get_piece(current);
2541            let left_len = self.pieces.get(node.left).subtree_len;
2542            let piece_len = p.byte_length;
2543
2544            if current_offset < left_len {
2545                current = node.left;
2546
2547            } else if current_offset < left_len + piece_len {
2548                //
2549                // The requested offset falls inside this exact piece
2550                //
2551
2552                let rel_offset = current_offset - left_len;
2553                let piece_doc_start = doc_offset + left_len;
2554
2555                let text = self.buffers.get_slice(p.buffer, p.byte_offset, p.byte_length);
2556
2557                return (&text.as_bytes()[rel_offset as usize..], piece_doc_start);
2558
2559            } else {
2560                doc_offset     += left_len + piece_len;
2561                current_offset -= left_len + piece_len;
2562                current = node.right;
2563            }
2564        }
2565
2566        (&[], offset)
2567    }
2568
2569    #[inline]
2570    #[must_use]
2571    pub fn chunk_at_byte(&self, offset: u32) -> (&[u8], u32) {
2572        self.read_largest_contigous_chunk_at_byte(offset)
2573    }
2574
2575    #[inline]
2576    #[must_use]
2577    pub fn chunk_at_char(&self, char_index: u32) -> (&[u8], u32) {
2578        let Some(offset) = self.try_char_to_byte(char_index) else { return (&[], 0) };
2579        self.chunk_at_byte(offset)
2580    }
2581
2582    #[inline]
2583    #[must_use]
2584    pub fn chunk_at_line_break(&self, break_index: u32) -> (&[u8], u32) {
2585        let Some(offset) = self.try_line_break_to_byte(break_index) else { return (&[], 0) };
2586        self.chunk_at_byte(offset)
2587    }
2588
2589    #[inline]
2590    #[must_use]
2591    pub fn line_break_to_byte(&self, break_index: u32) -> u32 {
2592        self.try_line_break_to_byte(break_index).unwrap()
2593    }
2594
2595    #[inline]
2596    #[must_use]
2597    pub fn try_line_break_to_byte(&self, break_index: u32) -> Option<u32> {
2598        // @Cutnpaste from line_to_byte
2599
2600        let total_newlines = self.pieces.get(self.root).subtree_newlines;
2601        if break_index >= total_newlines { return None; }
2602
2603        let mut current = self.root;
2604        let mut current_offset = 0;
2605        let mut current_newlines = 0;
2606
2607        while current != NIL {
2608            let node = self.pieces.get(current);
2609            let p = self.pieces.get_piece(current);
2610            let left_newlines = self.pieces.get(node.left).subtree_newlines;
2611            let left_len      = self.pieces.get(node.left).subtree_len;
2612            let piece_newlines = p.newline_count;
2613
2614            if break_index < current_newlines + left_newlines {
2615                //
2616                // The target line break is somewhere in the left subtree
2617                //
2618                current = node.left;
2619
2620            } else if break_index < current_newlines + left_newlines + piece_newlines {
2621                //
2622                // The target line break is inside this piece
2623                //
2624                let rel_break = break_index - (current_newlines + left_newlines);
2625                let absolute_newline_index = p.buffer_start_line + rel_break;
2626
2627                let absolute_byte_offset = if p.buffer == MOD_BUFFER {
2628                    self.buffers.modifications_newline_offsets[absolute_newline_index as usize]
2629                } else {
2630                    self.buffers.original_buffers[p.buffer].newline_offsets[absolute_newline_index as usize]
2631                };
2632
2633                //
2634                //
2635                //
2636                //
2637                //
2638                // Unlike `line_to_byte` which adds + 1 to find the start of the *next* line,
2639                // we omit it here to return the exact byte offset of the newline character itself.
2640                //
2641                //
2642                //
2643                //
2644                //
2645                let local_piece_offset = absolute_byte_offset - p.byte_offset;
2646                return Some(current_offset + left_len + local_piece_offset);
2647
2648            } else {
2649                current_newlines += left_newlines + piece_newlines;
2650                current_offset   += left_len + p.byte_length;
2651                current = node.right;
2652            }
2653        }
2654
2655        None
2656    }
2657
2658    #[inline]
2659    #[must_use]
2660    pub fn line_to_byte(&self, target_line: u32) -> u32 {
2661        self.try_line_to_byte(target_line).unwrap()
2662    }
2663
2664    #[inline]
2665    #[must_use]
2666    pub fn try_line_to_byte(&self, target_line: u32) -> Option<u32> {
2667        if target_line == 0 { return Some(0) }
2668        let mut current = self.root;
2669        let mut current_offset = 0;
2670        let mut current_line = 0;
2671        while current != NIL {
2672            let node = self.pieces.get(current);
2673            let p = self.pieces.get_piece(current);
2674            let left_newlines = self.pieces.get(node.left).subtree_newlines;
2675            let left_len      = self.pieces.get(node.left).subtree_len;
2676            let piece_newlines = p.newline_count;
2677            let piece_len      = p.byte_length;
2678
2679            if target_line <= current_line + left_newlines {
2680                //
2681                // The target line starts somewhere in the left subtree
2682                //
2683                current = node.left;
2684
2685            } else if target_line <= current_line + left_newlines + piece_newlines {
2686                //
2687                // The target line starts inside this piece
2688                //
2689
2690                current_line   += left_newlines;
2691                current_offset += left_len;
2692
2693                let rel_line = target_line - current_line; // >= 1, guaranteed
2694                let absolute_newline_index = p.buffer_start_line + rel_line - 1;
2695                let absolute_byte_offset = if p.buffer == MOD_BUFFER {
2696                    self.buffers.modifications_newline_offsets[absolute_newline_index as usize]
2697                } else {
2698                    self.buffers.original_buffers[p.buffer].newline_offsets[absolute_newline_index as usize]
2699                };
2700
2701                let local_piece_offset = absolute_byte_offset - p.byte_offset + 1;
2702                return Some(current_offset + local_piece_offset);
2703
2704            } else {
2705                current_line   += left_newlines + piece_newlines;
2706                current_offset += left_len + piece_len;
2707                current = node.right;
2708            }
2709        }
2710
2711        None
2712    }
2713
2714    #[inline]
2715    #[must_use]
2716    pub fn char_to_byte(&self, char_index: u32) -> u32 {
2717        self.try_char_to_byte(char_index).unwrap()
2718    }
2719
2720    #[inline]
2721    #[must_use]
2722    pub fn try_char_to_byte(&self, char_index: u32) -> Option<u32> {
2723        let total_chars = self.len_chars();
2724        if char_index > total_chars { return None; }
2725        if char_index == total_chars { return Some(self.len_bytes()); }
2726
2727        let mut current = self.root;
2728        let mut current_byte = 0;
2729        let mut current_char = 0;
2730
2731        while current != NIL {
2732            let node = self.pieces.get(current);
2733            let left_node = self.pieces.get(node.left);
2734
2735            let left_chars = left_node.subtree_chars;
2736            let left_bytes = left_node.subtree_len;
2737
2738            let p = self.pieces.get_piece(current);
2739            let piece_chars = p.char_count;
2740
2741            if char_index < current_char + left_chars {
2742                current = node.left;
2743
2744            } else if char_index < current_char + left_chars + piece_chars {
2745                //
2746                // Target char is inside this piece,
2747                // p.piece_start_char is the absolute char index of p.offset in its buffer,
2748                // so (p.piece_start_char + rel_char) is the absolute char target.
2749                //
2750
2751                let rel_char = char_index - (current_char + left_chars);
2752                let absolute_target_byte =
2753                    self.buffers.char_to_byte_absolute(p.buffer, p.piece_start_char + rel_char);
2754
2755                return Some(current_byte + left_bytes + (absolute_target_byte - p.byte_offset));
2756
2757            } else {
2758                current_char += left_chars + piece_chars;
2759                current_byte += left_bytes + p.byte_length;
2760                current = node.right;
2761            }
2762        }
2763
2764        None
2765    }
2766
2767    #[inline]
2768    #[must_use]
2769    pub fn byte_to_char(&self, byte_offset: u32) -> u32 {
2770        self.try_byte_to_char(byte_offset).unwrap()
2771    }
2772
2773    #[inline]
2774    #[must_use]
2775    pub fn try_byte_to_char(&self, byte_offset: u32) -> Option<u32> {
2776        let total_bytes = self.len_bytes();
2777        if byte_offset > total_bytes { return None; }
2778        if byte_offset == total_bytes { return Some(self.len_chars()); }
2779
2780        let mut current = self.root;
2781        let mut current_byte = 0;
2782        let mut current_char = 0;
2783
2784        while current != NIL {
2785            let node = self.pieces.get(current);
2786            let left_node = self.pieces.get(node.left);
2787
2788            let left_bytes = left_node.subtree_len;
2789            let left_chars = left_node.subtree_chars;
2790
2791            let p = self.pieces.get_piece(current);
2792            let piece_bytes = p.byte_length;
2793
2794            if byte_offset < current_byte + left_bytes {
2795                current = node.left;
2796
2797            } else if byte_offset < current_byte + left_bytes + piece_bytes {
2798                // Target byte is inside this piece.
2799                // byte_to_char_absolute gives the absolute char index, so subtracting
2800                // piece_start_char converts it to a piece-relative char count.
2801
2802                let rel_byte = byte_offset - (current_byte + left_bytes);
2803                let absolute_target_char =
2804                    self.buffers.byte_to_char_absolute(p.buffer, p.byte_offset + rel_byte);
2805
2806                return Some(current_char + left_chars + (absolute_target_char - p.piece_start_char));
2807
2808            } else {
2809                current_byte += left_bytes + piece_bytes;
2810                current_char += left_chars + p.char_count;
2811                current = node.right;
2812            }
2813        }
2814
2815        None
2816    }
2817
2818    #[inline]
2819    #[must_use]
2820    pub fn byte_to_line(&self, offset: u32) -> u32 {
2821        self.try_byte_to_line(offset).unwrap()
2822    }
2823
2824    #[inline]
2825    #[must_use]
2826    pub fn try_byte_to_line(&self, offset: u32) -> Option<u32> {
2827        self.try_byte_to_line_col(offset).map(|(l, _)| l)
2828    }
2829
2830    #[inline]
2831    #[must_use]
2832    pub fn byte_to_line_col(&self, offset: u32) -> (u32, u32) {
2833        self.try_byte_to_line_col(offset).unwrap()
2834    }
2835
2836    #[inline]
2837    #[must_use]
2838    pub fn try_byte_to_line_col(&self, offset: u32) -> Option<(u32, u32)> {
2839        let total_bytes = self.len_bytes();
2840        if offset > total_bytes { return None }
2841        if offset == total_bytes {
2842            //
2843            // Get offset of the last line
2844            //
2845            let line            = self.pieces.get(self.root).subtree_newlines;
2846            let line_start_byte = self.try_line_to_byte(line).unwrap_or(0);
2847            let target_char     = self.len_chars();
2848            let line_start_char = self.try_byte_to_char(line_start_byte)?;
2849            return Some((line, target_char - line_start_char));
2850        }
2851
2852        let mut current         = self.root;
2853        let mut current_line    = 0u32;
2854        let mut current_byte    = 0u32;
2855        let mut current_char    = 0u32;
2856
2857        while current != NIL {
2858            let node          = self.pieces.get(current);
2859            let left_node     = self.pieces.get(node.left);
2860            let left_bytes    = left_node.subtree_len;
2861            let left_newlines = left_node.subtree_newlines;
2862            let left_chars    = left_node.subtree_chars;
2863            let p             = self.pieces.get_piece(current);
2864            let piece_bytes   = p.byte_length;
2865
2866            if offset < current_byte + left_bytes {
2867                current = node.left;
2868
2869            } else if offset < current_byte + left_bytes + piece_bytes {
2870                current_line += left_newlines;
2871                current_char += left_chars;
2872
2873                let rel_byte = offset - (current_byte + left_bytes);
2874
2875                let (local_newlines, col) = if p.newline_count == 0 {
2876                    let target_char = self.buffers.byte_to_char_absolute(p.buffer, p.byte_offset + rel_byte);
2877                    let rel_char    = target_char - p.piece_start_char;
2878                    let abs_char    = current_char + rel_char;
2879
2880                    let line_start_byte = self.try_line_to_byte(current_line)?;
2881                    let line_start_char = self.try_byte_to_char(line_start_byte)?;
2882
2883                    (0, abs_char - line_start_char)
2884                } else {
2885                    let start_index       = p.buffer_start_line as usize;
2886                    let end_index         = start_index + p.newline_count as usize;
2887                    let absolute_target = p.byte_offset + rel_byte;
2888
2889                    let offsets = &self.buffers.get_newlines(p.buffer)[start_index..end_index];
2890
2891                    let local_nl = offsets.partition_point(|&off| off < absolute_target) as u32;
2892
2893                    let target_char = self.buffers.byte_to_char_absolute(p.buffer, p.byte_offset + rel_byte);
2894                    let col = if local_nl > 0 {
2895                        let last_nl_abs_byte = offsets[local_nl as usize - 1];
2896                        let last_nl_char     = self.buffers.byte_to_char_absolute(p.buffer, last_nl_abs_byte);
2897                        target_char - (last_nl_char + 1)
2898                    } else {
2899                        let line_start_byte = self.try_line_to_byte(current_line)?;
2900                        let line_start_char = self.try_byte_to_char(line_start_byte)?;
2901                        let rel_char        = target_char - p.piece_start_char;
2902                        (current_char + rel_char) - line_start_char
2903                    };
2904
2905                    (local_nl, col)
2906                };
2907
2908                return Some((current_line + local_newlines, col));
2909
2910            } else {
2911                current_line += left_newlines + p.newline_count;
2912                current_byte += left_bytes + piece_bytes;
2913                current_char += left_chars + p.char_count;
2914                current = node.right;
2915            }
2916        }
2917
2918        None
2919    }
2920
2921    #[inline]
2922    #[must_use]
2923    pub fn pieces(&self) -> PieceTreeIter<'_> {
2924        PieceTreeIter::new(&self.pieces, self.root)
2925    }
2926
2927    #[inline]
2928    #[must_use]
2929    pub fn get_line_range(&self, line: u32) -> (u32, u32) {
2930        self.try_get_line_range(line).unwrap()
2931    }
2932
2933    #[inline]
2934    #[must_use]
2935    pub fn try_get_line_range(&self, line: u32) -> Option<(u32, u32)> {
2936        let start = self.try_line_to_byte(line)?;
2937        let end = self.try_line_to_byte(line + 1).unwrap_or_else(|| self.total_length());
2938        Some((start, end))
2939    }
2940
2941    #[inline]
2942    #[must_use]
2943    pub fn get_line_content_allocating(&self, line: u32) -> Option<String> {
2944        let (start, end) = self.try_get_line_range(line)?;
2945
2946        let mut content = String::with_capacity((end - start) as usize);
2947        let mut walker = TreeWalker::new(self);
2948
2949        walker.seek(start);
2950        while walker.offset < end {
2951            if let Some(c) = walker.next() {
2952                content.push(c);
2953            } else {
2954                break;
2955            }
2956        }
2957
2958        Some(content)
2959    }
2960
2961    /// Byte at a given byte offset. O(log n).
2962    #[inline]
2963    #[must_use]
2964    pub fn byte(&self, offset: u32) -> u8 {
2965        self.try_byte(offset).unwrap()
2966    }
2967
2968    /// Byte at a given byte offset. O(log n).
2969    #[inline]
2970    #[must_use]
2971    pub fn try_byte(&self, offset: u32) -> Option<u8> {
2972        let (node, rel) = self.find_position(offset, false)?;
2973        let p = self.get_piece(node);
2974        let text = self.buffers.get_slice(p.buffer, p.byte_offset, p.byte_length);
2975        text.as_bytes().get(rel as usize).copied()
2976    }
2977
2978    /// Char at a given char index. O(log n) to find the piece, then
2979    /// a short scan within the piece.
2980    #[inline]
2981    #[must_use]
2982    pub fn char(&self, char_index: u32) -> char {
2983        self.try_char(char_index).unwrap()
2984    }
2985
2986    /// Char at a given char index. O(log n) to find the piece, then
2987    /// a short scan within the piece.
2988    #[inline]
2989    #[must_use]
2990    pub fn try_char(&self, char_index: u32) -> Option<char> {
2991        let byte_offset = self.try_char_to_byte(char_index)?;
2992        let (node, rel) = self.find_position(byte_offset, false)?;
2993        let p = self.get_piece(node);
2994        let text = self.buffers.get_slice(p.buffer, p.byte_offset, p.byte_length);
2995        text[rel as usize..].chars().next()
2996    }
2997
2998    /// Returns a non-allocating iterator of chars over the given char range.
2999    /// Backed by `TreeWalker::seek` so it reuses existing infrastructure.
3000    #[inline]
3001    #[must_use]
3002    pub fn slice_chars(&self, char_start: u32, char_end: u32) -> SliceChars<'_> {
3003        let byte_start = self.try_char_to_byte(char_start).unwrap_or(0);
3004        let byte_end   = self.try_char_to_byte(char_end).unwrap_or_else(|| self.total_length());
3005        SliceChars {
3006            walker:   { let mut w = TreeWalker::new(self); w.seek(byte_start); w },
3007            byte_end,
3008        }
3009    }
3010
3011    /// Returns a non-allocating iterator of chars over the given byte range.
3012    #[inline]
3013    #[must_use]
3014    pub fn slice_bytes(&self, byte_start: u32, byte_end: u32) -> SliceChars<'_> {
3015        SliceChars {
3016            walker:   { let mut w = TreeWalker::new(self); w.seek(byte_start); w },
3017            byte_end,
3018        }
3019    }
3020
3021    /// Non-allocating line view: returns a `ChunkIter` over the byte range of
3022    /// `line`. Line numbers are 0-based. The trailing \n is included if present.
3023    #[inline]
3024    #[must_use]
3025    pub fn line(&self, line: u32) -> TreeSlice<'_> {
3026        self.try_line(line).unwrap()
3027    }
3028
3029    #[inline]
3030    #[must_use]
3031    pub fn try_line(&self, line: u32) -> Option<TreeSlice<'_>> {
3032        let start = self.try_line_to_byte(line)?;
3033        let end = self.try_line_to_byte(line + 1).unwrap_or_else(|| self.len_bytes());
3034
3035        Some(self.slice(start..end))
3036    }
3037
3038    /// Number of lines (= newline count + 1)
3039    #[inline]
3040    #[must_use]
3041    pub fn len_lines(&self) -> u32 { self.pieces.get(self.root).subtree_newlines + 1 }
3042
3043    #[inline(always)]
3044    #[must_use]
3045    pub fn len_chars(&self) -> u32 { self.pieces.get(self.root).subtree_chars }
3046
3047    #[inline]
3048    #[must_use]
3049    pub fn len_bytes(&self) -> u32 { self.total_length() }
3050
3051    #[inline]
3052    pub fn remove<R>(&mut self, range: R) where R: RangeBounds<u32> {
3053        let start = match range.start_bound() {
3054            Bound::Included(&n) => n,
3055            Bound::Excluded(&n) => n + 1,
3056            Bound::Unbounded => 0,
3057        };
3058        let end = match range.end_bound() {
3059            Bound::Included(&n) => n + 1,
3060            Bound::Excluded(&n) => n,
3061            Bound::Unbounded => self.len_bytes(),
3062        };
3063        if end > start { self.remove_at(start, end - start) }
3064    }
3065
3066    #[inline]
3067    #[must_use]
3068    pub fn char_to_line(&self, char_index: u32) -> u32 {
3069        self.try_char_to_line(char_index).unwrap()
3070    }
3071
3072    #[inline]
3073    #[must_use]
3074    pub fn try_char_to_line(&self, char_index: u32) -> Option<u32> {
3075        let byte_index = self.try_char_to_byte(char_index)?;
3076        self.try_byte_to_line_col(byte_index).map(|(line, _)| line)
3077    }
3078
3079    #[inline]
3080    #[must_use]
3081    pub fn char_to_line_col(&self, char_index: u32) -> (u32, u32) {
3082        self.try_char_to_line_col(char_index).unwrap()
3083    }
3084
3085    #[inline]
3086    #[must_use]
3087    pub fn try_char_to_line_col(&self, char_index: u32) -> Option<(u32, u32)> {
3088        let byte_index = self.try_char_to_byte(char_index)?;
3089        self.try_byte_to_line_col(byte_index)
3090    }
3091
3092    #[inline]
3093    #[must_use]
3094    pub fn line_to_char(&self, line: u32) -> u32 {
3095        self.try_line_to_char(line).unwrap()
3096    }
3097
3098    #[inline]
3099    #[must_use]
3100    pub fn try_line_to_char(&self, line: u32) -> Option<u32> {
3101        let byte_index = self.try_line_to_byte(line)?;
3102        self.try_byte_to_char(byte_index)
3103    }
3104}
3105
3106#[derive(Debug)]
3107pub struct PieceTreeIter<'a, const MAX_INLINE_TREE_DEPTH: usize = 32> {
3108    arena: &'a Pieces,
3109    stack: SmallVec<[NodeRef; MAX_INLINE_TREE_DEPTH]>,
3110}
3111
3112impl<'a, const MAX_INLINE_TREE_DEPTH: usize> PieceTreeIter<'a, MAX_INLINE_TREE_DEPTH> {
3113    #[inline]
3114    #[must_use]
3115    pub fn new(arena: &'a Pieces, mut root: NodeRef) -> Self {
3116        let mut stack = SmallVec::new();
3117        while root != NIL {
3118            stack.push(root);
3119            root = arena.get(root).left;
3120        }
3121
3122        Self { arena, stack }
3123    }
3124}
3125
3126impl<const MAX_INLINE_TREE_DEPTH: usize> Iterator for PieceTreeIter<'_, MAX_INLINE_TREE_DEPTH> {
3127    type Item = (NodeRef, Piece);
3128
3129    #[inline]
3130    fn next(&mut self) -> Option<Self::Item> {
3131        let node_index = self.stack.pop()?;
3132        let node = self.arena.get(node_index);
3133        let p = self.arena.get_piece(node_index);
3134
3135        let mut current = node.right;
3136        while current != NIL {
3137            self.stack.push(current);
3138            current = self.arena.get(current).left;
3139        }
3140
3141        Some((node_index, p))
3142    }
3143}
3144
3145#[derive(Clone, Copy, PartialEq, Debug)]
3146enum Direction { Left, Center, Right }
3147
3148#[derive(Debug)]
3149pub struct TreeWalker<'a, const MAX_INLINE_TREE_DEPTH: usize = 32> {
3150    tree: &'a PieceTree,
3151    stack: SmallVec<[(NodeRef, Direction); MAX_INLINE_TREE_DEPTH]>,
3152    current_str: str::Chars<'a>,
3153    pub offset: u32,
3154}
3155
3156impl<'a, const MAX_INLINE_TREE_DEPTH: usize> TreeWalker<'a, MAX_INLINE_TREE_DEPTH> {
3157    #[inline]
3158    #[must_use]
3159    pub fn new(tree: &'a PieceTree) -> Self {
3160        let mut walker = Self {
3161            tree,
3162            stack: SmallVec::new(),
3163            current_str: "".chars(),
3164            offset: 0,
3165        };
3166        if tree.root != NIL {
3167            walker.stack.push((tree.root, Direction::Left));
3168        }
3169        walker.populate_chars();
3170        walker
3171    }
3172
3173    #[inline]
3174    pub fn seek(&mut self, target: u32) {
3175        self.stack.clear();
3176        self.offset = target;
3177        self.current_str = "".chars();
3178
3179        if self.tree.root == NIL { return; }
3180
3181        let mut current = self.tree.root;
3182        let mut current_offset = target;
3183
3184        while current != NIL {
3185            let node = self.tree.pieces.get(current);
3186            let p = self.tree.pieces.get_piece(current);
3187            let left_len = self.tree.pieces.get(node.left).subtree_len;
3188            let piece_len = p.byte_length;
3189
3190            if current_offset < left_len {
3191                self.stack.push((current, Direction::Center));
3192                current = node.left;
3193            } else if current_offset < left_len + piece_len {
3194                self.stack.push((current, Direction::Right));
3195                let text = self.tree.buffers.get_slice(p.buffer, p.byte_offset, p.byte_length);
3196                let rel_offset = current_offset - left_len;
3197                self.current_str = text[rel_offset as usize..].chars();
3198                break;
3199            } else {
3200                current_offset -= left_len + piece_len;
3201                current = node.right;
3202            }
3203        }
3204    }
3205
3206    #[inline]
3207    fn populate_chars(&mut self) {
3208        while let Some((node_index, dir)) = self.stack.pop() {
3209            let node = self.tree.pieces.get(node_index);
3210            match dir {
3211                Direction::Left => {
3212                    self.stack.push((node_index, Direction::Center));
3213                    if node.left != NIL { self.stack.push((node.left, Direction::Left)); }
3214                }
3215
3216                Direction::Center => {
3217                    self.stack.push((node_index, Direction::Right));
3218                    let p = self.tree.pieces.get_piece(node_index);
3219                    let text = self.tree.buffers.get_slice(p.buffer, p.byte_offset, p.byte_length);
3220                    self.current_str = text.chars();
3221                    return;
3222                }
3223
3224                Direction::Right => {
3225                    if node.right != NIL { self.stack.push((node.right, Direction::Left)); }
3226                }
3227            }
3228        }
3229    }
3230}
3231
3232impl Iterator for TreeWalker<'_> {
3233    type Item = char;
3234
3235    #[inline(always)]
3236    fn next(&mut self) -> Option<char> {
3237        loop {
3238            if let Some(c) = self.current_str.next() {
3239                self.offset += c.len_utf8() as u32;
3240                return Some(c);
3241            }
3242
3243            if self.stack.is_empty() { return None; }
3244            self.populate_chars();
3245        }
3246    }
3247}
3248
3249#[derive(Debug)]
3250pub struct ReverseTreeWalker<'a, const MAX_INLINE_TREE_DEPTH: usize = 32> {
3251    tree: &'a PieceTree,
3252    stack: SmallVec<[(NodeRef, bool); MAX_INLINE_TREE_DEPTH]>,
3253    current_str: str::Chars<'a>,
3254}
3255
3256impl<'a, const MAX_INLINE_TREE_DEPTH: usize> ReverseTreeWalker<'a, MAX_INLINE_TREE_DEPTH> {
3257    #[inline(always)]
3258    #[must_use]
3259    pub fn new(tree: &'a PieceTree) -> Self {
3260        let mut walker = Self {
3261            tree,
3262            stack: SmallVec::new(),
3263            current_str: "".chars(),
3264        };
3265        walker.push_rightmost(tree.root);
3266        walker
3267    }
3268
3269    #[inline]
3270    #[must_use]
3271    pub fn new_at(tree: &'a PieceTree, target_offset: u32) -> Self {
3272        let mut walker = Self {
3273            tree,
3274            stack: SmallVec::new(),
3275            current_str: "".chars(),
3276        };
3277        walker.seek(target_offset);
3278        walker
3279    }
3280
3281    #[inline(always)]
3282    fn push_rightmost(&mut self, mut node: NodeRef) {
3283        while node != NIL {
3284            self.stack.push((node, false));
3285            node = self.tree.pieces.get(node).right;
3286        }
3287    }
3288
3289    #[inline]
3290    pub fn seek(&mut self, mut target_offset: u32) {
3291        self.stack.clear();
3292        self.current_str = "".chars();
3293
3294        if self.tree.root == NIL { return; }
3295
3296        let total_bytes = self.tree.len_bytes();
3297
3298        if target_offset > total_bytes {
3299            target_offset = total_bytes;
3300        }
3301        if target_offset == total_bytes {
3302            self.push_rightmost(self.tree.root);
3303            return;
3304        }
3305
3306        let mut current = self.tree.root;
3307        let mut current_offset = target_offset;
3308
3309        while current != NIL {
3310            let node = self.tree.pieces.get(current);
3311            let p = self.tree.pieces.get_piece(current);
3312            let left_len = self.tree.pieces.get(node.left).subtree_len;
3313            let piece_len = p.byte_length;
3314
3315            if current_offset < left_len {
3316                self.stack.push((current, true));
3317                current = node.left;
3318
3319            } else if current_offset < left_len + piece_len {
3320                self.stack.push((current, true));
3321
3322                let text = self.tree.buffers.get_slice(p.buffer, p.byte_offset, p.byte_length);
3323                let rel_offset = current_offset - left_len;
3324
3325                // Keep the subset of the string before the offset
3326                self.current_str = text[..rel_offset as usize].chars();
3327
3328                break;
3329
3330            } else {
3331                self.stack.push((current, false));
3332                current_offset -= left_len + piece_len;
3333                current = node.right;
3334            }
3335        }
3336    }
3337}
3338
3339impl Iterator for ReverseTreeWalker<'_> {
3340    type Item = char;
3341
3342    #[inline]
3343    fn next(&mut self) -> Option<Self::Item> {
3344        if let Some(c) = self.current_str.next_back() { return Some(c); }
3345
3346        while let Some((node_index, visited_right)) = self.stack.pop() {
3347            let node = self.tree.pieces.get(node_index);
3348            if visited_right {
3349                self.push_rightmost(node.left);
3350            } else {
3351                self.stack.push((node_index, true));
3352
3353                let p = self.tree.pieces.get_piece(node_index);
3354                let text_slice = self.tree.buffers.get_slice(p.buffer, p.byte_offset, p.byte_length);
3355
3356                self.current_str = text_slice.chars();
3357
3358                if let Some(c) = self.current_str.next_back() { return Some(c); }
3359            }
3360        }
3361
3362        None
3363    }
3364}
3365
3366impl PieceTree {
3367    #[inline]
3368    pub fn debug(&self, f: &mut impl core::fmt::Write) -> core::fmt::Result {
3369        writeln!(f, "\n--- Tree State (Root: {:?}) ---", self.root)?;
3370        self.print_inorder(f, self.root, &mut None, 0)?;
3371        writeln!(f, "------------------------------\n")
3372    }
3373
3374    fn print_inorder(&self, f: &mut impl core::fmt::Write, node: NodeRef, last: &mut Option<Piece>, depth: usize) -> core::fmt::Result {
3375        if node == NIL { return Ok(()) }
3376
3377        let n = self.pieces.nodes[node];
3378
3379        self.print_inorder(f, n.left, last, depth + 1)?;
3380
3381        let cur = self.get_piece(node);
3382
3383        //
3384        // Check for the mergeable invariant
3385        //
3386        let warning = if let Some(prev) = last {
3387            if prev.buffer == cur.buffer
3388               && prev.byte_offset + prev.byte_length == cur.byte_offset
3389            {
3390                " --------- [!!! MERGEABLE NEIGHBORS NOT MERGED !!!] ---------"
3391            } else {
3392                ""
3393            }
3394        } else {
3395            ""
3396        };
3397
3398        let Piece { buffer, byte_offset: offset, byte_length: length, .. } = cur;
3399
3400        writeln!(
3401            f,
3402            "{:indent$}Node {node:?}: Buf={}, Off={offset}, Len={length}{warning}",
3403            "", buffer.as_u32(), indent = depth * 4
3404        )?;
3405
3406        *last = Some(cur);
3407
3408        self.print_inorder(f, n.right, last, depth + 1)
3409    }
3410}
3411
3412pub fn assert_state(tree: &PieceTree, expected: &str) {
3413    let tree_text = tree.to_string();
3414
3415    assert_eq!(tree_text, expected, "Text mismatch");
3416
3417    if !expected.is_empty() {
3418        let offsets = [0, expected.len() / 2, expected.len() - 1];
3419        for off in offsets {
3420            let chunk = tree.read_largest_contigous_chunk_at_byte(off as u32).0;
3421            let chunk_str = str::from_utf8(chunk).unwrap();
3422            assert!(
3423                expected[off..].starts_with(chunk_str),
3424                "Chunk mismatch at offset {}",
3425                off
3426            );
3427        }
3428    }
3429}
3430
3431pub fn assert_invariants(tree: &PieceTree) {
3432    fn check(tree: &PieceTree, node: NodeRef) -> (usize, usize) {
3433        if node == NIL { return (0, 1) }
3434
3435        let n = tree.pieces.nodes[node];
3436        let piece = tree.get_piece(node);
3437
3438        let (l_len, l_bh) = check(tree, n.left);
3439        let (r_len, r_bh) = check(tree, n.right);
3440
3441        let expected_len = l_len + piece.byte_length as usize + r_len;
3442        assert_eq!(n.subtree_len as usize, expected_len, "subtree_len mismatch");
3443
3444        if n.color() == Color::Red {
3445            assert_eq!(
3446                tree.pieces.nodes[n.left].color(),
3447                Color::Black,
3448                "red node with red left child"
3449            );
3450            assert_eq!(
3451                tree.pieces.nodes[n.right].color(),
3452                Color::Black,
3453                "red node with red right child"
3454            );
3455        }
3456
3457        assert_eq!(l_bh, r_bh, "black height mismatch");
3458
3459        let bh = l_bh + usize::from(n.color() == Color::Black);
3460        (expected_len, bh)
3461    }
3462
3463    if tree.root == NIL {
3464        assert_eq!(tree.total_length(), 0,            "Empty tree has nonzero length");
3465    } else {
3466        assert_eq!(
3467            tree.pieces.nodes[tree.root].color(),
3468            Color::Black,
3469            "root is not black"
3470        );
3471        let (len, _) = check(tree, tree.root);
3472        assert_eq!(len, tree.total_length() as usize, "Tree length and root length differ");
3473
3474    }
3475}
3476
3477pub fn assert_piece_metadata(tree: &PieceTree) {
3478    fn collect(tree: &PieceTree, node: NodeRef, out: &mut Vec<Piece>) {
3479        if node == NIL { return }
3480
3481        let n = tree.pieces.nodes[node];
3482
3483        collect(tree, n.left, out);
3484        out.push(tree.pieces.get_piece(node));
3485        collect(tree, n.right, out);
3486    }
3487
3488    let mut pieces = Vec::new();
3489    collect(tree, tree.root, &mut pieces);
3490
3491    for p in &pieces {
3492        let buf   = tree.buffers.get(p.buffer);
3493        let start = p.byte_offset as usize;
3494        let end   = start + p.byte_length as usize;
3495
3496        assert!(end <= buf.len(), "Piece points past end of buffer");
3497        assert!(p.byte_length > 0, "Zero-length piece found");
3498
3499        let slice = &buf[start..end];
3500        let (actual_chars, actual_nl) = count_chars_and_newlines(slice.as_bytes());
3501        assert_eq!(p.char_count,    actual_chars, "char_count mismatch");
3502        assert_eq!(p.newline_count, actual_nl,    "newline_count mismatch");
3503
3504        //
3505        // piece_start_char and buffer_start_line: scan only the prefix once
3506        //
3507        let prefix = &buf.as_bytes()[..p.byte_offset as usize];
3508        let actual_start_char = bytecount::num_chars(prefix) as u32;
3509        let actual_start_line = bytecount::count(prefix, b'\n') as u32;
3510
3511        assert_eq!(p.piece_start_char,  actual_start_char,
3512            "piece_start_char mismatch buffer={} offset={}", p.buffer.as_u32(), p.byte_offset);
3513
3514        assert_eq!(p.buffer_start_line, actual_start_line,
3515            "buffer_start_line mismatch buffer={} offset={}", p.buffer.as_u32(), p.byte_offset);
3516
3517        //
3518        // Verify the newline_offsets slice
3519        //
3520        let nl_offsets = &tree.buffers.get_newlines(p.buffer)
3521            [p.buffer_start_line as usize..(p.buffer_start_line + p.newline_count) as usize];
3522
3523        for (i, &abs_byte) in nl_offsets.iter().enumerate() {
3524            assert!(
3525                abs_byte >= p.byte_offset && abs_byte < p.byte_offset + p.byte_length,
3526                "newline_offsets[{}] outside piece", p.buffer_start_line as usize + i
3527            );
3528
3529            assert_eq!(
3530                buf.as_bytes()[abs_byte as usize], b'\n',
3531                "newline_offsets[{}] not a newline", p.buffer_start_line as usize + i
3532            );
3533        }
3534    }
3535}
3536
3537pub fn assert_no_mergeable_neighbors(tree: &PieceTree) {
3538    fn inorder(tree: &PieceTree, node: NodeRef, last: &mut Option<Piece>) {
3539        if node == NIL { return }
3540
3541        let n = tree.pieces.nodes[node];
3542        inorder(tree, n.left, last);
3543
3544        let cur = tree.get_piece(node);
3545
3546        if let Some(prev) = *last {
3547            if prev.buffer == cur.buffer
3548                && prev.byte_offset + prev.byte_length == cur.byte_offset
3549            {
3550                panic!("Mergeable neighboring pieces were left unmerged");
3551            }
3552        }
3553
3554        *last = Some(cur);
3555        inorder(tree, n.right, last);
3556    }
3557
3558    let mut last = None;
3559    inorder(tree, tree.root, &mut last);
3560}
3561
3562pub fn assert_coordinates(tree: &PieceTree, oracle: &str) {
3563    #[inline]
3564    fn oracle_offset_to_line_col(s: &str, byte_offset: usize) -> (usize, usize) {
3565        let slice = &s[..byte_offset];
3566        let line  = bytecount::count(slice.as_bytes(), b'\n');
3567        let last_nl = slice.rfind('\n').map_or(0, |i| i + 1);
3568        let col   = bytecount::num_chars(s[last_nl..byte_offset].as_bytes());
3569        (line, col)
3570    }
3571
3572    #[inline]
3573    fn oracle_line_to_offset(s: &str, target_line: usize) -> usize {
3574        if target_line == 0 { return 0 }
3575
3576        let mut line = 0;
3577        for (i, c) in s.char_indices() {
3578            if c == '\n' {
3579                line += 1;
3580                if line == target_line { return i + 1; }
3581            }
3582        }
3583
3584        s.len()
3585    }
3586
3587    fn check_coordinate(tree: &PieceTree, oracle: &str, byte_index: u32) {
3588        let char_index = bytecount::num_chars(oracle[..byte_index as usize].as_bytes()) as u32;
3589
3590        assert_eq!(tree.char_to_byte(char_index), byte_index,
3591                   "char_to_byte({}) wrong", char_index);
3592
3593        assert_eq!(tree.byte_to_char(byte_index), char_index,
3594                   "byte_to_char({}) wrong", byte_index);
3595
3596        let expected_lc = oracle_offset_to_line_col(oracle, byte_index as usize);
3597        assert_eq!(
3598            tree.byte_to_line_col(byte_index),
3599            (expected_lc.0 as u32, expected_lc.1 as u32),
3600            "offset_to_line_col({}) wrong", byte_index
3601        );
3602    }
3603
3604    let total_bytes = oracle.len() as u32;
3605    let total_chars = oracle.chars().count() as u32;
3606
3607    //
3608    // Always check these
3609    //
3610    check_coordinate(tree, oracle, 0);
3611    if total_bytes > 0 {
3612        check_coordinate(tree, oracle, total_bytes - 1);
3613        check_coordinate(tree, oracle, total_bytes / 2);
3614    }
3615
3616
3617    //
3618    // Sample ~8 positions spread across the document
3619    //
3620    for i in 0u32..8 {
3621        let byte =
3622            ((total_bytes as u64 * ((i as u64 * 2_654_435_761) & 0xFFFF_FFFF)) >> 32) as u32 % total_bytes.max(1);
3623
3624        // Snap to char boundary
3625        let byte = oracle.as_bytes()[..byte as usize]
3626            .iter().rposition(|&b| !(0x80..0xC0).contains(&b))
3627            .map_or(0, |i| i as u32);
3628
3629        check_coordinate(tree, oracle, byte);
3630    }
3631
3632    //
3633    // EOF and out-of-bounds always
3634    //
3635    assert_eq!(tree.char_to_byte(total_chars), total_bytes);
3636    assert_eq!(tree.byte_to_char(total_bytes), total_chars);
3637    assert_eq!(tree.try_char_to_byte(total_chars + 1), None);
3638    assert_eq!(tree.try_byte_to_char(total_bytes + 1), None);
3639    assert_eq!(tree.try_byte_to_line_col(total_bytes + 1), None);
3640
3641    //
3642    // line_to_offset: check first, last, middle line only
3643    //
3644    let total_lines = oracle.chars().filter(|&c| c == '\n').count() + 1;
3645    for line in [0, total_lines / 2, total_lines.saturating_sub(1)] {
3646        let expected = oracle_line_to_offset(oracle, line) as u32;
3647        assert_eq!(tree.try_line_to_byte(line as u32), Some(expected),
3648            "line_to_offset({}) wrong", line);
3649    }
3650
3651    assert_eq!(tree.try_line_to_byte(total_lines as u32), None);
3652}