1use super::metrics::{ByteMetric, LineMetric, RawLineMetric};
2use super::rope::RopeChunk;
3use super::{Rope, RopeSlice};
4use crate::tree::{Leaves, Units};
5
6#[derive(Clone)]
11pub struct Chunks<'a> {
12 leaves: Leaves<'a, { Rope::arity() }, RopeChunk>,
13 forward_extra_right: Option<&'a str>,
14 backward_extra_left: Option<&'a str>,
15}
16
17impl<'a> From<&'a Rope> for Chunks<'a> {
18 #[inline]
19 fn from(rope: &'a Rope) -> Self {
20 let mut leaves = rope.tree.leaves();
21 if rope.is_empty() {
22 let _ = leaves.next();
23 }
24 Self { leaves, forward_extra_right: None, backward_extra_left: None }
25 }
26}
27
28impl<'a> From<&RopeSlice<'a>> for Chunks<'a> {
29 #[inline]
30 fn from(slice: &RopeSlice<'a>) -> Self {
31 let mut leaves = slice.tree_slice.leaves();
32 if slice.is_empty() {
33 let _ = leaves.next();
34 }
35 Self { leaves, forward_extra_right: None, backward_extra_left: None }
36 }
37}
38
39impl<'a> Iterator for Chunks<'a> {
40 type Item = &'a str;
41
42 #[inline]
43 fn next(&mut self) -> Option<Self::Item> {
44 if let Some(extra) = self.forward_extra_right.take() {
45 Some(extra)
46 } else {
47 let Some(chunk) = self.leaves.next() else {
48 return self.backward_extra_left.take();
49 };
50
51 if chunk.left_chunk().is_empty() {
52 #[cfg(feature = "small_chunks")]
53 if chunk.right_chunk().is_empty() {
54 return self.next();
55 }
56
57 debug_assert!(!chunk.right_chunk().is_empty());
58
59 Some(chunk.right_chunk())
60 } else {
61 if !chunk.right_chunk().is_empty() {
62 self.forward_extra_right = Some(chunk.right_chunk());
63 }
64 Some(chunk.left_chunk())
65 }
66 }
67 }
68
69 #[inline]
70 fn size_hint(&self) -> (usize, Option<usize>) {
71 let exact = self.leaves.len();
72 (exact, Some(exact * 2))
73 }
74}
75
76impl DoubleEndedIterator for Chunks<'_> {
77 #[inline]
78 fn next_back(&mut self) -> Option<Self::Item> {
79 if let Some(extra) = self.backward_extra_left.take() {
80 Some(extra)
81 } else {
82 let Some(chunk) = self.leaves.next_back() else {
83 return self.forward_extra_right.take();
84 };
85
86 if chunk.right_chunk().is_empty() {
87 #[cfg(feature = "small_chunks")]
88 if chunk.left_chunk().is_empty() {
89 return self.next_back();
90 }
91
92 debug_assert!(!chunk.left_chunk().is_empty());
93
94 Some(chunk.left_chunk())
95 } else {
96 if !chunk.left_chunk().is_empty() {
97 self.backward_extra_left = Some(chunk.left_chunk());
98 }
99 Some(chunk.right_chunk())
100 }
101 }
102 }
103}
104
105impl core::iter::FusedIterator for Chunks<'_> {}
106
107#[derive(Clone)]
112pub struct Bytes<'a> {
113 chunks: Chunks<'a>,
114
115 forward_chunk: &'a [u8],
117
118 forward_byte_idx: usize,
120
121 backward_chunk: &'a [u8],
123
124 backward_byte_idx: usize,
126
127 bytes_yielded: usize,
129
130 bytes_total: usize,
132}
133
134impl<'a> From<&'a Rope> for Bytes<'a> {
135 #[inline]
136 fn from(rope: &'a Rope) -> Self {
137 Self {
138 chunks: rope.chunks(),
139 forward_chunk: &[],
140 forward_byte_idx: 0,
141 backward_chunk: &[],
142 backward_byte_idx: 0,
143 bytes_yielded: 0,
144 bytes_total: rope.byte_len(),
145 }
146 }
147}
148
149impl<'a> From<&RopeSlice<'a>> for Bytes<'a> {
150 #[inline]
151 fn from(slice: &RopeSlice<'a>) -> Self {
152 Self {
153 chunks: slice.chunks(),
154 forward_chunk: &[],
155 forward_byte_idx: 0,
156 backward_chunk: &[],
157 backward_byte_idx: 0,
158 bytes_yielded: 0,
159 bytes_total: slice.byte_len(),
160 }
161 }
162}
163
164impl Iterator for Bytes<'_> {
165 type Item = u8;
166
167 #[inline]
168 fn next(&mut self) -> Option<Self::Item> {
169 if self.forward_byte_idx == self.forward_chunk.len() {
170 if let Some(chunk) = self.chunks.next() {
171 self.forward_chunk = chunk.as_bytes();
172 self.forward_byte_idx = 0;
173 } else if self.backward_byte_idx == 0 {
174 return None;
175 } else {
176 let byte = self.backward_chunk[0];
177 self.backward_chunk = &self.backward_chunk[1..];
178 self.backward_byte_idx -= 1;
179 self.bytes_yielded += 1;
180 return Some(byte);
181 }
182 }
183
184 let byte = self.forward_chunk[self.forward_byte_idx];
185 self.forward_byte_idx += 1;
186 self.bytes_yielded += 1;
187 Some(byte)
188 }
189
190 #[inline]
191 fn size_hint(&self) -> (usize, Option<usize>) {
192 let exact = self.len();
193 (exact, Some(exact))
194 }
195}
196
197impl DoubleEndedIterator for Bytes<'_> {
198 #[inline]
199 fn next_back(&mut self) -> Option<Self::Item> {
200 if self.backward_byte_idx == 0 {
201 if let Some(chunk) = self.chunks.next_back() {
202 self.backward_chunk = chunk.as_bytes();
203 self.backward_byte_idx = chunk.len();
204 } else if self.forward_byte_idx == self.forward_chunk.len() {
205 return None;
206 } else {
207 let byte_idx = self.forward_chunk.len() - 1;
208 let byte = self.forward_chunk[byte_idx];
209 self.forward_chunk = &self.forward_chunk[..byte_idx];
210 self.bytes_yielded += 1;
211 return Some(byte);
212 }
213 }
214
215 self.backward_byte_idx -= 1;
216 let byte = self.backward_chunk[self.backward_byte_idx];
217 self.bytes_yielded += 1;
218 Some(byte)
219 }
220}
221
222impl ExactSizeIterator for Bytes<'_> {
223 #[inline]
224 fn len(&self) -> usize {
225 self.bytes_total - self.bytes_yielded
226 }
227}
228
229impl core::iter::FusedIterator for Bytes<'_> {}
230
231#[derive(Clone)]
237pub struct Chars<'a> {
238 chunks: Chunks<'a>,
239
240 forward_chunk: &'a str,
242
243 forward_byte_idx: usize,
246
247 backward_chunk: &'a str,
249
250 backward_byte_idx: usize,
252}
253
254impl<'a> From<&'a Rope> for Chars<'a> {
255 #[inline]
256 fn from(rope: &'a Rope) -> Self {
257 Self {
258 chunks: rope.chunks(),
259 forward_chunk: "",
260 forward_byte_idx: 0,
261 backward_chunk: "",
262 backward_byte_idx: 0,
263 }
264 }
265}
266
267impl<'a> From<&RopeSlice<'a>> for Chars<'a> {
268 #[inline]
269 fn from(slice: &RopeSlice<'a>) -> Self {
270 Self {
271 chunks: slice.chunks(),
272 forward_chunk: "",
273 forward_byte_idx: 0,
274 backward_chunk: "",
275 backward_byte_idx: 0,
276 }
277 }
278}
279
280impl Iterator for Chars<'_> {
281 type Item = char;
282
283 #[inline]
284 fn next(&mut self) -> Option<Self::Item> {
285 if self.forward_byte_idx == self.forward_chunk.len() {
286 if let Some(chunk) = self.chunks.next() {
287 self.forward_chunk = chunk;
288 self.forward_byte_idx = 0;
289 } else if self.backward_byte_idx == 0 {
290 return None;
291 } else {
292 let ch = unsafe {
293 self.backward_chunk
294 .chars()
295 .next()
296 .unwrap_unchecked()
299 };
300
301 let len = ch.len_utf8();
302 self.backward_chunk = &self.backward_chunk[len..];
303 self.backward_byte_idx -= len;
304 return Some(ch);
305 }
306 }
307
308 let ch = unsafe {
309 self.forward_chunk[self.forward_byte_idx..]
310 .chars()
311 .next()
312 .unwrap_unchecked()
316 };
317
318 self.forward_byte_idx += ch.len_utf8();
319
320 Some(ch)
321 }
322}
323
324impl DoubleEndedIterator for Chars<'_> {
325 #[inline]
326 fn next_back(&mut self) -> Option<Self::Item> {
327 if self.backward_byte_idx == 0 {
328 if let Some(chunk) = self.chunks.next_back() {
329 self.backward_chunk = chunk;
330 self.backward_byte_idx = self.backward_chunk.len();
331 } else if self.forward_byte_idx == self.forward_chunk.len() {
332 return None;
333 } else {
334 let ch = unsafe {
335 self.forward_chunk
336 .chars()
337 .next_back()
338 .unwrap_unchecked()
342 };
343
344 self.forward_chunk = &self.forward_chunk
345 [..self.forward_chunk.len() - ch.len_utf8()];
346
347 return Some(ch);
348 }
349 }
350
351 let ch = unsafe {
352 self.backward_chunk[..self.backward_byte_idx]
353 .chars()
354 .next_back()
355 .unwrap_unchecked()
358 };
359
360 self.backward_byte_idx -= ch.len_utf8();
361
362 Some(ch)
363 }
364}
365
366impl core::iter::FusedIterator for Chars<'_> {}
367
368#[derive(Clone)]
375pub struct RawLines<'a> {
376 units: Units<'a, { Rope::arity() }, RopeChunk, RawLineMetric>,
377
378 lines_yielded: usize,
380
381 lines_total: usize,
383}
384
385impl<'a> From<&'a Rope> for RawLines<'a> {
386 #[inline]
387 fn from(rope: &'a Rope) -> Self {
388 Self {
389 units: rope.tree.units::<RawLineMetric>(),
390 lines_yielded: 0,
391 lines_total: rope.line_len(),
392 }
393 }
394}
395
396impl<'a> From<&RopeSlice<'a>> for RawLines<'a> {
397 #[inline]
398 fn from(slice: &RopeSlice<'a>) -> Self {
399 Self {
400 units: slice.tree_slice.units::<RawLineMetric>(),
401 lines_yielded: 0,
402 lines_total: slice.line_len(),
403 }
404 }
405}
406
407impl<'a> Iterator for RawLines<'a> {
408 type Item = RopeSlice<'a>;
409
410 #[inline]
411 fn next(&mut self) -> Option<Self::Item> {
412 let (tree_slice, _) = self.units.next()?;
413 self.lines_yielded += 1;
414 Some(RopeSlice::from(tree_slice))
415 }
416
417 #[inline]
418 fn size_hint(&self) -> (usize, Option<usize>) {
419 let exact = self.len();
420 (exact, Some(exact))
421 }
422}
423
424impl DoubleEndedIterator for RawLines<'_> {
425 #[inline]
426 fn next_back(&mut self) -> Option<Self::Item> {
427 let (tree_slice, _) = self.units.next_back()?;
428 self.lines_yielded += 1;
429 Some(RopeSlice::from(tree_slice))
430 }
431}
432
433impl ExactSizeIterator for RawLines<'_> {
434 #[inline]
435 fn len(&self) -> usize {
436 self.lines_total - self.lines_yielded
437 }
438}
439
440impl core::iter::FusedIterator for RawLines<'_> {}
441
442#[derive(Clone)]
448pub struct Lines<'a> {
449 units: Units<'a, { Rope::arity() }, RopeChunk, LineMetric>,
450
451 lines_yielded: usize,
453
454 lines_total: usize,
456}
457
458impl<'a> From<&'a Rope> for Lines<'a> {
459 #[inline]
460 fn from(rope: &'a Rope) -> Self {
461 Self {
462 units: rope.tree.units::<LineMetric>(),
463 lines_yielded: 0,
464 lines_total: rope.line_len(),
465 }
466 }
467}
468
469impl<'a> From<&RopeSlice<'a>> for Lines<'a> {
470 #[inline]
471 fn from(slice: &RopeSlice<'a>) -> Self {
472 Self {
473 units: slice.tree_slice.units::<LineMetric>(),
474 lines_yielded: 0,
475 lines_total: slice.line_len(),
476 }
477 }
478}
479
480impl<'a> Iterator for Lines<'a> {
481 type Item = RopeSlice<'a>;
482
483 #[inline]
484 fn next(&mut self) -> Option<Self::Item> {
485 let (tree_slice, ByteMetric(advance)) = self.units.next()?;
486 self.lines_yielded += 1;
487
488 let mut slice = RopeSlice { tree_slice, has_trailing_newline: false };
489
490 if slice.tree_slice.end_slice().last_chunk().ends_with('\r')
495 && advance - slice.byte_len() == 1
496 {
497 slice.truncate_last_char();
498 }
499
500 Some(slice)
501 }
502
503 #[inline]
504 fn size_hint(&self) -> (usize, Option<usize>) {
505 let exact = self.len();
506 (exact, Some(exact))
507 }
508}
509
510impl DoubleEndedIterator for Lines<'_> {
511 #[inline]
512 fn next_back(&mut self) -> Option<Self::Item> {
513 let (tree_slice, ByteMetric(advance)) = self.units.next_back()?;
514 self.lines_yielded += 1;
515
516 let mut slice = RopeSlice { tree_slice, has_trailing_newline: false };
517
518 if slice.tree_slice.end_slice().last_chunk().ends_with('\r')
520 && advance - slice.byte_len() == 1
521 {
522 slice.truncate_last_char();
523 }
524
525 Some(slice)
526 }
527}
528
529impl ExactSizeIterator for Lines<'_> {
530 #[inline]
531 fn len(&self) -> usize {
532 self.lines_total - self.lines_yielded
533 }
534}
535
536impl core::iter::FusedIterator for Lines<'_> {}
537
538#[cfg_attr(docsrs, doc(cfg(feature = "graphemes")))]
539#[cfg(feature = "graphemes")]
540pub use graphemes::Graphemes;
541
542#[cfg(feature = "graphemes")]
543mod graphemes {
544 use alloc::borrow::Cow;
545
546 use unicode_segmentation::{GraphemeCursor, GraphemeIncomplete};
547
548 use super::*;
549
550 #[derive(Clone)]
557 pub struct Graphemes<'a> {
558 chunks: Chunks<'a>,
559
560 slice: RopeSlice<'a>,
563
564 forward_cursor: GraphemeCursor,
566
567 forward_chunk: &'a str,
569
570 forward_offset: usize,
575
576 backward_cursor: GraphemeCursor,
578
579 backward_chunk: &'a str,
581
582 backward_offset: usize,
587 }
588
589 impl<'a> From<&'a Rope> for Graphemes<'a> {
590 #[inline]
591 fn from(rope: &'a Rope) -> Self {
592 let len = rope.byte_len();
593
594 Self {
595 chunks: rope.chunks(),
596 slice: rope.byte_slice(..),
597 forward_cursor: GraphemeCursor::new(0, len, true),
598 forward_offset: 0,
599 forward_chunk: "",
600 backward_cursor: GraphemeCursor::new(len, len, true),
601 backward_chunk: "",
602 backward_offset: len,
603 }
604 }
605 }
606
607 impl<'a> From<&RopeSlice<'a>> for Graphemes<'a> {
608 #[inline]
609 fn from(slice: &RopeSlice<'a>) -> Self {
610 let len = slice.byte_len();
611
612 Self {
613 chunks: slice.chunks(),
614 slice: *slice,
615 forward_cursor: GraphemeCursor::new(0, len, true),
616 forward_offset: 0,
617 forward_chunk: "",
618 backward_cursor: GraphemeCursor::new(len, len, true),
619 backward_chunk: "",
620 backward_offset: len,
621 }
622 }
623 }
624
625 impl<'a> Iterator for Graphemes<'a> {
626 type Item = Cow<'a, str>;
627
628 #[inline]
629 fn next(&mut self) -> Option<Self::Item> {
630 debug_assert_eq!(
631 self.forward_offset,
632 self.forward_cursor.cur_cursor()
633 );
634
635 let mut using_backward_chunk = false;
636
637 if self.forward_chunk.is_empty() {
638 self.forward_chunk = if let Some(next) = self.chunks.next() {
639 next
640 } else if !self.backward_chunk.is_empty() {
641 debug_assert!(
642 self.backward_cursor.cur_cursor()
643 > self.forward_cursor.cur_cursor()
644 );
645 using_backward_chunk = true;
646 self.backward_chunk
647 } else {
648 return None;
649 }
650 }
651
652 let mut grapheme = Cow::Borrowed("");
653
654 loop {
655 match self
656 .forward_cursor
657 .next_boundary(self.forward_chunk, self.forward_offset)
660 {
661 Ok(Some(byte_end)) => {
662 if byte_end == self.forward_offset {
663 debug_assert!(!grapheme.is_empty());
664 return Some(grapheme);
665 }
666
667 debug_assert!(byte_end > self.forward_offset);
668
669 let grapheme_end = &self.forward_chunk
670 [..byte_end - self.forward_offset];
671
672 match &mut grapheme {
673 Cow::Borrowed(gr) if gr.is_empty() => {
674 *gr = grapheme_end;
675 },
676
677 Cow::Borrowed(gr) => {
678 let mut gr = gr.to_owned();
679 gr.push_str(grapheme_end);
680 grapheme = Cow::Owned(gr);
681 },
682
683 Cow::Owned(gr) => {
684 gr.push_str(grapheme_end);
685 },
686 }
687
688 self.forward_offset += grapheme_end.len();
689
690 self.forward_chunk =
691 &self.forward_chunk[grapheme_end.len()..];
692
693 if using_backward_chunk {
694 self.backward_chunk = self.forward_chunk;
695 }
696
697 return Some(grapheme);
698 },
699
700 Ok(None) => return None,
701
702 Err(GraphemeIncomplete::NextChunk) => {
703 match &mut grapheme {
704 Cow::Borrowed(gr) if gr.is_empty() => {
705 *gr = self.forward_chunk;
706 },
707
708 Cow::Borrowed(gr) => {
709 let mut gr = gr.to_owned();
710 gr.push_str(self.forward_chunk);
711 grapheme = Cow::Owned(gr);
712 },
713
714 Cow::Owned(gr) => gr.push_str(self.forward_chunk),
715 }
716
717 self.forward_offset += self.forward_chunk.len();
718
719 self.forward_chunk =
720 if let Some(next) = self.chunks.next() {
721 next
722 } else if !self.backward_chunk.is_empty() {
723 debug_assert!(
724 self.backward_cursor.cur_cursor()
725 > self.forward_cursor.cur_cursor()
726 );
727 using_backward_chunk = true;
728 self.backward_chunk
729 } else {
730 return None;
731 }
732 },
733
734 Err(GraphemeIncomplete::PreContext(byte_idx)) => {
737 let slice = self.slice.byte_slice(..byte_idx);
738 let chunk = slice.chunks().next_back().unwrap();
739 self.forward_cursor
740 .provide_context(chunk, byte_idx - chunk.len());
741 },
742
743 Err(_) => {
744 unreachable!();
745 },
746 }
747 }
748 }
749
750 #[inline]
751 fn size_hint(&self) -> (usize, Option<usize>) {
752 let hi = self.backward_offset - self.forward_offset;
753 let lo = (hi != 0) as usize;
754 (lo, Some(hi))
755 }
756 }
757
758 impl DoubleEndedIterator for Graphemes<'_> {
759 #[inline]
760 fn next_back(&mut self) -> Option<Self::Item> {
761 debug_assert_eq!(
762 self.backward_offset,
763 self.backward_cursor.cur_cursor()
764 );
765
766 let mut using_forward_chunk = false;
767
768 if self.backward_chunk.is_empty() {
769 self.backward_chunk =
770 if let Some(prev) = self.chunks.next_back() {
771 prev
772 } else if !self.forward_chunk.is_empty() {
773 debug_assert!(
774 self.backward_cursor.cur_cursor()
775 > self.forward_cursor.cur_cursor()
776 );
777 using_forward_chunk = true;
778 self.forward_chunk
779 } else {
780 return None;
781 }
782 }
783
784 let mut grapheme = Cow::Borrowed("");
785
786 loop {
787 match self
788 .backward_cursor
789 .prev_boundary(
792 self.backward_chunk,
793 self.backward_cursor.cur_cursor()
794 - self.backward_chunk.len(),
795 ) {
796 Ok(Some(byte_start)) => {
797 if byte_start == self.backward_offset {
798 debug_assert!(!grapheme.is_empty());
799 return Some(grapheme);
800 }
801
802 debug_assert!(byte_start < self.backward_offset);
803
804 let grapheme_start = {
805 let start_len = self.backward_offset - byte_start;
806 let chunk_len = self.backward_chunk.len();
807 &self.backward_chunk[(chunk_len - start_len)..]
808 };
809
810 match &mut grapheme {
811 Cow::Borrowed(gr) if gr.is_empty() => {
812 *gr = grapheme_start;
813 },
814
815 Cow::Borrowed(gr) => {
816 let mut new = String::with_capacity(
817 grapheme_start.len() + gr.len(),
818 );
819 new.push_str(grapheme_start);
820 new.push_str(gr);
821 grapheme = Cow::Owned(new);
822 },
823
824 Cow::Owned(gr) => {
825 let mut new = String::with_capacity(
826 grapheme_start.len() + gr.len(),
827 );
828 new.push_str(grapheme_start);
829 new.push_str(&*gr);
830 *gr = new;
831 },
832 }
833
834 self.backward_offset -= grapheme_start.len();
835
836 self.backward_chunk =
837 &self.backward_chunk[..self.backward_chunk.len()
838 - grapheme_start.len()];
839
840 if using_forward_chunk {
841 self.forward_chunk = self.backward_chunk;
842 }
843
844 return Some(grapheme);
845 },
846
847 Ok(None) => return None,
848
849 Err(GraphemeIncomplete::PrevChunk) => {
850 match &mut grapheme {
851 Cow::Borrowed(gr) if gr.is_empty() => {
852 *gr = self.backward_chunk;
853 },
854
855 Cow::Borrowed(gr) => {
856 let mut new = String::with_capacity(
857 self.backward_chunk.len() + gr.len(),
858 );
859 new.push_str(self.backward_chunk);
860 new.push_str(gr);
861 grapheme = Cow::Owned(new);
862 },
863
864 Cow::Owned(gr) => {
865 let mut new = String::with_capacity(
866 self.backward_chunk.len() + gr.len(),
867 );
868 new.push_str(self.backward_chunk);
869 new.push_str(gr);
870 *gr = new;
871 },
872 }
873
874 self.backward_offset -= self.backward_chunk.len();
875
876 self.backward_chunk =
877 if let Some(prev) = self.chunks.next_back() {
878 prev
879 } else if !self.forward_chunk.is_empty() {
880 debug_assert!(
881 self.backward_cursor.cur_cursor()
882 > self.forward_cursor.cur_cursor()
883 );
884 using_forward_chunk = true;
885 self.forward_chunk
886 } else {
887 return None;
888 }
889 },
890
891 Err(GraphemeIncomplete::PreContext(byte_idx)) => {
895 let slice = self.slice.byte_slice(..byte_idx);
896 let chunk = slice.chunks().next_back().unwrap();
897 self.backward_cursor
898 .provide_context(chunk, byte_idx - chunk.len());
899 },
900
901 Err(_) => {
902 unreachable!();
903 },
904 }
905 }
906 }
907 }
908
909 impl core::iter::FusedIterator for Graphemes<'_> {}
910}