1use std::{iter::FusedIterator, ops::RangeBounds, str::from_utf8_unchecked};
2
3use gapbuf::GapBuffer;
4use lender::{DoubleEndedLender, ExactSizeLender, Lender, Lending};
5
6use super::{Point, TextRange, records::Records, utf8_char_width};
7
8#[derive(Default, Clone)]
12pub struct Bytes {
13 buf: GapBuffer<u8>,
14 records: Records<[usize; 3]>,
15}
16
17impl Bytes {
18 pub(crate) fn new(string: &str) -> Self {
20 let buf = GapBuffer::from_iter(string.bytes());
21
22 let len = buf.len();
23 let chars = unsafe {
24 let (s0, s1) = buf.as_slices();
25 std::str::from_utf8_unchecked(s0).chars().count()
26 + std::str::from_utf8_unchecked(s1).chars().count()
27 };
28 let lines = buf.iter().filter(|b| **b == b'\n').count();
29 Self {
30 buf,
31 records: Records::with_max([len, chars, lines]),
32 }
33 }
34
35 pub fn len(&self) -> Point {
39 let [b, c, l] = self.records.max();
40 Point::from_raw(b, c, l)
41 }
42
43 pub fn is_empty(&self) -> bool {
54 self.buf.is_empty()
55 }
56
57 pub fn char_at(&self, p: Point) -> Option<char> {
59 if p.byte() >= self.len().byte() {
60 return None;
61 }
62
63 let [s0, s1] = self.strs(..).to_array();
64 if p.byte() < s0.len() {
65 s0[p.byte()..].chars().next()
66 } else {
67 s1[p.byte() - s0.len()..].chars().next()
68 }
69 }
70
71 pub fn buffers(&self, range: impl TextRange) -> Buffers {
78 let range = range.to_range(self.buf.len());
79 let (s0, s1) = self.buf.range(range).as_slices();
80 Buffers([s0.iter(), s1.iter()])
81 }
82
83 pub fn strs(&self, range: impl TextRange) -> Strs {
124 let range = range.to_range(self.buf.len());
125 Strs(self.strs_in_range_inner(range).into_iter())
126 }
127
128 pub fn lines(&self, range: impl TextRange) -> Lines<'_> {
135 let range = range.to_range(self.len().byte());
136 let start = self.point_at_line(self.point_at(range.start).line());
137 let end = {
138 let end = self.point_at(range.end);
139 let line_start = self.point_at_line(end.line());
140 match line_start == end {
141 true => end,
142 false => self.point_at_line((end.line() + 1).min(self.len().line())),
143 }
144 };
145
146 let (fwd_i, rev_i) = (start.line(), end.line());
149 if let Some(str) = self.get_contiguous(start..end) {
150 let lines = [str.lines(), "".lines()];
151 Lines::new(lines, None, fwd_i, rev_i)
152 } else if end.byte() > start.byte()
155 && self.buf[self.buf.gap() - 1] != b'\n'
156 && self.buf[self.buf.gap()] != b'\n'
157 {
158 let [str_0, str_1] = self.strs(start..end).to_array();
159 let lines = [str_0.lines(), str_1.lines()];
160 Lines::new(lines, None, fwd_i, rev_i)
161 } else {
164 let [str0, str1] = self.strs(start..end).to_array();
165
166 let (before, split0) = match str0.rsplit_once('\n') {
167 Some((before, split)) => (before, split),
168 None => ("", str0),
169 };
170 let (after, split1) = match str1.split_once('\n') {
171 Some((after, split)) => (after, split),
172 None => ("", str1),
173 };
174
175 let lines = [before.lines(), after.lines()];
176 let split_line = Some(split0.to_string() + split1);
177 Lines::new(lines, split_line, fwd_i, rev_i)
178 }
179 }
180
181 fn strs_in_range_inner(&self, range: impl RangeBounds<usize>) -> [&str; 2] {
183 let (s0, s1) = self.buf.as_slices();
184 let (start, end) = crate::get_ends(range, self.buf.len());
185 let (start, end) = (start, end);
186 assert!(
188 [start, end]
189 .into_iter()
190 .filter_map(|b| self.buf.get(b))
191 .all(|b| utf8_char_width(*b) > 0),
192 );
193
194 unsafe {
195 let r0 = start.min(s0.len())..end.min(s0.len());
196 let r1 = start.saturating_sub(s0.len()).min(s1.len())
197 ..end.saturating_sub(s0.len()).min(s1.len());
198
199 [from_utf8_unchecked(&s0[r0]), from_utf8_unchecked(&s1[r1])]
200 }
201 }
202
203 #[inline(always)]
214 pub fn point_at(&self, b: usize) -> Point {
215 assert!(
216 b <= self.len().byte(),
217 "byte out of bounds: the len is {}, but the byte is {b}",
218 self.len().byte()
219 );
220 let [c_b, c_c, mut c_l] = self.records.closest_to(b);
221
222 let found = if b >= c_b {
223 let [s0, s1] = self.strs_in_range_inner(c_b..);
224
225 s0.char_indices()
226 .chain(s1.char_indices().map(|(b, char)| (b + s0.len(), char)))
227 .enumerate()
228 .map(|(i, (this_b, char))| {
229 c_l += (char == '\n') as usize;
230 (c_b + this_b, c_c + i, c_l - (char == '\n') as usize)
231 })
232 .take_while(|&(rhs, ..)| b >= rhs)
233 .last()
234 } else {
235 let mut c_len = 0;
236 self.strs_in_range_inner(..c_b)
237 .into_iter()
238 .flat_map(str::chars)
239 .rev()
240 .enumerate()
241 .map(|(i, char)| {
242 c_l -= (char == '\n') as usize;
243 c_len += char.len_utf8();
244 (c_b - c_len, c_c - (i + 1), c_l)
245 })
246 .take_while(|&(rhs, ..)| b <= rhs)
247 .last()
248 };
249
250 found
251 .map(|(b, c, l)| Point::from_raw(b, c, l))
252 .unwrap_or(self.len())
253 }
254
255 #[inline(always)]
262 pub fn point_at_char(&self, c: usize) -> Point {
263 assert!(
264 c <= self.len().char(),
265 "char out of bounds: the len is {}, but the char is {c}",
266 self.len().char()
267 );
268 let [c_b, c_c, mut c_l] = self.records.closest_to_by_key(c, |[_, c, _]| *c);
269
270 let found = if c >= c_c {
271 let [s0, s1] = self.strs_in_range_inner(c_b..);
272
273 s0.char_indices()
274 .chain(s1.char_indices().map(|(b, char)| (b + s0.len(), char)))
275 .enumerate()
276 .map(|(i, (this_b, char))| {
277 c_l += (char == '\n') as usize;
278 (c_b + this_b, c_c + i, c_l - (char == '\n') as usize)
279 })
280 .take_while(|&(_, rhs, _)| c >= rhs)
281 .last()
282 } else {
283 let mut c_len = 0;
284 self.strs_in_range_inner(..)
285 .into_iter()
286 .flat_map(str::chars)
287 .rev()
288 .enumerate()
289 .map(|(i, char)| {
290 c_l -= (char == '\n') as usize;
291 c_len += char.len_utf8();
292 (c_b - c_len, c_c - (i + 1), c_l)
293 })
294 .take_while(|&(_, rhs, _)| c <= rhs)
295 .last()
296 };
297
298 found
299 .map(|(b, c, l)| Point::from_raw(b, c, l))
300 .unwrap_or(self.len())
301 }
302
303 #[inline(always)]
313 pub fn point_at_line(&self, l: usize) -> Point {
314 assert!(
315 l <= self.len().line(),
316 "line out of bounds: the len is {}, but the line is {l}",
317 self.len().line()
318 );
319 let (c_b, c_c, mut c_l) = {
320 let [mut b, mut c, l] = self.records.closest_to_by_key(l, |[.., l]| *l);
321 self.strs_in_range_inner(..b)
322 .into_iter()
323 .flat_map(str::chars)
324 .rev()
325 .take_while(|c| *c != '\n')
326 .for_each(|char| {
327 b -= char.len_utf8();
328 c -= 1;
329 });
330 (b, c, l)
331 };
332
333 let found = if l >= c_l {
334 let [s0, s1] = self.strs_in_range_inner(c_b..);
335
336 s0.char_indices()
337 .chain(s1.char_indices().map(|(b, char)| (b + s0.len(), char)))
338 .enumerate()
339 .map(|(i, (this_b, char))| {
340 c_l += (char == '\n') as usize;
341 (c_b + this_b, c_c + i, c_l - (char == '\n') as usize)
342 })
343 .find(|&(.., rhs)| l == rhs)
344 } else {
345 let mut c_len = 0;
346 self.strs_in_range_inner(..c_b)
347 .into_iter()
348 .flat_map(str::chars)
349 .rev()
350 .enumerate()
351 .map(|(i, char)| {
352 c_l -= (char == '\n') as usize;
353 c_len += char.len_utf8();
354 (c_b - c_len, c_c - (i + 1), c_l)
355 })
356 .take_while(|&(.., rhs)| l <= rhs)
357 .last()
358 };
359
360 found
361 .map(|(b, c, l)| Point::from_raw(b, c, l))
362 .unwrap_or(self.len())
363 }
364
365 #[inline(always)]
374 pub fn points_of_line(&self, l: usize) -> [Point; 2] {
375 assert!(
376 l <= self.len().line(),
377 "byte out of bounds: the len is {}, but the line is {l}",
378 self.len().line()
379 );
380
381 let start = self.point_at_line(l);
382 let end = self
383 .chars_fwd(start)
384 .find_map(|(p, _)| (p.line() > start.line()).then_some(p))
385 .unwrap_or(start);
386 [start, end]
387 }
388
389 pub fn last_point(&self) -> Option<Point> {
398 self.strs(..)
399 .chars()
400 .next_back()
401 .map(|char| self.len().rev(char))
402 }
403
404 pub fn chars_fwd(&self, p: Point) -> impl Iterator<Item = (Point, char)> + '_ {
410 self.strs_in_range_inner(p.byte()..)
411 .into_iter()
412 .flat_map(str::chars)
413 .scan(p, |p, char| {
414 let old_p = *p;
415 *p = p.fwd(char);
416 Some((old_p, char))
417 })
418 }
419
420 pub fn chars_rev(&self, p: Point) -> impl Iterator<Item = (Point, char)> + '_ {
426 self.strs_in_range_inner(..p.byte())
427 .into_iter()
428 .flat_map(str::chars)
429 .rev()
430 .scan(p, |p, char| {
431 *p = p.rev(char);
432 Some((*p, char))
433 })
434 }
435
436 pub(super) fn apply_change(&mut self, change: super::Change<&str>) {
442 let edit = change.added_text();
443 let start = change.start();
444
445 let new_len = {
446 let lines = edit.bytes().filter(|b| *b == b'\n').count();
447 [edit.len(), edit.chars().count(), lines]
448 };
449
450 let old_len = unsafe {
451 let range = start.byte()..change.taken_end().byte();
452 let str = String::from_utf8_unchecked(
453 self.buf
454 .splice(range, edit.as_bytes().iter().cloned())
455 .collect(),
456 );
457
458 let lines = str.bytes().filter(|b| *b == b'\n').count();
459 [str.len(), str.chars().count(), lines]
460 };
461
462 let start_rec = [start.byte(), start.char(), start.line()];
463 self.records.transform(start_rec, old_len, new_len);
464 self.records.insert(start_rec);
465 }
466
467 pub(super) fn extend(&mut self, other: Self) {
469 self.buf.extend(other.buf);
470 self.records
471 .transform(self.records.max(), [0, 0, 0], other.records.max())
472 }
473
474 pub(super) fn add_record(&mut self, [b, c, l]: [usize; 3]) {
476 self.records.insert([b, c, l]);
477 }
478
479 pub fn contiguous(&mut self, range: impl TextRange) -> &str {
493 self.make_contiguous(range.clone());
494 self.get_contiguous(range).unwrap()
495 }
496
497 pub fn make_contiguous(&mut self, range: impl TextRange) {
502 let range = range.to_range(self.len().byte());
503 let gap = self.buf.gap();
504
505 if range.end <= gap || range.start >= gap {
506 return;
507 }
508
509 if gap.abs_diff(range.start) < gap.abs_diff(range.end) {
510 self.buf.set_gap(range.start);
511 } else {
512 self.buf.set_gap(range.end);
513 }
514 }
515
516 pub fn get_contiguous(&self, range: impl TextRange) -> Option<&str> {
528 let range = range.to_range(self.len().byte());
529 let [s0, s1] = self.strs(..).to_array();
530
531 if range.end <= self.buf.gap() {
532 s0.get(range)
533 } else {
534 let gap = self.buf.gap();
535 s1.get(range.start - gap..range.end - gap)
536 }
537 }
538}
539
540pub struct Lines<'a> {
548 lines: [std::str::Lines<'a>; 2],
549 split_line: Option<String>,
550 fwd_i: usize,
551 rev_i: usize,
552 split_line_used: bool,
553}
554
555impl<'a> Lines<'a> {
556 fn new(
557 lines: [std::str::Lines<'a>; 2],
558 split_line: Option<String>,
559 fwd_i: usize,
560 rev_i: usize,
561 ) -> Self {
562 Self {
563 lines,
564 split_line,
565 fwd_i,
566 rev_i,
567 split_line_used: false,
568 }
569 }
570}
571
572impl<'a, 'text> Lending<'a> for Lines<'text> {
573 type Lend = (usize, &'a str);
574}
575
576impl<'a> Lender for Lines<'a> {
577 fn next(&mut self) -> Option<lender::Lend<'_, Self>> {
578 self.lines[0]
579 .next()
580 .or_else(|| {
581 if self.split_line_used {
582 None
583 } else {
584 self.split_line_used = true;
585 self.split_line.as_deref()
586 }
587 })
588 .or_else(|| self.lines[1].next())
589 .map(|line| {
590 self.fwd_i += 1;
591 (self.fwd_i - 1, line)
592 })
593 }
594
595 fn size_hint(&self) -> (usize, Option<usize>) {
596 (self.rev_i - self.fwd_i, Some(self.rev_i - self.fwd_i))
597 }
598}
599
600impl<'a> DoubleEndedLender for Lines<'a> {
601 fn next_back(&mut self) -> Option<lender::Lend<'_, Self>> {
602 self.lines[1]
603 .next_back()
604 .or_else(|| {
605 if self.split_line_used {
606 None
607 } else {
608 self.split_line_used = true;
609 self.split_line.as_deref()
610 }
611 })
612 .or_else(|| self.lines[0].next_back())
613 .map(|line| {
614 self.rev_i -= 1;
615 (self.rev_i, line)
616 })
617 }
618}
619
620impl<'a> ExactSizeLender for Lines<'a> {}
621
622#[derive(Clone)]
626pub struct Buffers<'a>([std::slice::Iter<'a, u8>; 2]);
627
628impl<'a> Buffers<'a> {
629 pub fn to_array(&self) -> [&'a [u8]; 2] {
631 self.0.clone().map(|iter| iter.as_slice())
632 }
633}
634
635impl<'a> Iterator for Buffers<'a> {
636 type Item = u8;
637
638 fn next(&mut self) -> Option<Self::Item> {
639 self.0[0].next().or_else(|| self.0[1].next()).copied()
640 }
641
642 fn size_hint(&self) -> (usize, Option<usize>) {
643 let (l0, u0) = self.0[0].size_hint();
644 let (l1, u1) = self.0[1].size_hint();
645 (l0 + l1, Some(u0.unwrap() + u1.unwrap()))
646 }
647}
648
649impl<'a> ExactSizeIterator for Buffers<'a> {}
650
651impl<'a> DoubleEndedIterator for Buffers<'a> {
652 fn next_back(&mut self) -> Option<Self::Item> {
653 self.0[1]
654 .next_back()
655 .or_else(|| self.0[0].next_back())
656 .copied()
657 }
658}
659
660#[derive(Clone)]
665pub struct Strs<'a>(std::array::IntoIter<&'a str, 2>);
666
667impl<'a> Strs<'a> {
668 pub fn to_array(&self) -> [&'a str; 2] {
670 let strs = self.0.as_slice();
671 [
672 strs.first().copied().unwrap_or(""),
673 strs.last().copied().unwrap_or(""),
674 ]
675 }
676
677 pub fn chars(self) -> impl DoubleEndedIterator<Item = char> + 'a {
681 let [s0, s1] = self.to_array();
682 s0.chars().chain(s1.chars())
683 }
684}
685
686impl<'a> Iterator for Strs<'a> {
687 type Item = &'a str;
688
689 fn next(&mut self) -> Option<Self::Item> {
690 self.0.next()
691 }
692
693 fn size_hint(&self) -> (usize, Option<usize>) {
694 self.0.size_hint()
695 }
696}
697
698impl ExactSizeIterator for Strs<'_> {}
699
700impl DoubleEndedIterator for Strs<'_> {
701 fn next_back(&mut self) -> Option<Self::Item> {
702 self.0.next_back()
703 }
704}
705
706impl FusedIterator for Strs<'_> {}
707
708impl std::fmt::Display for Strs<'_> {
709 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
710 let [s0, s1] = self.to_array();
711 write!(f, "{s0}{s1}")
712 }
713}
714
715impl std::fmt::Debug for Bytes {
716 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
717 f.debug_struct("Bytes")
718 .field("buf", &self.strs(..).to_array())
719 .field("records", &self.records)
720 .finish()
721 }
722}
723
724impl PartialEq for Bytes {
725 fn eq(&self, other: &Self) -> bool {
726 self.buf.as_slices() == other.buf.as_slices()
727 }
728}
729
730impl PartialEq<&str> for Bytes {
731 fn eq(&self, other: &&str) -> bool {
732 let [s0, s1] = self.strs(..).to_array();
733 other.len() == s0.len() + s1.len() && &other[..s0.len()] == s0 && &other[s0.len()..] == s1
734 }
735}
736
737impl PartialEq<String> for Bytes {
738 fn eq(&self, other: &String) -> bool {
739 let [s0, s1] = self.strs(..).to_array();
740 other.len() == s0.len() + s1.len() && &other[..s0.len()] == s0 && &other[s0.len()..] == s1
741 }
742}