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