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