crop/rope/rope_slice.rs
1use alloc::string::String;
2use core::ops::RangeBounds;
3
4use super::Rope;
5use super::iterators::{Bytes, Chars, Chunks, Lines, RawLines};
6use super::metrics::{ByteMetric, RawLineMetric};
7use super::rope::RopeChunk;
8use super::utils::{panic_messages as panic, *};
9use crate::range_bounds_to_start_end;
10use crate::tree::TreeSlice;
11
12/// An immutable slice of a [`Rope`](crate::Rope).
13#[derive(Copy, Clone)]
14pub struct RopeSlice<'a> {
15 pub(super) tree_slice: TreeSlice<'a, { Rope::arity() }, RopeChunk>,
16 pub(super) has_trailing_newline: bool,
17}
18
19impl<'a> RopeSlice<'a> {
20 #[doc(hidden)]
21 pub fn assert_invariants(&self) {
22 self.tree_slice.assert_invariants();
23
24 let first = self.tree_slice.start_slice();
25 first.assert_invariants();
26
27 let last = self.tree_slice.end_slice();
28 last.assert_invariants();
29
30 assert_eq!(self.has_trailing_newline, last.has_trailing_newline())
31 }
32
33 /// Returns the byte at `byte_index`.
34 ///
35 /// # Panics
36 ///
37 /// Panics if the byte index is out of bounds (i.e. greater than or equal
38 /// to [`byte_len()`](Self::byte_len())).
39 ///
40 /// # Examples
41 ///
42 /// ```
43 /// # use crop::Rope;
44 /// #
45 /// let r = Rope::from("bar");
46 /// let s = r.byte_slice(..);
47 ///
48 /// assert_eq!(s.byte(0), b'b');
49 /// assert_eq!(s.byte(1), b'a');
50 /// assert_eq!(s.byte(2), b'r');
51 /// ```
52 #[track_caller]
53 #[inline]
54 pub fn byte(&self, byte_index: usize) -> u8 {
55 if byte_index >= self.byte_len() {
56 panic::byte_index_out_of_bounds(byte_index, self.byte_len());
57 }
58
59 let (chunk, ByteMetric(chunk_byte_offset)) =
60 self.tree_slice.leaf_at_measure(ByteMetric(byte_index + 1));
61
62 chunk.byte(byte_index - chunk_byte_offset)
63 }
64
65 /// Returns the length of the `RopeSlice` in bytes.
66 ///
67 /// # Examples
68 ///
69 /// ```
70 /// # use crop::Rope;
71 /// #
72 /// let r = Rope::from("ƒoo");
73 ///
74 /// let s = r.byte_slice(2..2);
75 /// assert_eq!(s.byte_len(), 0);
76 ///
77 /// let s = r.byte_slice(..);
78 /// assert_eq!(s.byte_len(), 4);
79 /// ```
80 #[inline]
81 pub fn byte_len(&self) -> usize {
82 self.tree_slice.summary().bytes()
83 }
84
85 /// Returns the byte offset of the start of the given line.
86 ///
87 /// # Panics
88 ///
89 /// Panics if the line offset is out of bounds (i.e. greater than
90 /// [`line_len()`](Self::line_len())).
91 ///
92 /// # Examples
93 ///
94 /// ```
95 /// # use crop::Rope;
96 /// #
97 /// let r = Rope::from("ƒoo\nbär\r\nbaz");
98 ///
99 /// let s = r.byte_slice(..);
100 /// assert_eq!(s.byte_of_line(0), 0);
101 /// assert_eq!(s.byte_of_line(1), "ƒoo\n".len());
102 ///
103 /// let s = r.byte_slice("ƒoo\n".len()..);
104 /// assert_eq!(s.byte_of_line(1), "bär\r\n".len());
105 /// assert_eq!(s.byte_of_line(s.line_len()), s.byte_len());
106 /// ```
107 #[track_caller]
108 #[inline]
109 pub fn byte_of_line(&self, line_offset: usize) -> usize {
110 if line_offset > self.line_len() {
111 panic::line_offset_out_of_bounds(line_offset, self.line_len());
112 }
113
114 if line_offset > self.tree_slice.summary().line_breaks() {
115 return self.byte_len();
116 }
117
118 let ByteMetric(byte_offset) =
119 self.tree_slice.convert_measure(RawLineMetric(line_offset));
120
121 byte_offset
122 }
123
124 /// Returns the byte offset corresponding to the given UTF-16 code unit
125 /// offset.
126 ///
127 /// # Panics
128 ///
129 /// Panics if the UTF-16 code unit offset is out of bounds (i.e. greater
130 /// than [`utf16_len()`](Self::utf16_len())) or if it doesn't lie on a code
131 /// point boundary.
132 ///
133 /// # Examples
134 ///
135 /// ```
136 /// # use crop::Rope;
137 /// #
138 /// // The "𐐀" character is encoded using two code units in UTF-16 and
139 /// // four bytes in UTF-8.
140 /// let r = Rope::from("a𐐀b");
141 /// let s = r.byte_slice(1..);
142 /// assert_eq!(s.byte_of_utf16_code_unit(2), 4);
143 /// ```
144 #[cfg_attr(docsrs, doc(cfg(feature = "utf16-metric")))]
145 #[cfg(feature = "utf16-metric")]
146 #[track_caller]
147 #[inline]
148 pub fn byte_of_utf16_code_unit(&self, utf16_offset: usize) -> usize {
149 if utf16_offset > self.utf16_len() {
150 panic::utf16_offset_out_of_bounds(utf16_offset, self.utf16_len())
151 }
152
153 let ByteMetric(byte_offset) = self
154 .tree_slice
155 .convert_measure(super::metrics::Utf16Metric(utf16_offset));
156
157 byte_offset
158 }
159
160 /// Returns a sub-slice of this `RopeSlice` in the specified byte range,
161 /// where the start and end of the range are interpreted as offsets.
162 ///
163 /// # Panics
164 ///
165 /// Panics if the start or the end of the byte range don't lie on a code
166 /// point boundary, if the start is greater than the end or if the end is
167 /// out of bounds (i.e. greater than [`byte_len()`](Self::byte_len())).
168 ///
169 /// # Examples
170 ///
171 /// ```
172 /// # use crop::Rope;
173 /// #
174 /// let r = Rope::from("🗻∈🌏");
175 /// let s = r.byte_slice(4..);
176 ///
177 /// assert_eq!(s.byte_slice(..3), "∈");
178 /// assert_eq!(s.byte_slice(3..), "🌏");
179 /// ```
180 #[track_caller]
181 #[inline]
182 pub fn byte_slice<R>(self, byte_range: R) -> RopeSlice<'a>
183 where
184 R: RangeBounds<usize>,
185 {
186 let (start, end) =
187 range_bounds_to_start_end(byte_range, 0, self.byte_len());
188
189 if start > end {
190 panic::byte_start_after_end(start, end);
191 }
192
193 if end > self.byte_len() {
194 panic::byte_offset_out_of_bounds(end, self.byte_len());
195 }
196
197 self.tree_slice.slice(ByteMetric(start)..ByteMetric(end)).into()
198 }
199
200 /// Returns an iterator over the bytes of this `RopeSlice`.
201 ///
202 /// # Examples
203 ///
204 /// ```
205 /// # use crop::Rope;
206 /// #
207 /// let r = Rope::from("foobar");
208 /// let s = r.byte_slice(1..5);
209 ///
210 /// let mut bytes = s.bytes();
211 ///
212 /// assert_eq!(Some(b'o'), bytes.next());
213 /// assert_eq!(Some(b'o'), bytes.next());
214 /// assert_eq!(Some(b'b'), bytes.next());
215 /// assert_eq!(Some(b'a'), bytes.next());
216 /// assert_eq!(None, bytes.next());
217 /// ```
218 #[inline]
219 pub fn bytes(&self) -> Bytes<'a> {
220 Bytes::from(self)
221 }
222
223 /// Returns an iterator over the [`char`]s of this `RopeSlice`.
224 ///
225 /// # Examples
226 ///
227 /// ```
228 /// # use crop::Rope;
229 /// #
230 /// let r = Rope::from("🐻❄️");
231 /// let s = r.byte_slice(4..);
232 ///
233 /// let mut chars = s.chars();
234 ///
235 /// assert_eq!(Some('\u{200d}'), chars.next());
236 /// assert_eq!(Some('❄'), chars.next());
237 /// assert_eq!(Some('\u{fe0f}'), chars.next());
238 /// assert_eq!(None, chars.next());
239 /// ```
240 #[inline]
241 pub fn chars(&self) -> Chars<'a> {
242 Chars::from(self)
243 }
244
245 /// Returns an iterator over the chunks of this `RopeSlice`.
246 #[inline]
247 pub fn chunks(&self) -> Chunks<'a> {
248 Chunks::from(self)
249 }
250
251 /// Returns an iterator over the extended grapheme clusters of this
252 /// `RopeSlice`.
253 ///
254 /// # Examples
255 ///
256 /// ```no_run
257 /// # use crop::Rope;
258 /// #
259 /// let r = Rope::from("arg!\r\n🐻❄️");
260 /// let s = r.byte_slice(3..);
261 ///
262 /// let mut graphemes = s.graphemes();
263 ///
264 /// assert_eq!(Some("!"), graphemes.next().as_deref());
265 /// assert_eq!(Some("\r\n"), graphemes.next().as_deref());
266 /// assert_eq!(Some("🐻❄️"), graphemes.next().as_deref());
267 /// assert_eq!(None, graphemes.next());
268 /// ```
269 #[cfg_attr(docsrs, doc(cfg(feature = "graphemes")))]
270 #[cfg(feature = "graphemes")]
271 #[inline]
272 pub fn graphemes(&self) -> crate::iter::Graphemes<'a> {
273 crate::iter::Graphemes::from(self)
274 }
275
276 /// Returns `true` if the given byte offset lies on a [`char`] boundary.
277 ///
278 /// # Panics
279 ///
280 /// Panics if the byte offset is out of bounds (i.e. greater than
281 /// [`byte_len()`](Self::byte_len())).
282 ///
283 /// # Examples
284 ///
285 /// ```
286 /// # use crop::Rope;
287 /// #
288 /// let r = Rope::from("Löwe 老虎 Léopard");
289 /// let s = r.byte_slice(3..);
290 ///
291 /// assert!(s.is_char_boundary(0));
292 /// assert!(s.is_char_boundary(s.byte_len()));
293 /// assert!(s.is_char_boundary(6)); // between '老' and '虎'
294 /// assert!(!s.is_char_boundary(12)); // between the 1st and 2nd byte of 'é'
295 /// ```
296 #[track_caller]
297 #[inline]
298 pub fn is_char_boundary(&self, byte_offset: usize) -> bool {
299 if byte_offset > self.byte_len() {
300 panic::byte_offset_out_of_bounds(byte_offset, self.byte_len());
301 }
302
303 let (chunk, ByteMetric(chunk_byte_offset)) =
304 self.tree_slice.leaf_at_measure(ByteMetric(byte_offset));
305
306 chunk.is_char_boundary(byte_offset - chunk_byte_offset)
307 }
308
309 /// Returns `true` if the `RopeSlice`'s byte length is zero.
310 ///
311 /// # Examples
312 ///
313 /// ```
314 /// # use crop::Rope;
315 /// #
316 /// let r = Rope::from("");
317 /// assert!(r.byte_slice(..).is_empty());
318 ///
319 /// let r = Rope::from("foo");
320 /// assert!(!r.line_slice(..).is_empty());
321 /// ```
322 #[inline]
323 pub fn is_empty(&self) -> bool {
324 self.byte_len() == 0
325 }
326
327 /// Returns `true` if the given byte offset lies on a grapheme cluster
328 /// boundary.
329 ///
330 /// # Panics
331 ///
332 /// Panics if the byte offset is out of bounds (i.e. greater than
333 /// [`byte_len()`](Self::byte_len())).
334 ///
335 /// # Examples
336 ///
337 /// ```
338 /// # use crop::Rope;
339 /// #
340 /// let r = Rope::from("aargh!\r\n🐻❄️");
341 /// let s = r.line_slice(1..);
342 ///
343 /// assert!(s.is_grapheme_boundary(0));
344 /// assert!(s.is_grapheme_boundary(s.byte_len()));
345 /// assert!(!s.is_grapheme_boundary(4)); // between the 1st and 2nd code point of '🐻❄️'
346 /// ```
347 #[cfg_attr(docsrs, doc(cfg(feature = "graphemes")))]
348 #[cfg(feature = "graphemes")]
349 #[track_caller]
350 #[inline]
351 pub fn is_grapheme_boundary(&self, byte_offset: usize) -> bool {
352 if byte_offset > self.byte_len() {
353 panic::byte_offset_out_of_bounds(byte_offset, self.byte_len());
354 }
355
356 is_grapheme_boundary(self.chunks(), self.byte_len(), byte_offset)
357 }
358
359 /// Returns the line at `line_index`, without its line terminator.
360 ///
361 /// If you want to include the line break consider taking a
362 /// [`line_slice()`](Self::line_slice()) in the
363 /// `line_index..line_index + 1` range.
364 ///
365 /// # Panics
366 ///
367 /// Panics if the line index is out of bounds (i.e. greater than or equal
368 /// to [`line_len()`](Self::byte_len())).
369 ///
370 /// # Examples
371 ///
372 /// ```
373 /// # use crop::Rope;
374 /// #
375 /// let r = Rope::from("foo\nbar\r\nbaz");
376 /// let s = r.line_slice(..2);
377 ///
378 /// assert_eq!(s.line(0), "foo");
379 /// assert_eq!(s.line(1), "bar");
380 /// ```
381 #[track_caller]
382 #[inline]
383 pub fn line(self, line_index: usize) -> RopeSlice<'a> {
384 if line_index >= self.line_len() {
385 panic::line_offset_out_of_bounds(line_index, self.line_len());
386 }
387
388 let tree_slice = self
389 .tree_slice
390 .slice(RawLineMetric(line_index)..RawLineMetric(line_index + 1));
391
392 let mut line = Self { tree_slice, has_trailing_newline: false };
393
394 if line.tree_slice.summary().line_breaks() == 1 {
395 line.truncate_trailing_line_break();
396 }
397
398 line
399 }
400
401 /// Returns the number of lines in the `RopeSlice`.
402 ///
403 /// The final line break is optional and doesn't count as a separate empty
404 /// line.
405 ///
406 /// # Examples
407 ///
408 /// ```
409 /// # use crop::Rope;
410 /// #
411 /// let r = Rope::from("a\nb\r\n");
412 ///
413 /// let s = r.byte_slice(..);
414 /// assert_eq!(s.line_len(), 2);
415 ///
416 /// let s = r.byte_slice(..3);
417 /// assert_eq!(s.line_len(), 2);
418 ///
419 /// let s = r.byte_slice(..2);
420 /// assert_eq!(s.line_len(), 1);
421 ///
422 /// let s = r.byte_slice(..1);
423 /// assert_eq!(s.line_len(), 1);
424 ///
425 /// let s = r.byte_slice(..0);
426 /// assert_eq!(s.line_len(), 0);
427 /// ```
428 #[inline]
429 pub fn line_len(&self) -> usize {
430 self.tree_slice.summary().line_breaks() + 1
431 - (self.has_trailing_newline as usize)
432 - (self.is_empty() as usize)
433 }
434
435 /// Returns the line offset of the given byte.
436 ///
437 /// # Panics
438 ///
439 /// Panics if the byte offset is out of bounds (i.e. greater than
440 /// [`byte_len()`](Self::byte_len())).
441 ///
442 /// # Examples
443 ///
444 /// ```
445 /// # use crop::Rope;
446 /// #
447 /// let r = Rope::from("foo\nbar\r\nbaz");
448 ///
449 /// let s = r.byte_slice(..);
450 /// assert_eq!(s.line_of_byte(0), 0);
451 /// assert_eq!(s.line_of_byte(4), 1);
452 ///
453 /// let s = r.line_slice(1..);
454 /// assert_eq!(s.line_of_byte(0), 0);
455 /// assert_eq!(s.line_of_byte(4), 0); // between the '\r' and the '\n'
456 /// assert_eq!(s.line_of_byte(s.byte_len()), 1);
457 /// ```
458 #[track_caller]
459 #[inline]
460 pub fn line_of_byte(&self, byte_offset: usize) -> usize {
461 if byte_offset > self.byte_len() {
462 panic::byte_offset_out_of_bounds(byte_offset, self.byte_len());
463 }
464
465 let RawLineMetric(line_offset) =
466 self.tree_slice.convert_measure(ByteMetric(byte_offset));
467
468 line_offset
469 }
470
471 /// Returns a sub-slice of this `RopeSlice` in the specified line range,
472 /// where the start and end of the range are interpreted as offsets.
473 ///
474 /// # Panics
475 ///
476 /// Panics if the start is greater than the end or if the end is out of
477 /// bounds (i.e. greater than [`line_len()`](Self::line_len())).
478 ///
479 /// # Examples
480 ///
481 /// ```
482 /// # use crop::Rope;
483 /// #
484 /// let r = Rope::from("foo\nbar\r\nbaz\nfoobar\n");
485 /// let s = r.byte_slice(2..17);
486 ///
487 /// assert_eq!(s.line_slice(..1), "o\n");
488 /// assert_eq!(s.line_slice(1..3), "bar\r\nbaz\n");
489 /// assert_eq!(s.line_slice(3..4), "foob");
490 /// assert_eq!(s.line_slice(4..), "");
491 /// ```
492 #[track_caller]
493 #[inline]
494 pub fn line_slice<R>(self, line_range: R) -> RopeSlice<'a>
495 where
496 R: RangeBounds<usize>,
497 {
498 let (start, end) =
499 range_bounds_to_start_end(line_range, 0, self.line_len());
500
501 if start > end {
502 panic::line_start_after_end(start, end);
503 }
504
505 if end > self.line_len() {
506 panic::line_offset_out_of_bounds(end, self.line_len());
507 }
508
509 self.tree_slice.slice(RawLineMetric(start)..RawLineMetric(end)).into()
510 }
511
512 /// Returns an iterator over the lines of this `RopeSlice`, not including
513 /// the line terminators.
514 ///
515 /// The final line break is optional and doesn't cause the iterator to
516 /// return a final empty line.
517 ///
518 /// If you want to include the line breaks consider using the
519 /// [`raw_lines()`](Self::raw_lines()) method instead.
520 ///
521 /// # Examples
522 ///
523 /// ```
524 /// # use crop::Rope;
525 /// #
526 /// let r = Rope::from("foo\nbar\r\nbaz\n");
527 /// let s = r.line_slice(1..);
528 ///
529 /// let mut lines = s.lines();
530 ///
531 /// assert_eq!("bar", lines.next().unwrap());
532 /// assert_eq!("baz", lines.next().unwrap());
533 /// assert_eq!(None, lines.next());
534 /// ```
535 #[inline]
536 pub fn lines(&self) -> Lines<'a> {
537 Lines::from(self)
538 }
539
540 /// Returns an iterator over the lines of this `RopeSlice`, including the
541 /// line terminators.
542 ///
543 /// The final line break is optional and doesn't cause the iterator to
544 /// return a final empty line.
545 ///
546 /// If you don't want to include the line breaks consider using the
547 /// [`raw_lines()`](Self::raw_lines()) method instead.
548 ///
549 /// # Examples
550 ///
551 /// ```
552 /// # use crop::Rope;
553 /// #
554 /// let r = Rope::from("foo\nbar\r\nbaz\n");
555 /// let s = r.byte_slice(..r.byte_len() - 1);
556 ///
557 /// let mut raw_lines = s.raw_lines();
558 ///
559 /// assert_eq!("foo\n", raw_lines.next().unwrap());
560 /// assert_eq!("bar\r\n", raw_lines.next().unwrap());
561 /// assert_eq!("baz", raw_lines.next().unwrap());
562 /// assert_eq!(None, raw_lines.next());
563 ///
564 /// let s = r.byte_slice(..);
565 ///
566 /// let mut raw_lines = s.raw_lines();
567 ///
568 /// assert_eq!("foo\n", raw_lines.next().unwrap());
569 /// assert_eq!("bar\r\n", raw_lines.next().unwrap());
570 /// assert_eq!("baz\n", raw_lines.next().unwrap());
571 /// assert_eq!(None, raw_lines.next());
572 /// ```
573 #[inline]
574 pub fn raw_lines(&self) -> RawLines<'a> {
575 RawLines::from(self)
576 }
577
578 /// Removes the last char from the range spanned by this slice.
579 ///
580 /// # Panics
581 ///
582 /// Panics if the slice is empty or if the relative offset is not on a char
583 /// boundary.
584 #[inline]
585 pub(super) fn truncate_last_char(&mut self) {
586 debug_assert!(!self.is_empty());
587
588 let slice = &mut self.tree_slice;
589
590 // The last slice only contains one byte so we have to re-slice.
591 if slice.end_summary.bytes() == 1 {
592 *self = self.byte_slice(..self.byte_len() - 1);
593 }
594 // The last slice contains more than 2 bytes so we can just mutate
595 // in place.
596 else {
597 let last = &mut slice.end_slice;
598
599 slice.summary -= slice.end_summary;
600
601 let new_end_summary = last.truncate_last_char(slice.end_summary);
602
603 slice.end_summary = new_end_summary;
604
605 slice.summary += slice.end_summary;
606
607 if slice.leaf_count() == 1 {
608 slice.start_slice = slice.end_slice;
609 slice.start_summary = slice.end_summary;
610 }
611 }
612 }
613
614 /// Removes the trailing line break (either LF or CRLF) from the range
615 /// spanned by this slice.
616 ///
617 /// # Panics
618 ///
619 /// Panics if this slice doesn't have a trailing line break.
620 #[inline]
621 pub(super) fn truncate_trailing_line_break(&mut self) {
622 debug_assert!(
623 self.tree_slice.end_slice().last_chunk().ends_with('\n')
624 );
625
626 self.truncate_last_char();
627
628 if self.tree_slice.end_slice().last_chunk().ends_with('\r') {
629 self.truncate_last_char();
630 }
631 }
632
633 /// Returns the number of UTF-16 code units this `RopeSlice` would span if
634 /// it stores its contents as UTF-16 instead of UTF-8.
635 ///
636 /// # Examples
637 ///
638 /// ```
639 /// # use crop::Rope;
640 /// #
641 /// // The "🐸" emoji is encoded using two UTF-16 code units.
642 /// let r = Rope::from("abc🐸");
643 /// let s = r.byte_slice(2..);
644 /// assert_eq!(s.utf16_len(), 3);
645 /// ```
646 #[cfg_attr(docsrs, doc(cfg(feature = "utf16-metric")))]
647 #[cfg(feature = "utf16-metric")]
648 #[inline]
649 pub fn utf16_len(&self) -> usize {
650 self.tree_slice.summary().utf16_code_units()
651 }
652
653 /// Returns the UTF-16 code unit offset corresponding to the given byte
654 /// offset.
655 ///
656 /// # Panics
657 ///
658 /// Panics if the byte offset is out of bounds (i.e. greater than
659 /// [`byte_len()`](Self::byte_len())).
660 ///
661 /// # Examples
662 ///
663 /// ```
664 /// # use crop::Rope;
665 /// #
666 /// // The "𐐀" character is encoded using two code units in UTF-16 and
667 /// // four bytes in UTF-8.
668 /// let r = Rope::from("a𐐀b");
669 /// let s = r.byte_slice(1..);
670 /// assert_eq!(s.utf16_code_unit_of_byte(4), 2);
671 /// ```
672 #[cfg_attr(docsrs, doc(cfg(feature = "utf16-metric")))]
673 #[cfg(feature = "utf16-metric")]
674 #[track_caller]
675 #[inline]
676 pub fn utf16_code_unit_of_byte(&self, byte_offset: usize) -> usize {
677 if byte_offset > self.byte_len() {
678 panic::byte_offset_out_of_bounds(byte_offset, self.byte_len());
679 }
680
681 let super::metrics::Utf16Metric(utf16_offset) =
682 self.tree_slice.convert_measure(ByteMetric(byte_offset));
683
684 utf16_offset
685 }
686
687 /// Returns a sub-slice of this `RopeSlice` in the specified UTF-16 code
688 /// unit range, where the start and end of the range are interpreted as
689 /// offsets.
690 ///
691 /// # Panics
692 ///
693 /// Panics if the start is greater than the end or if the end is out of
694 /// bounds (i.e. greater than [`utf16_len()`](Self::utf16_len())).
695 ///
696 /// # Examples
697 ///
698 /// ```
699 /// # use crop::Rope;
700 /// #
701 /// // Both "𐐀" and "🐸" are encoded using two code units in UTF-16.
702 /// let r = Rope::from("ab𐐀de🐸");
703 /// let s = r.byte_slice(..);
704 ///
705 /// assert_eq!(s.utf16_slice(..4), "ab𐐀");
706 /// assert_eq!(s.utf16_slice(5..), "e🐸");
707 /// assert_eq!(s.utf16_slice(2..4), "𐐀");
708 /// ```
709 #[cfg_attr(docsrs, doc(cfg(feature = "utf16-metric")))]
710 #[cfg(feature = "utf16-metric")]
711 #[track_caller]
712 #[inline]
713 pub fn utf16_slice<R>(self, utf16_range: R) -> RopeSlice<'a>
714 where
715 R: RangeBounds<usize>,
716 {
717 use super::metrics::Utf16Metric;
718
719 let (start, end) =
720 range_bounds_to_start_end(utf16_range, 0, self.utf16_len());
721
722 if start > end {
723 panic::utf16_start_after_end(start, end);
724 }
725
726 if end > self.utf16_len() {
727 panic::utf16_offset_out_of_bounds(end, self.utf16_len());
728 }
729
730 self.tree_slice.slice(Utf16Metric(start)..Utf16Metric(end)).into()
731 }
732}
733
734impl<'a> From<TreeSlice<'a, { Rope::arity() }, RopeChunk>> for RopeSlice<'a> {
735 #[inline]
736 fn from(tree_slice: TreeSlice<'a, { Rope::arity() }, RopeChunk>) -> Self {
737 Self {
738 has_trailing_newline: tree_slice
739 .end_slice()
740 .has_trailing_newline(),
741
742 tree_slice,
743 }
744 }
745}
746
747impl core::fmt::Debug for RopeSlice<'_> {
748 #[inline]
749 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
750 f.write_str("RopeSlice(\"")?;
751 debug_chunks(self.chunks(), f)?;
752 f.write_str("\")")
753 }
754}
755
756impl core::fmt::Display for RopeSlice<'_> {
757 #[inline]
758 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
759 for chunk in self.chunks() {
760 f.write_str(chunk)?;
761 }
762 Ok(())
763 }
764}
765
766impl core::cmp::PartialEq<RopeSlice<'_>> for RopeSlice<'_> {
767 #[inline]
768 fn eq(&self, rhs: &RopeSlice<'_>) -> bool {
769 (self.byte_len() == rhs.byte_len())
770 && (self.line_len() == rhs.line_len())
771 && chunks_eq_chunks(self.chunks(), rhs.chunks())
772 }
773}
774
775impl core::cmp::PartialEq<Rope> for RopeSlice<'_> {
776 #[inline]
777 fn eq(&self, rhs: &Rope) -> bool {
778 rhs == self
779 }
780}
781
782impl core::cmp::PartialEq<str> for RopeSlice<'_> {
783 #[inline]
784 fn eq(&self, rhs: &str) -> bool {
785 (self.byte_len() == rhs.len()) && chunks_eq_str(self.chunks(), rhs)
786 }
787}
788
789impl core::cmp::PartialEq<RopeSlice<'_>> for str {
790 #[inline]
791 fn eq(&self, rhs: &RopeSlice<'_>) -> bool {
792 rhs == self
793 }
794}
795
796impl core::cmp::PartialEq<&str> for RopeSlice<'_> {
797 #[inline]
798 fn eq(&self, rhs: &&str) -> bool {
799 self == *rhs
800 }
801}
802
803impl core::cmp::PartialEq<RopeSlice<'_>> for &str {
804 #[inline]
805 fn eq(&self, rhs: &RopeSlice<'_>) -> bool {
806 rhs == self
807 }
808}
809
810impl core::cmp::PartialEq<String> for RopeSlice<'_> {
811 #[inline]
812 fn eq(&self, rhs: &String) -> bool {
813 self == &**rhs
814 }
815}
816
817impl core::cmp::PartialEq<RopeSlice<'_>> for String {
818 #[inline]
819 fn eq(&self, rhs: &RopeSlice<'_>) -> bool {
820 rhs == self
821 }
822}
823
824impl core::cmp::PartialEq<alloc::borrow::Cow<'_, str>> for RopeSlice<'_> {
825 #[inline]
826 fn eq(&self, rhs: &alloc::borrow::Cow<'_, str>) -> bool {
827 self == &**rhs
828 }
829}
830
831impl core::cmp::PartialEq<RopeSlice<'_>> for alloc::borrow::Cow<'_, str> {
832 #[inline]
833 fn eq(&self, rhs: &RopeSlice<'_>) -> bool {
834 rhs == self
835 }
836}
837
838impl core::cmp::Eq for RopeSlice<'_> {}