Skip to main content

java_string/
slice.rs

1use std::borrow::Cow;
2use std::collections::Bound;
3use std::fmt::{Debug, Display, Formatter, Write};
4use std::hash::{Hash, Hasher};
5use std::ops::{
6    Add, AddAssign, Index, IndexMut, Range, RangeBounds, RangeFrom, RangeFull, RangeInclusive,
7    RangeTo, RangeToInclusive,
8};
9use std::rc::Rc;
10use std::str::FromStr;
11use std::sync::Arc;
12use std::{ptr, slice};
13
14use crate::char::EscapeDebugExtArgs;
15use crate::validations::{
16    run_utf8_full_validation_from_semi, run_utf8_semi_validation, slice_error_fail,
17    str_end_index_overflow_fail,
18};
19use crate::{
20    Bytes, CharEscapeIter, CharIndices, Chars, EscapeDebug, EscapeDefault, EscapeUnicode,
21    JavaCodePoint, JavaStrPattern, JavaString, Lines, MatchIndices, Matches, ParseError,
22    RMatchIndices, RMatches, RSplit, RSplitN, RSplitTerminator, Split, SplitAsciiWhitespace,
23    SplitInclusive, SplitN, SplitTerminator, SplitWhitespace, Utf8Error,
24};
25
26#[derive(PartialEq, Eq, PartialOrd, Ord)]
27#[repr(transparent)]
28pub struct JavaStr {
29    inner: [u8],
30}
31
32#[allow(clippy::multiple_inherent_impl)]
33impl JavaStr {
34    /// Converts `v` to a `&JavaStr` if it is fully-valid UTF-8, i.e. UTF-8
35    /// without surrogate code points. See [`std::str::from_utf8`].
36    #[inline]
37    pub const fn from_full_utf8(v: &[u8]) -> Result<&JavaStr, Utf8Error> {
38        match std::str::from_utf8(v) {
39            Ok(str) => Ok(JavaStr::from_str(str)),
40            Err(err) => Err(Utf8Error::from_std(err)),
41        }
42    }
43
44    /// Converts `v` to a `&mut JavaStr` if it is fully-valid UTF-8, i.e. UTF-8
45    /// without surrogate code points. See [`std::str::from_utf8_mut`].
46    #[inline]
47    pub const fn from_full_utf8_mut(v: &mut [u8]) -> Result<&mut JavaStr, Utf8Error> {
48        match std::str::from_utf8_mut(v) {
49            Ok(str) => Ok(JavaStr::from_mut_str(str)),
50            Err(err) => Err(Utf8Error::from_std(err)),
51        }
52    }
53
54    /// Converts `v` to a `&JavaStr` if it is semi-valid UTF-8, i.e. UTF-8
55    /// with surrogate code points.
56    pub fn from_semi_utf8(v: &[u8]) -> Result<&JavaStr, Utf8Error> {
57        match run_utf8_semi_validation(v) {
58            Ok(()) => Ok(unsafe { JavaStr::from_semi_utf8_unchecked(v) }),
59            Err(err) => Err(err),
60        }
61    }
62
63    /// Converts `v` to a `&mut JavaStr` if it is semi-valid UTF-8, i.e. UTF-8
64    /// with surrogate code points.
65    pub fn from_semi_utf8_mut(v: &mut [u8]) -> Result<&mut JavaStr, Utf8Error> {
66        match run_utf8_semi_validation(v) {
67            Ok(()) => Ok(unsafe { JavaStr::from_semi_utf8_unchecked_mut(v) }),
68            Err(err) => Err(err),
69        }
70    }
71
72    /// # Safety
73    ///
74    /// The parameter must be in semi-valid UTF-8 format, that is, UTF-8 plus
75    /// surrogate code points.
76    #[inline]
77    #[must_use]
78    pub const unsafe fn from_semi_utf8_unchecked(v: &[u8]) -> &JavaStr {
79        unsafe {
80            // SAFETY: the caller must guarantee that the bytes `v` are valid UTF-8, minus
81            // the absence of surrogate chars. Also relies on `&JavaStr` and `&[u8]`
82            // having the same layout.
83            std::mem::transmute(v)
84        }
85    }
86
87    /// # Safety
88    ///
89    /// The parameter must be in semi-valid UTF-8 format, that is, UTF-8 plus
90    /// surrogate code points.
91    #[inline]
92    #[must_use]
93    pub const unsafe fn from_semi_utf8_unchecked_mut(v: &mut [u8]) -> &mut JavaStr {
94        unsafe {
95            // SAFETY: see from_semi_utf8_unchecked
96            std::mem::transmute(v)
97        }
98    }
99
100    #[inline]
101    #[must_use]
102    pub const fn from_str(str: &str) -> &JavaStr {
103        unsafe {
104            // SAFETY: the input str is guaranteed to have valid UTF-8.
105            JavaStr::from_semi_utf8_unchecked(str.as_bytes())
106        }
107    }
108
109    #[inline]
110    #[must_use]
111    pub const fn from_mut_str(str: &mut str) -> &mut JavaStr {
112        unsafe {
113            // SAFETY: the input str is guaranteed to have valid UTF-8.
114            JavaStr::from_semi_utf8_unchecked_mut(str.as_bytes_mut())
115        }
116    }
117
118    #[inline]
119    #[must_use]
120    pub fn from_boxed_str(v: Box<str>) -> Box<JavaStr> {
121        unsafe { JavaStr::from_boxed_semi_utf8_unchecked(v.into_boxed_bytes()) }
122    }
123
124    /// # Safety
125    ///
126    /// The parameter must be in semi-valid UTF-8 format, that is, UTF-8 plus
127    /// surrogate code points.
128    #[inline]
129    #[must_use]
130    pub unsafe fn from_boxed_semi_utf8_unchecked(v: Box<[u8]>) -> Box<JavaStr> {
131        unsafe { Box::from_raw(Box::into_raw(v) as *mut JavaStr) }
132    }
133
134    /// See [`str::as_bytes`].
135    #[inline]
136    #[must_use]
137    pub const fn as_bytes(&self) -> &[u8] {
138        &self.inner
139    }
140
141    /// See [`str::as_bytes_mut`].
142    ///
143    /// # Safety
144    ///
145    /// The returned slice must not have invalid UTF-8 written to it, besides
146    /// surrogate pairs.
147    #[inline]
148    #[must_use]
149    pub const unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
150        &mut self.inner
151    }
152
153    /// See [`str::as_mut_ptr`].
154    #[inline]
155    #[must_use]
156    pub const fn as_mut_ptr(&mut self) -> *mut u8 {
157        self.inner.as_mut_ptr()
158    }
159
160    /// See [`str::as_ptr`].
161    #[inline]
162    #[must_use]
163    pub const fn as_ptr(&self) -> *const u8 {
164        self.inner.as_ptr()
165    }
166
167    /// Tries to convert this `&JavaStr` to a `&str`, returning an error if
168    /// it is not fully valid UTF-8, i.e. has no surrogate code points.
169    pub const fn as_str(&self) -> Result<&str, Utf8Error> {
170        // Manual implementation of Option::map since it's not const
171        match run_utf8_full_validation_from_semi(self.as_bytes()) {
172            Ok(..) => unsafe {
173                // SAFETY: we were already semi-valid, and full validation just succeeded.
174                Ok(self.as_str_unchecked())
175            },
176            Err(err) => Err(err),
177        }
178    }
179
180    /// # Safety
181    ///
182    /// This string must be fully valid UTF-8, i.e. have no surrogate code
183    /// points.
184    #[inline]
185    #[must_use]
186    pub const unsafe fn as_str_unchecked(&self) -> &str {
187        unsafe {
188            // SAFETY: the caller must guarantee that the bytes `self` are valid UTF-8
189            std::str::from_utf8_unchecked(self.as_bytes())
190        }
191    }
192
193    /// Converts this `&JavaStr` to a `Cow<str>`, replacing surrogate code
194    /// points with the replacement character �.
195    ///
196    /// ```
197    /// # use std::borrow::Cow;
198    /// # use java_string::{JavaCodePoint, JavaStr, JavaString};
199    /// let s = JavaStr::from_str("Hello 🦀 World!");
200    /// let result = s.as_str_lossy();
201    /// assert!(matches!(result, Cow::Borrowed(_)));
202    /// assert_eq!(result, "Hello 🦀 World!");
203    ///
204    /// let s = JavaString::from("Hello ")
205    ///     + JavaString::from(JavaCodePoint::from_u32(0xd800).unwrap()).as_java_str()
206    ///     + JavaStr::from_str(" World!");
207    /// let result = s.as_str_lossy();
208    /// assert!(matches!(result, Cow::Owned(_)));
209    /// assert_eq!(result, "Hello � World!");
210    /// ```
211    #[must_use]
212    pub fn as_str_lossy(&self) -> Cow<'_, str> {
213        match run_utf8_full_validation_from_semi(self.as_bytes()) {
214            Ok(()) => unsafe {
215                // SAFETY: validation succeeded
216                Cow::Borrowed(self.as_str_unchecked())
217            },
218            Err(error) => unsafe {
219                // SAFETY: invalid parts of string are converted to replacement char
220                Cow::Owned(
221                    self.transform_invalid_string(error, str::to_owned, |_| {
222                        JavaStr::from_str("\u{FFFD}")
223                    })
224                    .into_string_unchecked(),
225                )
226            },
227        }
228    }
229
230    /// See [`str::bytes`].
231    #[inline]
232    pub fn bytes(&self) -> Bytes<'_> {
233        Bytes {
234            inner: self.inner.iter().copied(),
235        }
236    }
237
238    /// See [`str::char_indices`].
239    #[inline]
240    pub fn char_indices(&self) -> CharIndices<'_> {
241        CharIndices {
242            front_offset: 0,
243            inner: self.chars(),
244        }
245    }
246
247    /// See [`str::chars`].
248    #[inline]
249    pub fn chars(&self) -> Chars<'_> {
250        Chars {
251            inner: self.inner.iter(),
252        }
253    }
254
255    /// See [`str::contains`].
256    ///
257    /// ```
258    /// # use java_string::JavaStr;
259    /// let bananas = JavaStr::from_str("bananas");
260    ///
261    /// assert!(bananas.contains("nana"));
262    /// assert!(!bananas.contains("apples"));
263    /// ```
264    #[inline]
265    #[must_use]
266    pub fn contains<P>(&self, mut pat: P) -> bool
267    where
268        P: JavaStrPattern,
269    {
270        pat.find_in(self).is_some()
271    }
272
273    /// See [`str::ends_with`].
274    ///
275    /// ```
276    /// # use java_string::JavaStr;
277    /// let bananas = JavaStr::from_str("bananas");
278    ///
279    /// assert!(bananas.ends_with("anas"));
280    /// assert!(!bananas.ends_with("nana"));
281    /// ```
282    #[inline]
283    #[must_use]
284    pub fn ends_with<P>(&self, mut pat: P) -> bool
285    where
286        P: JavaStrPattern,
287    {
288        pat.suffix_len_in(self).is_some()
289    }
290
291    /// See [`str::eq_ignore_ascii_case`].
292    #[inline]
293    #[must_use]
294    pub fn eq_ignore_ascii_case(&self, other: &str) -> bool {
295        self.as_bytes().eq_ignore_ascii_case(other.as_bytes())
296    }
297
298    /// See [`str::eq_ignore_ascii_case`].
299    #[inline]
300    #[must_use]
301    pub fn eq_java_ignore_ascii_case(&self, other: &JavaStr) -> bool {
302        self.as_bytes().eq_ignore_ascii_case(other.as_bytes())
303    }
304
305    /// See [`str::escape_debug`].
306    ///
307    /// ```
308    /// # use java_string::JavaStr;
309    /// assert_eq!(
310    ///     JavaStr::from_str("❤\n!").escape_debug().to_string(),
311    ///     "❤\\n!"
312    /// );
313    /// ```
314    #[inline]
315    pub fn escape_debug(&self) -> EscapeDebug<'_> {
316        #[inline]
317        fn escape_first(first: JavaCodePoint) -> CharEscapeIter {
318            first.escape_debug_ext(EscapeDebugExtArgs::ESCAPE_ALL)
319        }
320        #[inline]
321        fn escape_rest(char: JavaCodePoint) -> CharEscapeIter {
322            char.escape_debug_ext(EscapeDebugExtArgs {
323                escape_single_quote: true,
324                escape_double_quote: true,
325            })
326        }
327
328        let mut chars = self.chars();
329        EscapeDebug {
330            inner: chars
331                .next()
332                .map(escape_first as fn(JavaCodePoint) -> CharEscapeIter)
333                .into_iter()
334                .flatten()
335                .chain(chars.flat_map(escape_rest as fn(JavaCodePoint) -> CharEscapeIter)),
336        }
337    }
338
339    /// See [`str::escape_default`].
340    ///
341    /// ```
342    /// # use java_string::JavaStr;
343    /// assert_eq!(
344    ///     JavaStr::from_str("❤\n!").escape_default().to_string(),
345    ///     "\\u{2764}\\n!"
346    /// );
347    /// ```
348    #[inline]
349    pub fn escape_default(&self) -> EscapeDefault<'_> {
350        EscapeDefault {
351            inner: self.chars().flat_map(JavaCodePoint::escape_default),
352        }
353    }
354
355    /// See [`str::escape_unicode`].
356    ///
357    /// ```
358    /// # use java_string::JavaStr;
359    /// assert_eq!(
360    ///     JavaStr::from_str("❤\n!").escape_unicode().to_string(),
361    ///     "\\u{2764}\\u{a}\\u{21}"
362    /// );
363    /// ```
364    #[inline]
365    pub fn escape_unicode(&self) -> EscapeUnicode<'_> {
366        EscapeUnicode {
367            inner: self.chars().flat_map(JavaCodePoint::escape_unicode),
368        }
369    }
370
371    /// See [`str::find`].
372    ///
373    /// ```
374    /// let s = "Löwe 老虎 Léopard Gepardi";
375    ///
376    /// assert_eq!(s.find('L'), Some(0));
377    /// assert_eq!(s.find('é'), Some(14));
378    /// assert_eq!(s.find("par"), Some(17));
379    ///
380    /// let x: &[_] = &['1', '2'];
381    /// assert_eq!(s.find(x), None);
382    /// ```
383    #[inline]
384    #[must_use]
385    pub fn find<P>(&self, mut pat: P) -> Option<usize>
386    where
387        P: JavaStrPattern,
388    {
389        pat.find_in(self).map(|(index, _)| index)
390    }
391
392    /// See [`str::get`].
393    ///
394    /// ```
395    /// # use java_string::{JavaStr, JavaString};
396    /// let v = JavaString::from("🗻∈🌏");
397    ///
398    /// assert_eq!(Some(JavaStr::from_str("🗻")), v.get(0..4));
399    ///
400    /// // indices not on UTF-8 sequence boundaries
401    /// assert!(v.get(1..).is_none());
402    /// assert!(v.get(..8).is_none());
403    ///
404    /// // out of bounds
405    /// assert!(v.get(..42).is_none());
406    /// ```
407    #[inline]
408    #[must_use]
409    pub fn get<I>(&self, i: I) -> Option<&JavaStr>
410    where
411        I: JavaStrSliceIndex,
412    {
413        i.get(self)
414    }
415
416    /// See [`str::get_mut`].
417    #[inline]
418    #[must_use]
419    pub fn get_mut<I>(&mut self, i: I) -> Option<&mut JavaStr>
420    where
421        I: JavaStrSliceIndex,
422    {
423        i.get_mut(self)
424    }
425
426    /// See [`str::get_unchecked`].
427    ///
428    /// # Safety
429    ///
430    /// - The starting index must not exceed the ending index
431    /// - Indexes must be within bounds of the original slice
432    /// - Indexes must lie on UTF-8 sequence boundaries
433    #[inline]
434    #[must_use]
435    pub unsafe fn get_unchecked<I>(&self, i: I) -> &JavaStr
436    where
437        I: JavaStrSliceIndex,
438    {
439        unsafe { &*i.get_unchecked(self) }
440    }
441
442    /// See [`str::get_unchecked_mut`].
443    ///
444    /// # Safety
445    ///
446    /// - The starting index must not exceed the ending index
447    /// - Indexes must be within bounds of the original slice
448    /// - Indexes must lie on UTF-8 sequence boundaries
449    #[inline]
450    #[must_use]
451    pub unsafe fn get_unchecked_mut<I>(&mut self, i: I) -> &mut JavaStr
452    where
453        I: JavaStrSliceIndex,
454    {
455        unsafe { &mut *i.get_unchecked_mut(self) }
456    }
457
458    /// See [`str::into_boxed_bytes`].
459    #[inline]
460    #[must_use]
461    pub fn into_boxed_bytes(self: Box<JavaStr>) -> Box<[u8]> {
462        unsafe { Box::from_raw(Box::into_raw(self) as *mut [u8]) }
463    }
464
465    /// See [`str::into_string`].
466    #[inline]
467    #[must_use]
468    pub fn into_string(self: Box<JavaStr>) -> JavaString {
469        let slice = self.into_boxed_bytes();
470        unsafe { JavaString::from_semi_utf8_unchecked(slice.into_vec()) }
471    }
472
473    /// See [`str::is_ascii`].
474    #[inline]
475    #[must_use]
476    pub fn is_ascii(&self) -> bool {
477        self.as_bytes().is_ascii()
478    }
479
480    /// See [`str::is_char_boundary`].
481    #[inline]
482    #[must_use]
483    pub const fn is_char_boundary(&self, index: usize) -> bool {
484        // 0 is always ok.
485        // Test for 0 explicitly so that it can optimize out the check
486        // easily and skip reading string data for that case.
487        // Note that optimizing `self.get(..index)` relies on this.
488        if index == 0 {
489            return true;
490        }
491
492        if index >= self.len() {
493            // For `true` we have two options:
494            //
495            // - index == self.len() Empty strings are valid, so return true
496            // - index > self.len() In this case return false
497            //
498            // The check is placed exactly here, because it improves generated
499            // code on higher opt-levels. See PR https://github.com/rust-lang/rust/pull/84751 for more details.
500            index == self.len()
501        } else {
502            // This is bit magic equivalent to: b < 128 || b >= 192
503            (self.as_bytes()[index] as i8) >= -0x40
504        }
505    }
506
507    pub(crate) fn floor_char_boundary(&self, index: usize) -> usize {
508        if index >= self.len() {
509            self.len()
510        } else {
511            let lower_bound = index.saturating_sub(3);
512            let new_index = self.as_bytes()[lower_bound..=index].iter().rposition(|b| {
513                // This is bit magic equivalent to: b < 128 || b >= 192
514                (*b as i8) >= -0x40
515            });
516
517            // SAFETY: we know that the character boundary will be within four bytes
518            unsafe { lower_bound + new_index.unwrap_unchecked() }
519        }
520    }
521
522    /// See [`str::is_empty`].
523    #[inline]
524    #[must_use]
525    pub fn is_empty(&self) -> bool {
526        self.len() == 0
527    }
528
529    /// See [`str::len`].
530    #[inline]
531    #[must_use]
532    pub const fn len(&self) -> usize {
533        self.inner.len()
534    }
535
536    /// See [`str::lines`].
537    #[inline]
538    pub fn lines(&self) -> Lines<'_> {
539        Lines {
540            inner: self.split_inclusive('\n').map(|line| {
541                let Some(line) = line.strip_suffix('\n') else {
542                    return line;
543                };
544                let Some(line) = line.strip_suffix('\r') else {
545                    return line;
546                };
547                line
548            }),
549        }
550    }
551
552    /// See [`str::make_ascii_lowercase`].
553    #[inline]
554    pub fn make_ascii_lowercase(&mut self) {
555        // SAFETY: changing ASCII letters only does not invalidate UTF-8.
556        let me = unsafe { self.as_bytes_mut() };
557        me.make_ascii_lowercase()
558    }
559
560    /// See [`str::make_ascii_uppercase`].
561    #[inline]
562    pub fn make_ascii_uppercase(&mut self) {
563        // SAFETY: changing ASCII letters only does not invalidate UTF-8.
564        let me = unsafe { self.as_bytes_mut() };
565        me.make_ascii_uppercase()
566    }
567
568    /// See [`str::match_indices`].
569    ///
570    /// ```
571    /// # use java_string::JavaStr;
572    /// let v: Vec<_> = JavaStr::from_str("abcXXXabcYYYabc")
573    ///     .match_indices("abc")
574    ///     .collect();
575    /// assert_eq!(
576    ///     v,
577    ///     [
578    ///         (0, JavaStr::from_str("abc")),
579    ///         (6, JavaStr::from_str("abc")),
580    ///         (12, JavaStr::from_str("abc"))
581    ///     ]
582    /// );
583    ///
584    /// let v: Vec<_> = JavaStr::from_str("1abcabc2").match_indices("abc").collect();
585    /// assert_eq!(
586    ///     v,
587    ///     [(1, JavaStr::from_str("abc")), (4, JavaStr::from_str("abc"))]
588    /// );
589    ///
590    /// let v: Vec<_> = JavaStr::from_str("ababa").match_indices("aba").collect();
591    /// assert_eq!(v, [(0, JavaStr::from_str("aba"))]); // only the first `aba`
592    /// ```
593    #[inline]
594    pub fn match_indices<P>(&self, pat: P) -> MatchIndices<'_, P>
595    where
596        P: JavaStrPattern,
597    {
598        MatchIndices {
599            str: self,
600            start: 0,
601            pat,
602        }
603    }
604
605    /// See [`str::matches`].
606    ///
607    /// ```
608    /// # use java_string::{JavaCodePoint, JavaStr};
609    /// let v: Vec<&JavaStr> = JavaStr::from_str("abcXXXabcYYYabc")
610    ///     .matches("abc")
611    ///     .collect();
612    /// assert_eq!(
613    ///     v,
614    ///     [
615    ///         JavaStr::from_str("abc"),
616    ///         JavaStr::from_str("abc"),
617    ///         JavaStr::from_str("abc")
618    ///     ]
619    /// );
620    ///
621    /// let v: Vec<&JavaStr> = JavaStr::from_str("1abc2abc3")
622    ///     .matches(JavaCodePoint::is_numeric)
623    ///     .collect();
624    /// assert_eq!(
625    ///     v,
626    ///     [
627    ///         JavaStr::from_str("1"),
628    ///         JavaStr::from_str("2"),
629    ///         JavaStr::from_str("3")
630    ///     ]
631    /// );
632    /// ```
633    #[inline]
634    pub fn matches<P>(&self, pat: P) -> Matches<'_, P>
635    where
636        P: JavaStrPattern,
637    {
638        Matches { str: self, pat }
639    }
640
641    /// See [`str::parse`].
642    #[inline]
643    pub fn parse<F>(&self) -> Result<F, ParseError<<F as FromStr>::Err>>
644    where
645        F: FromStr,
646    {
647        match self.as_str() {
648            Ok(str) => str.parse().map_err(ParseError::Err),
649            Err(err) => Err(ParseError::InvalidUtf8(err)),
650        }
651    }
652
653    /// See [`str::repeat`].
654    #[inline]
655    #[must_use]
656    pub fn repeat(&self, n: usize) -> JavaString {
657        unsafe { JavaString::from_semi_utf8_unchecked(self.as_bytes().repeat(n)) }
658    }
659
660    /// See [`str::replace`].
661    ///
662    /// ```
663    /// # use java_string::JavaStr;
664    /// let s = JavaStr::from_str("this is old");
665    ///
666    /// assert_eq!("this is new", s.replace("old", "new"));
667    /// assert_eq!("than an old", s.replace("is", "an"));
668    /// ```
669    #[inline]
670    #[must_use]
671    pub fn replace<P>(&self, from: P, to: &str) -> JavaString
672    where
673        P: JavaStrPattern,
674    {
675        self.replace_java(from, JavaStr::from_str(to))
676    }
677
678    /// See [`str::replace`].
679    #[inline]
680    #[must_use]
681    pub fn replace_java<P>(&self, from: P, to: &JavaStr) -> JavaString
682    where
683        P: JavaStrPattern,
684    {
685        let mut result = JavaString::new();
686        let mut last_end = 0;
687        for (start, part) in self.match_indices(from) {
688            result.push_java_str(unsafe { self.get_unchecked(last_end..start) });
689            result.push_java_str(to);
690            last_end = start + part.len();
691        }
692        result.push_java_str(unsafe { self.get_unchecked(last_end..self.len()) });
693        result
694    }
695
696    /// See [`str::replacen`].
697    ///
698    /// ```
699    /// # use java_string::{JavaCodePoint, JavaStr};
700    /// let s = JavaStr::from_str("foo foo 123 foo");
701    /// assert_eq!("new new 123 foo", s.replacen("foo", "new", 2));
702    /// assert_eq!("faa fao 123 foo", s.replacen('o', "a", 3));
703    /// assert_eq!(
704    ///     "foo foo new23 foo",
705    ///     s.replacen(JavaCodePoint::is_numeric, "new", 1)
706    /// );
707    /// ```
708    #[inline]
709    #[must_use]
710    pub fn replacen<P>(&self, from: P, to: &str, count: usize) -> JavaString
711    where
712        P: JavaStrPattern,
713    {
714        self.replacen_java(from, JavaStr::from_str(to), count)
715    }
716
717    /// See [`str::replacen`].
718    #[inline]
719    #[must_use]
720    pub fn replacen_java<P>(&self, from: P, to: &JavaStr, count: usize) -> JavaString
721    where
722        P: JavaStrPattern,
723    {
724        // Hope to reduce the times of re-allocation
725        let mut result = JavaString::with_capacity(32);
726        let mut last_end = 0;
727        for (start, part) in self.match_indices(from).take(count) {
728            result.push_java_str(unsafe { self.get_unchecked(last_end..start) });
729            result.push_java_str(to);
730            last_end = start + part.len();
731        }
732        result.push_java_str(unsafe { self.get_unchecked(last_end..self.len()) });
733        result
734    }
735
736    /// See [`str::rfind`].
737    ///
738    /// ```
739    /// # use java_string::JavaStr;
740    /// let s = JavaStr::from_str("Löwe 老虎 Léopard Gepardi");
741    ///
742    /// assert_eq!(s.rfind('L'), Some(13));
743    /// assert_eq!(s.rfind('é'), Some(14));
744    /// assert_eq!(s.rfind("par"), Some(24));
745    ///
746    /// let x: &[_] = &['1', '2'];
747    /// assert_eq!(s.rfind(x), None);
748    /// ```
749    #[inline]
750    #[must_use]
751    pub fn rfind<P>(&self, mut pat: P) -> Option<usize>
752    where
753        P: JavaStrPattern,
754    {
755        pat.rfind_in(self).map(|(index, _)| index)
756    }
757
758    /// See [`str::rmatch_indices`].
759    ///
760    /// ```
761    /// # use java_string::JavaStr;
762    /// let v: Vec<_> = JavaStr::from_str("abcXXXabcYYYabc")
763    ///     .rmatch_indices("abc")
764    ///     .collect();
765    /// assert_eq!(
766    ///     v,
767    ///     [
768    ///         (12, JavaStr::from_str("abc")),
769    ///         (6, JavaStr::from_str("abc")),
770    ///         (0, JavaStr::from_str("abc"))
771    ///     ]
772    /// );
773    ///
774    /// let v: Vec<_> = JavaStr::from_str("1abcabc2")
775    ///     .rmatch_indices("abc")
776    ///     .collect();
777    /// assert_eq!(
778    ///     v,
779    ///     [(4, JavaStr::from_str("abc")), (1, JavaStr::from_str("abc"))]
780    /// );
781    ///
782    /// let v: Vec<_> = JavaStr::from_str("ababa").rmatch_indices("aba").collect();
783    /// assert_eq!(v, [(2, JavaStr::from_str("aba"))]); // only the last `aba`
784    /// ```
785    #[inline]
786    pub fn rmatch_indices<P>(&self, pat: P) -> RMatchIndices<'_, P>
787    where
788        P: JavaStrPattern,
789    {
790        RMatchIndices {
791            inner: self.match_indices(pat),
792        }
793    }
794
795    /// See [`str::rmatches`].
796    ///
797    /// ```
798    /// # use java_string::{JavaCodePoint, JavaStr};
799    /// let v: Vec<&JavaStr> = JavaStr::from_str("abcXXXabcYYYabc")
800    ///     .rmatches("abc")
801    ///     .collect();
802    /// assert_eq!(
803    ///     v,
804    ///     [
805    ///         JavaStr::from_str("abc"),
806    ///         JavaStr::from_str("abc"),
807    ///         JavaStr::from_str("abc")
808    ///     ]
809    /// );
810    ///
811    /// let v: Vec<&JavaStr> = JavaStr::from_str("1abc2abc3")
812    ///     .rmatches(JavaCodePoint::is_numeric)
813    ///     .collect();
814    /// assert_eq!(
815    ///     v,
816    ///     [
817    ///         JavaStr::from_str("3"),
818    ///         JavaStr::from_str("2"),
819    ///         JavaStr::from_str("1")
820    ///     ]
821    /// );
822    /// ```
823    #[inline]
824    pub fn rmatches<P>(&self, pat: P) -> RMatches<'_, P>
825    where
826        P: JavaStrPattern,
827    {
828        RMatches {
829            inner: self.matches(pat),
830        }
831    }
832
833    /// See [`str::rsplit`].
834    ///
835    /// ```
836    /// # use java_string::JavaStr;
837    /// let v: Vec<&JavaStr> = JavaStr::from_str("Mary had a little lamb")
838    ///     .rsplit(' ')
839    ///     .collect();
840    /// assert_eq!(
841    ///     v,
842    ///     [
843    ///         JavaStr::from_str("lamb"),
844    ///         JavaStr::from_str("little"),
845    ///         JavaStr::from_str("a"),
846    ///         JavaStr::from_str("had"),
847    ///         JavaStr::from_str("Mary")
848    ///     ]
849    /// );
850    ///
851    /// let v: Vec<&JavaStr> = JavaStr::from_str("").rsplit('X').collect();
852    /// assert_eq!(v, [JavaStr::from_str("")]);
853    ///
854    /// let v: Vec<&JavaStr> = JavaStr::from_str("lionXXtigerXleopard")
855    ///     .rsplit('X')
856    ///     .collect();
857    /// assert_eq!(
858    ///     v,
859    ///     [
860    ///         JavaStr::from_str("leopard"),
861    ///         JavaStr::from_str("tiger"),
862    ///         JavaStr::from_str(""),
863    ///         JavaStr::from_str("lion")
864    ///     ]
865    /// );
866    ///
867    /// let v: Vec<&JavaStr> = JavaStr::from_str("lion::tiger::leopard")
868    ///     .rsplit("::")
869    ///     .collect();
870    /// assert_eq!(
871    ///     v,
872    ///     [
873    ///         JavaStr::from_str("leopard"),
874    ///         JavaStr::from_str("tiger"),
875    ///         JavaStr::from_str("lion")
876    ///     ]
877    /// );
878    /// ```
879    #[inline]
880    pub fn rsplit<P>(&self, pat: P) -> RSplit<'_, P>
881    where
882        P: JavaStrPattern,
883    {
884        RSplit::new(self, pat)
885    }
886
887    /// See [`str::rsplit_once`].
888    ///
889    /// ```
890    /// # use java_string::JavaStr;
891    /// assert_eq!(JavaStr::from_str("cfg").rsplit_once('='), None);
892    /// assert_eq!(
893    ///     JavaStr::from_str("cfg=foo").rsplit_once('='),
894    ///     Some((JavaStr::from_str("cfg"), JavaStr::from_str("foo")))
895    /// );
896    /// assert_eq!(
897    ///     JavaStr::from_str("cfg=foo=bar").rsplit_once('='),
898    ///     Some((JavaStr::from_str("cfg=foo"), JavaStr::from_str("bar")))
899    /// );
900    /// ```
901    #[inline]
902    #[must_use]
903    pub fn rsplit_once<P>(&self, mut delimiter: P) -> Option<(&JavaStr, &JavaStr)>
904    where
905        P: JavaStrPattern,
906    {
907        let (index, len) = delimiter.rfind_in(self)?;
908        // SAFETY: pattern is known to return valid indices.
909        unsafe {
910            Some((
911                self.get_unchecked(..index),
912                self.get_unchecked(index + len..),
913            ))
914        }
915    }
916
917    /// See [`str::rsplit_terminator`].
918    ///
919    /// ```
920    /// # use java_string::JavaStr;
921    /// let v: Vec<&JavaStr> = JavaStr::from_str("A.B.").rsplit_terminator('.').collect();
922    /// assert_eq!(v, [JavaStr::from_str("B"), JavaStr::from_str("A")]);
923    ///
924    /// let v: Vec<&JavaStr> = JavaStr::from_str("A..B..").rsplit_terminator(".").collect();
925    /// assert_eq!(
926    ///     v,
927    ///     [
928    ///         JavaStr::from_str(""),
929    ///         JavaStr::from_str("B"),
930    ///         JavaStr::from_str(""),
931    ///         JavaStr::from_str("A")
932    ///     ]
933    /// );
934    ///
935    /// let v: Vec<&JavaStr> = JavaStr::from_str("A.B:C.D")
936    ///     .rsplit_terminator(&['.', ':'][..])
937    ///     .collect();
938    /// assert_eq!(
939    ///     v,
940    ///     [
941    ///         JavaStr::from_str("D"),
942    ///         JavaStr::from_str("C"),
943    ///         JavaStr::from_str("B"),
944    ///         JavaStr::from_str("A")
945    ///     ]
946    /// );
947    /// ```
948    #[inline]
949    pub fn rsplit_terminator<P>(&self, pat: P) -> RSplitTerminator<'_, P>
950    where
951        P: JavaStrPattern,
952    {
953        RSplitTerminator::new(self, pat)
954    }
955
956    /// See [`str::rsplitn`].
957    ///
958    /// ```
959    /// # use java_string::JavaStr;
960    /// let v: Vec<&JavaStr> = JavaStr::from_str("Mary had a little lamb")
961    ///     .rsplitn(3, ' ')
962    ///     .collect();
963    /// assert_eq!(
964    ///     v,
965    ///     [
966    ///         JavaStr::from_str("lamb"),
967    ///         JavaStr::from_str("little"),
968    ///         JavaStr::from_str("Mary had a")
969    ///     ]
970    /// );
971    ///
972    /// let v: Vec<&JavaStr> = JavaStr::from_str("lionXXtigerXleopard")
973    ///     .rsplitn(3, 'X')
974    ///     .collect();
975    /// assert_eq!(
976    ///     v,
977    ///     [
978    ///         JavaStr::from_str("leopard"),
979    ///         JavaStr::from_str("tiger"),
980    ///         JavaStr::from_str("lionX")
981    ///     ]
982    /// );
983    ///
984    /// let v: Vec<&JavaStr> = JavaStr::from_str("lion::tiger::leopard")
985    ///     .rsplitn(2, "::")
986    ///     .collect();
987    /// assert_eq!(
988    ///     v,
989    ///     [
990    ///         JavaStr::from_str("leopard"),
991    ///         JavaStr::from_str("lion::tiger")
992    ///     ]
993    /// );
994    /// ```
995    #[inline]
996    pub fn rsplitn<P>(&self, n: usize, pat: P) -> RSplitN<'_, P>
997    where
998        P: JavaStrPattern,
999    {
1000        RSplitN::new(self, pat, n)
1001    }
1002
1003    /// See [`str::split`].
1004    ///
1005    /// ```
1006    /// # use java_string::{JavaCodePoint, JavaStr};
1007    /// let v: Vec<&JavaStr> = JavaStr::from_str("Mary had a little lamb")
1008    ///     .split(' ')
1009    ///     .collect();
1010    /// assert_eq!(
1011    ///     v,
1012    ///     [
1013    ///         JavaStr::from_str("Mary"),
1014    ///         JavaStr::from_str("had"),
1015    ///         JavaStr::from_str("a"),
1016    ///         JavaStr::from_str("little"),
1017    ///         JavaStr::from_str("lamb")
1018    ///     ]
1019    /// );
1020    ///
1021    /// let v: Vec<&JavaStr> = JavaStr::from_str("").split('X').collect();
1022    /// assert_eq!(v, [JavaStr::from_str("")]);
1023    ///
1024    /// let v: Vec<&JavaStr> = JavaStr::from_str("lionXXtigerXleopard")
1025    ///     .split('X')
1026    ///     .collect();
1027    /// assert_eq!(
1028    ///     v,
1029    ///     [
1030    ///         JavaStr::from_str("lion"),
1031    ///         JavaStr::from_str(""),
1032    ///         JavaStr::from_str("tiger"),
1033    ///         JavaStr::from_str("leopard")
1034    ///     ]
1035    /// );
1036    ///
1037    /// let v: Vec<&JavaStr> = JavaStr::from_str("lion::tiger::leopard")
1038    ///     .split("::")
1039    ///     .collect();
1040    /// assert_eq!(
1041    ///     v,
1042    ///     [
1043    ///         JavaStr::from_str("lion"),
1044    ///         JavaStr::from_str("tiger"),
1045    ///         JavaStr::from_str("leopard")
1046    ///     ]
1047    /// );
1048    ///
1049    /// let v: Vec<&JavaStr> = JavaStr::from_str("abc1def2ghi")
1050    ///     .split(JavaCodePoint::is_numeric)
1051    ///     .collect();
1052    /// assert_eq!(
1053    ///     v,
1054    ///     [
1055    ///         JavaStr::from_str("abc"),
1056    ///         JavaStr::from_str("def"),
1057    ///         JavaStr::from_str("ghi")
1058    ///     ]
1059    /// );
1060    ///
1061    /// let v: Vec<&JavaStr> = JavaStr::from_str("lionXtigerXleopard")
1062    ///     .split(JavaCodePoint::is_uppercase)
1063    ///     .collect();
1064    /// assert_eq!(
1065    ///     v,
1066    ///     [
1067    ///         JavaStr::from_str("lion"),
1068    ///         JavaStr::from_str("tiger"),
1069    ///         JavaStr::from_str("leopard")
1070    ///     ]
1071    /// );
1072    /// ```
1073    #[inline]
1074    pub fn split<P>(&self, pat: P) -> Split<'_, P>
1075    where
1076        P: JavaStrPattern,
1077    {
1078        Split::new(self, pat)
1079    }
1080
1081    /// See [`str::split_ascii_whitespace`].
1082    ///
1083    /// ```
1084    /// # use java_string::JavaStr;
1085    /// let mut iter = JavaStr::from_str(" Mary   had\ta little  \n\t lamb").split_ascii_whitespace();
1086    /// assert_eq!(Some(JavaStr::from_str("Mary")), iter.next());
1087    /// assert_eq!(Some(JavaStr::from_str("had")), iter.next());
1088    /// assert_eq!(Some(JavaStr::from_str("a")), iter.next());
1089    /// assert_eq!(Some(JavaStr::from_str("little")), iter.next());
1090    /// assert_eq!(Some(JavaStr::from_str("lamb")), iter.next());
1091    ///
1092    /// assert_eq!(None, iter.next());
1093    /// ```
1094    #[inline]
1095    pub fn split_ascii_whitespace(&self) -> SplitAsciiWhitespace<'_> {
1096        #[inline]
1097        fn is_non_empty(bytes: &&[u8]) -> bool {
1098            !bytes.is_empty()
1099        }
1100
1101        SplitAsciiWhitespace {
1102            inner: self
1103                .as_bytes()
1104                .split(u8::is_ascii_whitespace as fn(&u8) -> bool)
1105                .filter(is_non_empty as fn(&&[u8]) -> bool)
1106                .map(|bytes| unsafe { JavaStr::from_semi_utf8_unchecked(bytes) }),
1107        }
1108    }
1109
1110    /// See [`str::split_at`].
1111    ///
1112    /// ```
1113    /// # use java_string::JavaStr;
1114    /// let s = JavaStr::from_str("Per Martin-Löf");
1115    ///
1116    /// let (first, last) = s.split_at(3);
1117    ///
1118    /// assert_eq!("Per", first);
1119    /// assert_eq!(" Martin-Löf", last);
1120    /// ```
1121    /// ```should_panic
1122    /// # use java_string::JavaStr;
1123    /// let s = JavaStr::from_str("Per Martin-Löf");
1124    /// // Should panic
1125    /// let _ = s.split_at(13);
1126    /// ```
1127    #[inline]
1128    #[must_use]
1129    pub fn split_at(&self, mid: usize) -> (&JavaStr, &JavaStr) {
1130        // is_char_boundary checks that the index is in [0, .len()]
1131        if self.is_char_boundary(mid) {
1132            // SAFETY: just checked that `mid` is on a char boundary.
1133            unsafe {
1134                (
1135                    self.get_unchecked(0..mid),
1136                    self.get_unchecked(mid..self.len()),
1137                )
1138            }
1139        } else {
1140            slice_error_fail(self, 0, mid)
1141        }
1142    }
1143
1144    /// See [`str::split_at_mut`].
1145    ///
1146    /// ```
1147    /// # use java_string::{JavaStr, JavaString};
1148    /// let mut s = JavaString::from("Per Martin-Löf");
1149    /// let s = s.as_mut_java_str();
1150    ///
1151    /// let (first, last) = s.split_at_mut(3);
1152    ///
1153    /// assert_eq!("Per", first);
1154    /// assert_eq!(" Martin-Löf", last);
1155    /// ```
1156    /// ```should_panic
1157    /// # use java_string::{JavaStr, JavaString};
1158    /// let mut s = JavaString::from("Per Martin-Löf");
1159    /// let s = s.as_mut_java_str();
1160    /// // Should panic
1161    /// let _ = s.split_at(13);
1162    /// ```
1163    #[inline]
1164    #[must_use]
1165    pub fn split_at_mut(&mut self, mid: usize) -> (&mut JavaStr, &mut JavaStr) {
1166        // is_char_boundary checks that the index is in [0, .len()]
1167        if self.is_char_boundary(mid) {
1168            // SAFETY: just checked that `mid` is on a char boundary.
1169            unsafe { self.split_at_mut_unchecked(mid) }
1170        } else {
1171            slice_error_fail(self, 0, mid)
1172        }
1173    }
1174
1175    /// See [`str::split_at_checked`].
1176    ///
1177    /// ```
1178    /// # use java_string::JavaStr;
1179    /// let s = JavaStr::from_str("Per Martin-Löf");
1180    ///
1181    /// let (first, last) = s.split_at_checked(3).unwrap();
1182    /// assert_eq!("Per", first);
1183    /// assert_eq!(" Martin-Löf", last);
1184    ///
1185    /// assert_eq!(None, s.split_at_checked(13)); // Inside “ö”
1186    /// assert_eq!(None, s.split_at_checked(16)); // Beyond the string length
1187    /// ```
1188    #[inline]
1189    #[must_use]
1190    pub const fn split_at_checked(&self, mid: usize) -> Option<(&JavaStr, &JavaStr)> {
1191        // is_char_boundary checks that the index is in [0, .len()]
1192        if self.is_char_boundary(mid) {
1193            // SAFETY: just checked that `mid` is on a char boundary.
1194            unsafe { Some(self.split_at_unchecked(mid)) }
1195        } else {
1196            None
1197        }
1198    }
1199
1200    /// # Safety
1201    ///
1202    /// Caller must ensure that `mid` lies on a valid char boundary
1203    #[inline]
1204    const unsafe fn split_at_unchecked(&self, mid: usize) -> (&JavaStr, &JavaStr) {
1205        let len = self.len();
1206        let ptr = self.as_ptr();
1207        // SAFETY: caller guarantees `mid` is on a char boundary.
1208        unsafe {
1209            (
1210                Self::from_semi_utf8_unchecked(slice::from_raw_parts(ptr, mid)),
1211                Self::from_semi_utf8_unchecked(slice::from_raw_parts(ptr.add(mid), len - mid)),
1212            )
1213        }
1214    }
1215
1216    /// See [`str::split_at_mut_checked`].
1217    ///
1218    /// ```
1219    /// # use java_string::{JavaStr, JavaString};
1220    /// let mut s = JavaString::from("Per Martin-Löf");
1221    /// let mut s = s.as_mut_java_str();
1222    /// if let Some((first, last)) = s.split_at_mut_checked(3) {
1223    ///     first.make_ascii_uppercase();
1224    ///     assert_eq!("PER", first);
1225    ///     assert_eq!(" Martin-Löf", last);
1226    /// }
1227    /// assert_eq!("PER Martin-Löf", s);
1228    ///
1229    /// assert_eq!(None, s.split_at_mut_checked(13)); // Inside “ö”
1230    /// assert_eq!(None, s.split_at_mut_checked(16)); // Beyond the string length
1231    /// ```
1232    #[inline]
1233    #[must_use]
1234    pub const fn split_at_mut_checked(
1235        &mut self,
1236        mid: usize,
1237    ) -> Option<(&mut JavaStr, &mut JavaStr)> {
1238        // is_char_boundary checks that the index is in [0, .len()]
1239        if self.is_char_boundary(mid) {
1240            // SAFETY: just checked that `mid` is on a char boundary.
1241            unsafe { Some(self.split_at_mut_unchecked(mid)) }
1242        } else {
1243            None
1244        }
1245    }
1246
1247    /// # Safety
1248    ///
1249    /// Caller must ensure that `mid` lies on a valid char boundary
1250    #[inline]
1251    const unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut JavaStr, &mut JavaStr) {
1252        let len = self.len();
1253        let ptr = self.as_mut_ptr();
1254        // SAFETY: caller guarantees `mid` is on a char boundary.
1255        unsafe {
1256            (
1257                Self::from_semi_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, mid)),
1258                Self::from_semi_utf8_unchecked_mut(slice::from_raw_parts_mut(
1259                    ptr.add(mid),
1260                    len - mid,
1261                )),
1262            )
1263        }
1264    }
1265
1266    /// See [`str::split_inclusive`].
1267    ///
1268    /// ```
1269    /// # use java_string::JavaStr;
1270    /// let v: Vec<&JavaStr> = JavaStr::from_str("Mary had a little lamb\nlittle lamb\nlittle lamb.\n")
1271    ///     .split_inclusive('\n')
1272    ///     .collect();
1273    /// assert_eq!(
1274    ///     v,
1275    ///     [
1276    ///         JavaStr::from_str("Mary had a little lamb\n"),
1277    ///         JavaStr::from_str("little lamb\n"),
1278    ///         JavaStr::from_str("little lamb.\n")
1279    ///     ]
1280    /// );
1281    /// ```
1282    #[inline]
1283    pub fn split_inclusive<P>(&self, pat: P) -> SplitInclusive<'_, P>
1284    where
1285        P: JavaStrPattern,
1286    {
1287        SplitInclusive::new(self, pat)
1288    }
1289
1290    /// See [`str::split_once`].
1291    ///
1292    /// ```
1293    /// # use java_string::JavaStr;
1294    /// assert_eq!(JavaStr::from_str("cfg").split_once('='), None);
1295    /// assert_eq!(
1296    ///     JavaStr::from_str("cfg=").split_once('='),
1297    ///     Some((JavaStr::from_str("cfg"), JavaStr::from_str("")))
1298    /// );
1299    /// assert_eq!(
1300    ///     JavaStr::from_str("cfg=foo").split_once('='),
1301    ///     Some((JavaStr::from_str("cfg"), JavaStr::from_str("foo")))
1302    /// );
1303    /// assert_eq!(
1304    ///     JavaStr::from_str("cfg=foo=bar").split_once('='),
1305    ///     Some((JavaStr::from_str("cfg"), JavaStr::from_str("foo=bar")))
1306    /// );
1307    /// ```
1308    #[inline]
1309    #[must_use]
1310    pub fn split_once<P>(&self, mut delimiter: P) -> Option<(&JavaStr, &JavaStr)>
1311    where
1312        P: JavaStrPattern,
1313    {
1314        let (index, len) = delimiter.find_in(self)?;
1315        // SAFETY: pattern is known to return valid indices.
1316        unsafe {
1317            Some((
1318                self.get_unchecked(..index),
1319                self.get_unchecked(index + len..),
1320            ))
1321        }
1322    }
1323
1324    /// See [`str::split_terminator`].
1325    ///
1326    /// ```
1327    /// # use java_string::JavaStr;
1328    /// let v: Vec<&JavaStr> = JavaStr::from_str("A.B.").split_terminator('.').collect();
1329    /// assert_eq!(v, [JavaStr::from_str("A"), JavaStr::from_str("B")]);
1330    ///
1331    /// let v: Vec<&JavaStr> = JavaStr::from_str("A..B..").split_terminator(".").collect();
1332    /// assert_eq!(
1333    ///     v,
1334    ///     [
1335    ///         JavaStr::from_str("A"),
1336    ///         JavaStr::from_str(""),
1337    ///         JavaStr::from_str("B"),
1338    ///         JavaStr::from_str("")
1339    ///     ]
1340    /// );
1341    ///
1342    /// let v: Vec<&JavaStr> = JavaStr::from_str("A.B:C.D")
1343    ///     .split_terminator(&['.', ':'][..])
1344    ///     .collect();
1345    /// assert_eq!(
1346    ///     v,
1347    ///     [
1348    ///         JavaStr::from_str("A"),
1349    ///         JavaStr::from_str("B"),
1350    ///         JavaStr::from_str("C"),
1351    ///         JavaStr::from_str("D")
1352    ///     ]
1353    /// );
1354    /// ```
1355    #[inline]
1356    pub fn split_terminator<P>(&self, pat: P) -> SplitTerminator<'_, P>
1357    where
1358        P: JavaStrPattern,
1359    {
1360        SplitTerminator::new(self, pat)
1361    }
1362
1363    /// See [`str::split_whitespace`].
1364    #[inline]
1365    pub fn split_whitespace(&self) -> SplitWhitespace<'_> {
1366        SplitWhitespace {
1367            inner: self
1368                .split(JavaCodePoint::is_whitespace as fn(JavaCodePoint) -> bool)
1369                .filter(|str| !str.is_empty()),
1370        }
1371    }
1372
1373    /// See [`str::splitn`].
1374    ///
1375    /// ```
1376    /// # use java_string::JavaStr;
1377    /// let v: Vec<&JavaStr> = JavaStr::from_str("Mary had a little lambda")
1378    ///     .splitn(3, ' ')
1379    ///     .collect();
1380    /// assert_eq!(
1381    ///     v,
1382    ///     [
1383    ///         JavaStr::from_str("Mary"),
1384    ///         JavaStr::from_str("had"),
1385    ///         JavaStr::from_str("a little lambda")
1386    ///     ]
1387    /// );
1388    ///
1389    /// let v: Vec<&JavaStr> = JavaStr::from_str("lionXXtigerXleopard")
1390    ///     .splitn(3, "X")
1391    ///     .collect();
1392    /// assert_eq!(
1393    ///     v,
1394    ///     [
1395    ///         JavaStr::from_str("lion"),
1396    ///         JavaStr::from_str(""),
1397    ///         JavaStr::from_str("tigerXleopard")
1398    ///     ]
1399    /// );
1400    ///
1401    /// let v: Vec<&JavaStr> = JavaStr::from_str("abcXdef").splitn(1, 'X').collect();
1402    /// assert_eq!(v, [JavaStr::from_str("abcXdef")]);
1403    ///
1404    /// let v: Vec<&JavaStr> = JavaStr::from_str("").splitn(1, 'X').collect();
1405    /// assert_eq!(v, [JavaStr::from_str("")]);
1406    /// ```
1407    #[inline]
1408    pub fn splitn<P>(&self, n: usize, pat: P) -> SplitN<'_, P>
1409    where
1410        P: JavaStrPattern,
1411    {
1412        SplitN::new(self, pat, n)
1413    }
1414
1415    /// See [`str::starts_with`].
1416    ///
1417    /// ```
1418    /// # use java_string::JavaStr;
1419    /// let bananas = JavaStr::from_str("bananas");
1420    ///
1421    /// assert!(bananas.starts_with("bana"));
1422    /// assert!(!bananas.starts_with("nana"));
1423    /// ```
1424    #[inline]
1425    #[must_use]
1426    pub fn starts_with<P>(&self, mut pat: P) -> bool
1427    where
1428        P: JavaStrPattern,
1429    {
1430        pat.prefix_len_in(self).is_some()
1431    }
1432
1433    /// See [`str::strip_prefix`].
1434    ///
1435    /// ```
1436    /// # use java_string::JavaStr;
1437    /// assert_eq!(
1438    ///     JavaStr::from_str("foo:bar").strip_prefix("foo:"),
1439    ///     Some(JavaStr::from_str("bar"))
1440    /// );
1441    /// assert_eq!(JavaStr::from_str("foo:bar").strip_prefix("bar"), None);
1442    /// assert_eq!(
1443    ///     JavaStr::from_str("foofoo").strip_prefix("foo"),
1444    ///     Some(JavaStr::from_str("foo"))
1445    /// );
1446    /// ```
1447    #[inline]
1448    #[must_use]
1449    pub fn strip_prefix<P>(&self, mut prefix: P) -> Option<&JavaStr>
1450    where
1451        P: JavaStrPattern,
1452    {
1453        let len = prefix.prefix_len_in(self)?;
1454        // SAFETY: pattern is known to return valid indices.
1455        unsafe { Some(self.get_unchecked(len..)) }
1456    }
1457
1458    /// See [`str::strip_suffix`].
1459    ///
1460    /// ```
1461    /// # use java_string::JavaStr;
1462    /// assert_eq!(
1463    ///     JavaStr::from_str("bar:foo").strip_suffix(":foo"),
1464    ///     Some(JavaStr::from_str("bar"))
1465    /// );
1466    /// assert_eq!(JavaStr::from_str("bar:foo").strip_suffix("bar"), None);
1467    /// assert_eq!(
1468    ///     JavaStr::from_str("foofoo").strip_suffix("foo"),
1469    ///     Some(JavaStr::from_str("foo"))
1470    /// );
1471    /// ```
1472    #[inline]
1473    #[must_use]
1474    pub fn strip_suffix<P>(&self, mut suffix: P) -> Option<&JavaStr>
1475    where
1476        P: JavaStrPattern,
1477    {
1478        let len = suffix.suffix_len_in(self)?;
1479        // SAFETY: pattern is known to return valid indices.
1480        unsafe { Some(self.get_unchecked(..self.len() - len)) }
1481    }
1482
1483    /// See [`str::to_ascii_lowercase`].
1484    #[inline]
1485    #[must_use]
1486    pub fn to_ascii_lowercase(&self) -> JavaString {
1487        let mut s = self.to_owned();
1488        s.make_ascii_lowercase();
1489        s
1490    }
1491
1492    /// See [`str::to_ascii_uppercase`].
1493    #[inline]
1494    #[must_use]
1495    pub fn to_ascii_uppercase(&self) -> JavaString {
1496        let mut s = self.to_owned();
1497        s.make_ascii_uppercase();
1498        s
1499    }
1500
1501    /// See [`str::to_lowercase`].
1502    ///
1503    /// ```
1504    /// # use java_string::{JavaCodePoint, JavaStr, JavaString};
1505    /// let s = JavaStr::from_str("HELLO");
1506    /// assert_eq!("hello", s.to_lowercase());
1507    ///
1508    /// let odysseus = JavaStr::from_str("ὈΔΥΣΣΕΎΣ");
1509    /// assert_eq!("ὀδυσσεύς", odysseus.to_lowercase());
1510    ///
1511    /// let s = JavaString::from("Hello ")
1512    ///     + JavaString::from(JavaCodePoint::from_u32(0xd800).unwrap()).as_java_str()
1513    ///     + JavaStr::from_str(" World!");
1514    /// let expected = JavaString::from("hello ")
1515    ///     + JavaString::from(JavaCodePoint::from_u32(0xd800).unwrap()).as_java_str()
1516    ///     + JavaStr::from_str(" world!");
1517    /// assert_eq!(expected, s.to_lowercase());
1518    /// ```
1519    #[inline]
1520    #[must_use]
1521    pub fn to_lowercase(&self) -> JavaString {
1522        self.transform_string(str::to_lowercase, |ch| ch)
1523    }
1524
1525    /// See [`str::to_uppercase`].
1526    ///
1527    /// ```
1528    /// # use java_string::{JavaCodePoint, JavaStr, JavaString};
1529    /// let s = JavaStr::from_str("hello");
1530    /// assert_eq!("HELLO", s.to_uppercase());
1531    ///
1532    /// let s = JavaStr::from_str("tschüß");
1533    /// assert_eq!("TSCHÜSS", s.to_uppercase());
1534    ///
1535    /// let s = JavaString::from("Hello ")
1536    ///     + JavaString::from(JavaCodePoint::from_u32(0xd800).unwrap()).as_java_str()
1537    ///     + JavaStr::from_str(" World!");
1538    /// let expected = JavaString::from("HELLO ")
1539    ///     + JavaString::from(JavaCodePoint::from_u32(0xd800).unwrap()).as_java_str()
1540    ///     + JavaStr::from_str(" WORLD!");
1541    /// assert_eq!(expected, s.to_uppercase());
1542    /// ```
1543    #[inline]
1544    #[must_use]
1545    pub fn to_uppercase(&self) -> JavaString {
1546        self.transform_string(str::to_uppercase, |ch| ch)
1547    }
1548
1549    /// See [`str::trim`].
1550    #[inline]
1551    #[must_use]
1552    pub fn trim(&self) -> &JavaStr {
1553        self.trim_matches(|c: JavaCodePoint| c.is_whitespace())
1554    }
1555
1556    /// See [`str::trim_ascii`]
1557    #[inline]
1558    #[must_use]
1559    pub fn trim_ascii(&self) -> &JavaStr {
1560        self.trim_matches(|c: JavaCodePoint| c.is_ascii_whitespace())
1561    }
1562
1563    /// See [`str::trim_end`].
1564    #[inline]
1565    #[must_use]
1566    pub fn trim_end(&self) -> &JavaStr {
1567        self.trim_end_matches(|c: JavaCodePoint| c.is_whitespace())
1568    }
1569
1570    /// See [`str::trim_ascii_end`]
1571    pub fn trim_ascii_end(&self) -> &JavaStr {
1572        self.trim_end_matches(|c: JavaCodePoint| c.is_ascii_whitespace())
1573    }
1574
1575    /// See [`str::trim_end_matches`].
1576    ///
1577    /// ```
1578    /// # use java_string::{JavaCodePoint, JavaStr};
1579    /// assert_eq!(
1580    ///     JavaStr::from_str("11foo1bar11").trim_end_matches('1'),
1581    ///     "11foo1bar"
1582    /// );
1583    /// assert_eq!(
1584    ///     JavaStr::from_str("123foo1bar123").trim_end_matches(JavaCodePoint::is_numeric),
1585    ///     "123foo1bar"
1586    /// );
1587    ///
1588    /// let x: &[_] = &['1', '2'];
1589    /// assert_eq!(
1590    ///     JavaStr::from_str("12foo1bar12").trim_end_matches(x),
1591    ///     "12foo1bar"
1592    /// );
1593    /// ```
1594    #[inline]
1595    #[must_use]
1596    pub fn trim_end_matches<P>(&self, mut pat: P) -> &JavaStr
1597    where
1598        P: JavaStrPattern,
1599    {
1600        let mut str = self;
1601        while let Some(suffix_len) = pat.suffix_len_in(str) {
1602            if suffix_len == 0 {
1603                break;
1604            }
1605            // SAFETY: pattern is known to return valid indices.
1606            str = unsafe { str.get_unchecked(..str.len() - suffix_len) };
1607        }
1608        str
1609    }
1610
1611    /// See [`str::trim_matches`].
1612    ///
1613    /// ```
1614    /// # use java_string::{JavaCodePoint, JavaStr};
1615    /// assert_eq!(
1616    ///     JavaStr::from_str("11foo1bar11").trim_matches('1'),
1617    ///     "foo1bar"
1618    /// );
1619    /// assert_eq!(
1620    ///     JavaStr::from_str("123foo1bar123").trim_matches(JavaCodePoint::is_numeric),
1621    ///     "foo1bar"
1622    /// );
1623    ///
1624    /// let x: &[_] = &['1', '2'];
1625    /// assert_eq!(JavaStr::from_str("12foo1bar12").trim_matches(x), "foo1bar");
1626    /// ```
1627    #[inline]
1628    #[must_use]
1629    pub fn trim_matches<P>(&self, mut pat: P) -> &JavaStr
1630    where
1631        P: JavaStrPattern,
1632    {
1633        let mut str = self;
1634        while let Some(prefix_len) = pat.prefix_len_in(str) {
1635            if prefix_len == 0 {
1636                break;
1637            }
1638            // SAFETY: pattern is known to return valid indices.
1639            str = unsafe { str.get_unchecked(prefix_len..) };
1640        }
1641        while let Some(suffix_len) = pat.suffix_len_in(str) {
1642            if suffix_len == 0 {
1643                break;
1644            }
1645            // SAFETY: pattern is known to return valid indices.
1646            str = unsafe { str.get_unchecked(..str.len() - suffix_len) };
1647        }
1648        str
1649    }
1650
1651    /// See [`str::trim_start`].
1652    #[inline]
1653    #[must_use]
1654    pub fn trim_start(&self) -> &JavaStr {
1655        self.trim_start_matches(|c: JavaCodePoint| c.is_whitespace())
1656    }
1657
1658    /// See [`str::trim_ascii_start`]
1659    #[inline]
1660    #[must_use]
1661    pub fn trim_ascii_start(&self) -> &JavaStr {
1662        self.trim_start_matches(|c: JavaCodePoint| c.is_ascii_whitespace())
1663    }
1664
1665    /// See [`str::trim_start_matches`].
1666    ///
1667    /// ```
1668    /// # use java_string::{JavaCodePoint, JavaStr};
1669    /// assert_eq!(
1670    ///     JavaStr::from_str("11foo1bar11").trim_start_matches('1'),
1671    ///     "foo1bar11"
1672    /// );
1673    /// assert_eq!(
1674    ///     JavaStr::from_str("123foo1bar123").trim_start_matches(JavaCodePoint::is_numeric),
1675    ///     "foo1bar123"
1676    /// );
1677    ///
1678    /// let x: &[_] = &['1', '2'];
1679    /// assert_eq!(
1680    ///     JavaStr::from_str("12foo1bar12").trim_start_matches(x),
1681    ///     "foo1bar12"
1682    /// );
1683    /// ```
1684    #[inline]
1685    #[must_use]
1686    pub fn trim_start_matches<P>(&self, mut pat: P) -> &JavaStr
1687    where
1688        P: JavaStrPattern,
1689    {
1690        let mut str = self;
1691        while let Some(prefix_len) = pat.prefix_len_in(str) {
1692            if prefix_len == 0 {
1693                break;
1694            }
1695            // SAFETY: pattern is known to return valid indices.
1696            str = unsafe { str.get_unchecked(prefix_len..) };
1697        }
1698        str
1699    }
1700
1701    #[inline]
1702    fn transform_string<SF, ICF>(
1703        &self,
1704        mut string_transformer: SF,
1705        invalid_char_transformer: ICF,
1706    ) -> JavaString
1707    where
1708        SF: FnMut(&str) -> String,
1709        ICF: FnMut(&JavaStr) -> &JavaStr,
1710    {
1711        let bytes = self.as_bytes();
1712        match run_utf8_full_validation_from_semi(bytes) {
1713            Ok(()) => JavaString::from(string_transformer(unsafe {
1714                // SAFETY: validation succeeded
1715                std::str::from_utf8_unchecked(bytes)
1716            })),
1717            Err(error) => {
1718                self.transform_invalid_string(error, string_transformer, invalid_char_transformer)
1719            }
1720        }
1721    }
1722
1723    #[inline]
1724    fn transform_invalid_string<SF, ICF>(
1725        &self,
1726        error: Utf8Error,
1727        mut string_transformer: SF,
1728        mut invalid_char_transformer: ICF,
1729    ) -> JavaString
1730    where
1731        SF: FnMut(&str) -> String,
1732        ICF: FnMut(&JavaStr) -> &JavaStr,
1733    {
1734        let bytes = self.as_bytes();
1735        let mut result = JavaString::from(string_transformer(unsafe {
1736            // SAFETY: validation succeeded up to this index
1737            std::str::from_utf8_unchecked(bytes.get_unchecked(..error.valid_up_to))
1738        }));
1739        result.push_java_str(invalid_char_transformer(unsafe {
1740            // SAFETY: any UTF-8 error in semi-valid UTF-8 is a 3 byte long sequence
1741            // representing a surrogate code point. We're pushing that sequence now
1742            JavaStr::from_semi_utf8_unchecked(
1743                bytes.get_unchecked(error.valid_up_to..error.valid_up_to + 3),
1744            )
1745        }));
1746        let mut index = error.valid_up_to + 3;
1747        loop {
1748            let remainder = unsafe { bytes.get_unchecked(index..) };
1749            match run_utf8_full_validation_from_semi(remainder) {
1750                Ok(()) => {
1751                    result.push_str(&string_transformer(unsafe {
1752                        // SAFETY: validation succeeded
1753                        std::str::from_utf8_unchecked(remainder)
1754                    }));
1755                    return result;
1756                }
1757                Err(error) => {
1758                    result.push_str(&string_transformer(unsafe {
1759                        // SAFETY: validation succeeded up to this index
1760                        std::str::from_utf8_unchecked(
1761                            bytes.get_unchecked(index..index + error.valid_up_to),
1762                        )
1763                    }));
1764                    result.push_java_str(invalid_char_transformer(unsafe {
1765                        // SAFETY: see comment above
1766                        JavaStr::from_semi_utf8_unchecked(bytes.get_unchecked(
1767                            index + error.valid_up_to..index + error.valid_up_to + 3,
1768                        ))
1769                    }));
1770                    index += error.valid_up_to + 3;
1771                }
1772            }
1773        }
1774    }
1775}
1776
1777impl<'a> Add<&JavaStr> for Cow<'a, JavaStr> {
1778    type Output = Cow<'a, JavaStr>;
1779
1780    #[inline]
1781    fn add(mut self, rhs: &JavaStr) -> Self::Output {
1782        self += rhs;
1783        self
1784    }
1785}
1786
1787impl AddAssign<&JavaStr> for Cow<'_, JavaStr> {
1788    #[inline]
1789    fn add_assign(&mut self, rhs: &JavaStr) {
1790        if !rhs.is_empty() {
1791            match self {
1792                Cow::Borrowed(lhs) => {
1793                    let mut result = lhs.to_owned();
1794                    result.push_java_str(rhs);
1795                    *self = Cow::Owned(result);
1796                }
1797                Cow::Owned(lhs) => {
1798                    lhs.push_java_str(rhs);
1799                }
1800            }
1801        }
1802    }
1803}
1804
1805impl AsRef<[u8]> for JavaStr {
1806    #[inline]
1807    fn as_ref(&self) -> &[u8] {
1808        self.as_bytes()
1809    }
1810}
1811
1812impl AsRef<JavaStr> for str {
1813    #[inline]
1814    fn as_ref(&self) -> &JavaStr {
1815        JavaStr::from_str(self)
1816    }
1817}
1818
1819impl AsRef<JavaStr> for String {
1820    #[inline]
1821    fn as_ref(&self) -> &JavaStr {
1822        JavaStr::from_str(self)
1823    }
1824}
1825
1826impl AsRef<JavaStr> for JavaStr {
1827    #[inline]
1828    fn as_ref(&self) -> &JavaStr {
1829        self
1830    }
1831}
1832
1833impl Clone for Box<JavaStr> {
1834    #[inline]
1835    fn clone(&self) -> Self {
1836        let buf: Box<[u8]> = self.as_bytes().into();
1837        unsafe { JavaStr::from_boxed_semi_utf8_unchecked(buf) }
1838    }
1839}
1840
1841impl Debug for JavaStr {
1842    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1843        f.write_char('"')?;
1844        let mut from = 0;
1845        for (i, c) in self.char_indices() {
1846            let esc = c.escape_debug_ext(EscapeDebugExtArgs {
1847                escape_single_quote: false,
1848                escape_double_quote: true,
1849            });
1850            // If char needs escaping, flush backlog so far and write, else skip.
1851            // Also handle invalid UTF-8 here
1852            if esc.len() != 1 || c.as_char().is_none() {
1853                unsafe {
1854                    // SAFETY: any invalid UTF-8 should have been caught by a previous iteration
1855                    f.write_str(self[from..i].as_str_unchecked())?
1856                };
1857                for c in esc {
1858                    f.write_char(c)?;
1859                }
1860                from = i + c.len_utf8();
1861            }
1862        }
1863        unsafe {
1864            // SAFETY: any invalid UTF-8 should have been caught by the loop above
1865            f.write_str(self[from..].as_str_unchecked())?
1866        };
1867        f.write_char('"')
1868    }
1869}
1870
1871impl Default for &JavaStr {
1872    #[inline]
1873    fn default() -> Self {
1874        JavaStr::from_str("")
1875    }
1876}
1877
1878impl Default for Box<JavaStr> {
1879    #[inline]
1880    fn default() -> Self {
1881        JavaStr::from_boxed_str(Box::<str>::default())
1882    }
1883}
1884
1885impl Display for JavaStr {
1886    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1887        Display::fmt(&self.as_str_lossy(), f)
1888    }
1889}
1890
1891impl<'a> From<&'a JavaStr> for Cow<'a, JavaStr> {
1892    #[inline]
1893    fn from(value: &'a JavaStr) -> Self {
1894        Cow::Borrowed(value)
1895    }
1896}
1897
1898impl From<&JavaStr> for Arc<JavaStr> {
1899    #[inline]
1900    fn from(value: &JavaStr) -> Self {
1901        let arc = Arc::<[u8]>::from(value.as_bytes());
1902        unsafe { Arc::from_raw(Arc::into_raw(arc) as *const JavaStr) }
1903    }
1904}
1905
1906impl From<&JavaStr> for Box<JavaStr> {
1907    #[inline]
1908    fn from(value: &JavaStr) -> Self {
1909        unsafe { JavaStr::from_boxed_semi_utf8_unchecked(Box::from(value.as_bytes())) }
1910    }
1911}
1912
1913impl From<&JavaStr> for Rc<JavaStr> {
1914    #[inline]
1915    fn from(value: &JavaStr) -> Self {
1916        let rc = Rc::<[u8]>::from(value.as_bytes());
1917        unsafe { Rc::from_raw(Rc::into_raw(rc) as *const JavaStr) }
1918    }
1919}
1920
1921impl From<&JavaStr> for Vec<u8> {
1922    #[inline]
1923    fn from(value: &JavaStr) -> Self {
1924        From::from(value.as_bytes())
1925    }
1926}
1927
1928impl From<Cow<'_, JavaStr>> for Box<JavaStr> {
1929    #[inline]
1930    fn from(value: Cow<'_, JavaStr>) -> Self {
1931        match value {
1932            Cow::Borrowed(s) => Box::from(s),
1933            Cow::Owned(s) => Box::from(s),
1934        }
1935    }
1936}
1937
1938impl From<JavaString> for Box<JavaStr> {
1939    #[inline]
1940    fn from(value: JavaString) -> Self {
1941        value.into_boxed_str()
1942    }
1943}
1944
1945impl<'a> From<&'a str> for &'a JavaStr {
1946    #[inline]
1947    fn from(value: &'a str) -> Self {
1948        JavaStr::from_str(value)
1949    }
1950}
1951
1952impl<'a> From<&'a String> for &'a JavaStr {
1953    #[inline]
1954    fn from(value: &'a String) -> Self {
1955        JavaStr::from_str(value)
1956    }
1957}
1958
1959impl FromIterator<char> for Box<JavaStr> {
1960    #[inline]
1961    fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
1962        JavaString::from_iter(iter).into_boxed_str()
1963    }
1964}
1965
1966impl<'a> FromIterator<&'a char> for Box<JavaStr> {
1967    #[inline]
1968    fn from_iter<T: IntoIterator<Item = &'a char>>(iter: T) -> Self {
1969        JavaString::from_iter(iter).into_boxed_str()
1970    }
1971}
1972
1973impl FromIterator<JavaCodePoint> for Box<JavaStr> {
1974    #[inline]
1975    fn from_iter<T: IntoIterator<Item = JavaCodePoint>>(iter: T) -> Self {
1976        JavaString::from_iter(iter).into_boxed_str()
1977    }
1978}
1979
1980impl<'a> FromIterator<&'a JavaCodePoint> for Box<JavaStr> {
1981    #[inline]
1982    fn from_iter<T: IntoIterator<Item = &'a JavaCodePoint>>(iter: T) -> Self {
1983        JavaString::from_iter(iter).into_boxed_str()
1984    }
1985}
1986
1987impl<'a> FromIterator<&'a str> for Box<JavaStr> {
1988    #[inline]
1989    fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
1990        JavaString::from_iter(iter).into_boxed_str()
1991    }
1992}
1993
1994impl<'a> FromIterator<&'a JavaStr> for Box<JavaStr> {
1995    #[inline]
1996    fn from_iter<T: IntoIterator<Item = &'a JavaStr>>(iter: T) -> Self {
1997        JavaString::from_iter(iter).into_boxed_str()
1998    }
1999}
2000
2001impl FromIterator<String> for Box<JavaStr> {
2002    fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
2003        JavaString::from_iter(iter).into_boxed_str()
2004    }
2005}
2006
2007impl FromIterator<JavaString> for Box<JavaStr> {
2008    fn from_iter<T: IntoIterator<Item = JavaString>>(iter: T) -> Self {
2009        JavaString::from_iter(iter).into_boxed_str()
2010    }
2011}
2012
2013impl FromIterator<Box<str>> for Box<JavaStr> {
2014    #[inline]
2015    fn from_iter<T: IntoIterator<Item = Box<str>>>(iter: T) -> Self {
2016        JavaString::from_iter(iter).into_boxed_str()
2017    }
2018}
2019
2020impl FromIterator<Box<JavaStr>> for Box<JavaStr> {
2021    #[inline]
2022    fn from_iter<T: IntoIterator<Item = Box<JavaStr>>>(iter: T) -> Self {
2023        JavaString::from_iter(iter).into_boxed_str()
2024    }
2025}
2026
2027impl<'a> FromIterator<Cow<'a, str>> for Box<JavaStr> {
2028    #[inline]
2029    fn from_iter<T: IntoIterator<Item = Cow<'a, str>>>(iter: T) -> Self {
2030        JavaString::from_iter(iter).into_boxed_str()
2031    }
2032}
2033
2034impl<'a> FromIterator<Cow<'a, JavaStr>> for Box<JavaStr> {
2035    #[inline]
2036    fn from_iter<T: IntoIterator<Item = Cow<'a, JavaStr>>>(iter: T) -> Self {
2037        JavaString::from_iter(iter).into_boxed_str()
2038    }
2039}
2040
2041impl Hash for JavaStr {
2042    #[inline]
2043    fn hash<H: Hasher>(&self, state: &mut H) {
2044        state.write(self.as_bytes());
2045        state.write_u8(0xff);
2046    }
2047}
2048
2049impl<I> Index<I> for JavaStr
2050where
2051    I: JavaStrSliceIndex,
2052{
2053    type Output = JavaStr;
2054
2055    #[inline]
2056    fn index(&self, index: I) -> &Self::Output {
2057        index.index(self)
2058    }
2059}
2060
2061impl<I> IndexMut<I> for JavaStr
2062where
2063    I: JavaStrSliceIndex,
2064{
2065    #[inline]
2066    fn index_mut(&mut self, index: I) -> &mut Self::Output {
2067        index.index_mut(self)
2068    }
2069}
2070
2071impl<'b> PartialEq<&'b JavaStr> for Cow<'_, str> {
2072    #[inline]
2073    fn eq(&self, other: &&'b JavaStr) -> bool {
2074        self == *other
2075    }
2076}
2077
2078impl<'b> PartialEq<&'b JavaStr> for Cow<'_, JavaStr> {
2079    #[inline]
2080    fn eq(&self, other: &&'b JavaStr) -> bool {
2081        self == *other
2082    }
2083}
2084
2085impl<'a> PartialEq<Cow<'a, str>> for &JavaStr {
2086    #[inline]
2087    fn eq(&self, other: &Cow<'a, str>) -> bool {
2088        *self == other
2089    }
2090}
2091
2092impl<'a> PartialEq<Cow<'a, str>> for JavaStr {
2093    #[inline]
2094    fn eq(&self, other: &Cow<'a, str>) -> bool {
2095        other == self
2096    }
2097}
2098
2099impl<'a> PartialEq<Cow<'a, JavaStr>> for &JavaStr {
2100    #[inline]
2101    fn eq(&self, other: &Cow<'a, JavaStr>) -> bool {
2102        *self == other
2103    }
2104}
2105
2106impl<'a> PartialEq<Cow<'a, JavaStr>> for JavaStr {
2107    #[inline]
2108    fn eq(&self, other: &Cow<'a, JavaStr>) -> bool {
2109        other == self
2110    }
2111}
2112
2113impl PartialEq<String> for &JavaStr {
2114    #[inline]
2115    fn eq(&self, other: &String) -> bool {
2116        *self == other
2117    }
2118}
2119
2120impl PartialEq<String> for JavaStr {
2121    #[inline]
2122    fn eq(&self, other: &String) -> bool {
2123        self == &other[..]
2124    }
2125}
2126
2127impl PartialEq<JavaStr> for String {
2128    #[inline]
2129    fn eq(&self, other: &JavaStr) -> bool {
2130        &self[..] == other
2131    }
2132}
2133
2134impl PartialEq<JavaString> for &JavaStr {
2135    #[inline]
2136    fn eq(&self, other: &JavaString) -> bool {
2137        *self == other
2138    }
2139}
2140
2141impl PartialEq<JavaString> for JavaStr {
2142    #[inline]
2143    fn eq(&self, other: &JavaString) -> bool {
2144        self == other[..]
2145    }
2146}
2147
2148impl PartialEq<JavaStr> for Cow<'_, str> {
2149    #[inline]
2150    fn eq(&self, other: &JavaStr) -> bool {
2151        match self {
2152            Cow::Borrowed(this) => this == other,
2153            Cow::Owned(this) => this == other,
2154        }
2155    }
2156}
2157
2158impl PartialEq<JavaStr> for Cow<'_, JavaStr> {
2159    #[inline]
2160    fn eq(&self, other: &JavaStr) -> bool {
2161        match self {
2162            Cow::Borrowed(this) => this == other,
2163            Cow::Owned(this) => this == other,
2164        }
2165    }
2166}
2167
2168impl PartialEq<JavaStr> for str {
2169    #[inline]
2170    fn eq(&self, other: &JavaStr) -> bool {
2171        JavaStr::from_str(self) == other
2172    }
2173}
2174
2175impl PartialEq<JavaStr> for &str {
2176    #[inline]
2177    fn eq(&self, other: &JavaStr) -> bool {
2178        self.as_bytes() == &other.inner
2179    }
2180}
2181
2182impl PartialEq<str> for JavaStr {
2183    #[inline]
2184    fn eq(&self, other: &str) -> bool {
2185        &self.inner == other.as_bytes()
2186    }
2187}
2188
2189impl<'a> PartialEq<&'a str> for JavaStr {
2190    #[inline]
2191    fn eq(&self, other: &&'a str) -> bool {
2192        &self.inner == other.as_bytes()
2193    }
2194}
2195
2196impl PartialEq<JavaStr> for &JavaStr {
2197    #[inline]
2198    fn eq(&self, other: &JavaStr) -> bool {
2199        self.inner == other.inner
2200    }
2201}
2202
2203impl<'a> PartialEq<&'a JavaStr> for JavaStr {
2204    #[inline]
2205    fn eq(&self, other: &&'a JavaStr) -> bool {
2206        self.inner == other.inner
2207    }
2208}
2209
2210impl ToOwned for JavaStr {
2211    type Owned = JavaString;
2212
2213    #[inline]
2214    fn to_owned(&self) -> Self::Owned {
2215        unsafe { JavaString::from_semi_utf8_unchecked(self.as_bytes().to_vec()) }
2216    }
2217}
2218
2219mod private_slice_index {
2220    use std::ops;
2221
2222    pub trait Sealed {}
2223
2224    impl Sealed for ops::Range<usize> {}
2225    impl Sealed for ops::RangeTo<usize> {}
2226    impl Sealed for ops::RangeFrom<usize> {}
2227    impl Sealed for ops::RangeFull {}
2228    impl Sealed for ops::RangeInclusive<usize> {}
2229    impl Sealed for ops::RangeToInclusive<usize> {}
2230}
2231
2232/// # Safety
2233///
2234/// Implementations' `check_bounds` method must properly check the bounds of the
2235/// slice, such that calling `get_unchecked` is not UB.
2236pub unsafe trait JavaStrSliceIndex: private_slice_index::Sealed + Sized {
2237    fn check_bounds(&self, slice: &JavaStr) -> bool;
2238    fn check_bounds_fail(self, slice: &JavaStr) -> !;
2239
2240    /// # Safety
2241    ///
2242    /// - The input slice must be a valid pointer
2243    /// - This index must not be out of bounds of the input slice
2244    /// - The indices of this slice must point to char boundaries in the input
2245    ///   slice
2246    unsafe fn get_unchecked(self, slice: *const JavaStr) -> *const JavaStr;
2247
2248    /// # Safety
2249    ///
2250    /// - The input slice must be a valid pointer
2251    /// - This index must not be out of bounds of the input slice
2252    /// - The indices of this slice must point to char boundaries in the input
2253    ///   slice
2254    unsafe fn get_unchecked_mut(self, slice: *mut JavaStr) -> *mut JavaStr;
2255
2256    #[inline]
2257    fn get(self, slice: &JavaStr) -> Option<&JavaStr> {
2258        self.check_bounds(slice)
2259            .then(|| unsafe { &*self.get_unchecked(slice) })
2260    }
2261
2262    #[inline]
2263    fn get_mut(self, slice: &mut JavaStr) -> Option<&mut JavaStr> {
2264        self.check_bounds(slice)
2265            .then(|| unsafe { &mut *self.get_unchecked_mut(slice) })
2266    }
2267
2268    #[inline]
2269    fn index(self, slice: &JavaStr) -> &JavaStr {
2270        if self.check_bounds(slice) {
2271            unsafe { &*self.get_unchecked(slice) }
2272        } else {
2273            self.check_bounds_fail(slice)
2274        }
2275    }
2276
2277    #[inline]
2278    fn index_mut(self, slice: &mut JavaStr) -> &mut JavaStr {
2279        if self.check_bounds(slice) {
2280            unsafe { &mut *self.get_unchecked_mut(slice) }
2281        } else {
2282            self.check_bounds_fail(slice)
2283        }
2284    }
2285}
2286
2287unsafe impl JavaStrSliceIndex for RangeFull {
2288    #[inline]
2289    fn check_bounds(&self, _slice: &JavaStr) -> bool {
2290        true
2291    }
2292
2293    #[inline]
2294    fn check_bounds_fail(self, _slice: &JavaStr) -> ! {
2295        unreachable!()
2296    }
2297
2298    #[inline]
2299    unsafe fn get_unchecked(self, slice: *const JavaStr) -> *const JavaStr {
2300        slice
2301    }
2302
2303    #[inline]
2304    unsafe fn get_unchecked_mut(self, slice: *mut JavaStr) -> *mut JavaStr {
2305        slice
2306    }
2307}
2308
2309unsafe impl JavaStrSliceIndex for Range<usize> {
2310    #[inline]
2311    fn check_bounds(&self, slice: &JavaStr) -> bool {
2312        self.start <= self.end
2313            && slice.is_char_boundary(self.start)
2314            && slice.is_char_boundary(self.end)
2315    }
2316
2317    #[inline]
2318    #[track_caller]
2319    fn check_bounds_fail(self, slice: &JavaStr) -> ! {
2320        slice_error_fail(slice, self.start, self.end)
2321    }
2322
2323    #[inline]
2324    unsafe fn get_unchecked(self, slice: *const JavaStr) -> *const JavaStr {
2325        let slice = slice as *const [u8];
2326        // SAFETY: the caller guarantees that `self` is in bounds of `slice`
2327        // which satisfies all the conditions for `add`.
2328        let ptr = unsafe { (slice as *const u8).add(self.start) };
2329        let len = self.end - self.start;
2330        ptr::slice_from_raw_parts(ptr, len) as *const JavaStr
2331    }
2332
2333    #[inline]
2334    unsafe fn get_unchecked_mut(self, slice: *mut JavaStr) -> *mut JavaStr {
2335        let slice = slice as *mut [u8];
2336        // SAFETY: see comments for `get_unchecked`.
2337        let ptr = unsafe { (slice as *mut u8).add(self.start) };
2338        let len = self.end - self.start;
2339        ptr::slice_from_raw_parts_mut(ptr, len) as *mut JavaStr
2340    }
2341}
2342
2343unsafe impl JavaStrSliceIndex for RangeTo<usize> {
2344    #[inline]
2345    fn check_bounds(&self, slice: &JavaStr) -> bool {
2346        slice.is_char_boundary(self.end)
2347    }
2348
2349    #[inline]
2350    #[track_caller]
2351    fn check_bounds_fail(self, slice: &JavaStr) -> ! {
2352        slice_error_fail(slice, 0, self.end)
2353    }
2354
2355    #[inline]
2356    unsafe fn get_unchecked(self, slice: *const JavaStr) -> *const JavaStr {
2357        unsafe { (0..self.end).get_unchecked(slice) }
2358    }
2359
2360    #[inline]
2361    unsafe fn get_unchecked_mut(self, slice: *mut JavaStr) -> *mut JavaStr {
2362        unsafe { (0..self.end).get_unchecked_mut(slice) }
2363    }
2364}
2365
2366unsafe impl JavaStrSliceIndex for RangeFrom<usize> {
2367    #[inline]
2368    fn check_bounds(&self, slice: &JavaStr) -> bool {
2369        slice.is_char_boundary(self.start)
2370    }
2371
2372    #[inline]
2373    #[track_caller]
2374    fn check_bounds_fail(self, slice: &JavaStr) -> ! {
2375        slice_error_fail(slice, self.start, slice.len())
2376    }
2377
2378    #[inline]
2379    unsafe fn get_unchecked(self, slice: *const JavaStr) -> *const JavaStr {
2380        let len = unsafe { (&(*(slice as *const [u8]))).len() };
2381        #[allow(clippy::needless_borrow)]
2382        unsafe {
2383            (self.start..len).get_unchecked(slice)
2384        }
2385    }
2386
2387    #[inline]
2388    unsafe fn get_unchecked_mut(self, slice: *mut JavaStr) -> *mut JavaStr {
2389        let len = unsafe { (&(*(slice as *mut [u8]))).len() };
2390        #[allow(clippy::needless_borrow)]
2391        unsafe {
2392            (self.start..len).get_unchecked_mut(slice)
2393        }
2394    }
2395}
2396
2397#[inline]
2398fn into_slice_range(range: RangeInclusive<usize>) -> Range<usize> {
2399    let exclusive_end = *range.end() + 1;
2400    let start = match range.end_bound() {
2401        Bound::Excluded(..) => exclusive_end, // excluded
2402        Bound::Included(..) => *range.start(),
2403        Bound::Unbounded => unreachable!(),
2404    };
2405    start..exclusive_end
2406}
2407
2408unsafe impl JavaStrSliceIndex for RangeInclusive<usize> {
2409    #[inline]
2410    fn check_bounds(&self, slice: &JavaStr) -> bool {
2411        *self.end() != usize::MAX && into_slice_range(self.clone()).check_bounds(slice)
2412    }
2413
2414    #[inline]
2415    #[track_caller]
2416    fn check_bounds_fail(self, slice: &JavaStr) -> ! {
2417        if *self.end() == usize::MAX {
2418            str_end_index_overflow_fail()
2419        } else {
2420            into_slice_range(self).check_bounds_fail(slice)
2421        }
2422    }
2423
2424    #[inline]
2425    unsafe fn get_unchecked(self, slice: *const JavaStr) -> *const JavaStr {
2426        unsafe { into_slice_range(self).get_unchecked(slice) }
2427    }
2428
2429    #[inline]
2430    unsafe fn get_unchecked_mut(self, slice: *mut JavaStr) -> *mut JavaStr {
2431        unsafe { into_slice_range(self).get_unchecked_mut(slice) }
2432    }
2433}
2434
2435unsafe impl JavaStrSliceIndex for RangeToInclusive<usize> {
2436    #[inline]
2437    fn check_bounds(&self, slice: &JavaStr) -> bool {
2438        (0..=self.end).check_bounds(slice)
2439    }
2440
2441    #[inline]
2442    fn check_bounds_fail(self, slice: &JavaStr) -> ! {
2443        (0..=self.end).check_bounds_fail(slice)
2444    }
2445
2446    #[inline]
2447    unsafe fn get_unchecked(self, slice: *const JavaStr) -> *const JavaStr {
2448        unsafe { (0..=self.end).get_unchecked(slice) }
2449    }
2450
2451    #[inline]
2452    unsafe fn get_unchecked_mut(self, slice: *mut JavaStr) -> *mut JavaStr {
2453        unsafe { (0..=self.end).get_unchecked_mut(slice) }
2454    }
2455}