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