Skip to main content

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<'_> {}