Skip to main content

hipstr/
string.rs

1//! String.
2//!
3//! This module provides the [`HipStr`] type as well as the associated helper
4//! and error types.
5
6use alloc::borrow::Cow;
7use alloc::fmt;
8use alloc::string::{FromUtf16Error, String};
9use core::borrow::Borrow;
10use core::error::Error;
11use core::hash::Hash;
12use core::mem::transmute;
13use core::ops::{Deref, DerefMut, Range, RangeBounds};
14use core::str::{Lines, SplitAsciiWhitespace, SplitWhitespace, Utf8Error};
15
16use self::pattern::{DoubleEndedPattern, IterWrapper, Pattern, ReversePattern};
17use crate::bytes::{simplify_range, HipByt, SliceErrorKind as ByteSliceErrorKind};
18use crate::Backend;
19
20mod cmp;
21mod convert;
22mod pattern;
23
24#[cfg(feature = "borsh")]
25mod borsh;
26#[cfg(feature = "bstr")]
27pub(crate) mod bstr;
28#[cfg(feature = "serde")]
29pub mod serde;
30
31#[cfg(test)]
32mod tests;
33
34/// Smart string, i.e. cheaply clonable and sliceable string.
35///
36/// Internally used the same representations as [`HipByt`].
37///
38/// # Examples
39///
40/// You can create a `HipStr` from a [string slice (`&str`)][str], an owned
41/// string ([`String`], [`Box<str>`][std::boxed::Box]), or a clone-on-write smart pointer
42/// ([`Cow<str>`][std::borrow::Cow]) with [`From`]:
43///
44/// ```
45/// # use hipstr::HipStr;
46/// let hello = HipStr::from("Hello");
47/// ```
48///
49/// When possible, the `From` implementations of `HipStr` takes ownership of the
50/// underlying string buffer:
51///
52/// ```
53/// # use hipstr::HipStr;
54/// let world = HipStr::from(String::from("World")); // here the heap-allocation is reused
55/// ```
56///
57/// For borrowing string slice, you can also use the no-copy
58/// [`HipStr::borrowed`] (like [`Cow::Borrowed`](std::borrow::Cow)):
59///
60/// ```
61/// # use hipstr::HipStr;
62/// let hello = HipStr::borrowed("Hello, world!");
63/// ```
64///
65/// # Representations
66///
67/// Like `HipByt`, `HipStr` has three possible internal representations:
68///
69/// * borrow
70/// * inline string
71/// * shared heap allocated string
72#[repr(transparent)]
73pub struct HipStr<'borrow, B>(HipByt<'borrow, B>)
74where
75    B: Backend;
76
77impl<'borrow, B> HipStr<'borrow, B>
78where
79    B: Backend,
80{
81    /// Creates an empty `HipStr`.
82    ///
83    /// Function provided for [`String::new`] replacement.
84    ///
85    /// # Representation
86    ///
87    /// ⚠️ Warning! The used representation of the empty string is unspecified.
88    /// It may be *borrowed* or *inlined* but will never be allocated.
89    ///
90    /// # Examples
91    ///
92    /// Basic usage:
93    ///
94    /// ```
95    /// # use hipstr::HipStr;
96    /// let s = HipStr::new();
97    /// ```
98    #[inline]
99    #[must_use]
100    pub const fn new() -> Self {
101        Self(HipByt::new())
102    }
103
104    /// Creates a new `HipStr` with the given capacity.
105    ///
106    /// The final capacity depends on the representation and is not guaranteed
107    /// to be exact. However, the returned `HipStr` will be able to hold at
108    /// least `capacity` bytes without reallocating or changing representation.
109    ///
110    /// # Representation
111    ///
112    /// If the capacity is less or equal to the inline capacity, the
113    /// representation will be *inline*.
114    ///
115    /// Otherwise, it will be *allocated*.
116    ///
117    /// The representation is **not normalized**.
118    ///
119    /// # Examples
120    ///
121    /// Basic usage:
122    ///
123    /// ```
124    /// # use hipstr::HipStr;
125    /// let mut s = HipStr::with_capacity(42);
126    /// for _ in 0..42 {
127    ///     s.push('*');
128    /// }
129    /// assert_eq!(s, "*".repeat(42));
130    /// ```
131    #[inline]
132    #[must_use]
133    pub fn with_capacity(cap: usize) -> Self {
134        Self(HipByt::with_capacity(cap))
135    }
136
137    /// Creates a new `HipStr` from a string slice.
138    ///
139    /// No heap allocation is performed.
140    /// **The string slice is borrowed and not copied.**
141    ///
142    /// See also [`HipStr::from_static`] to ensure the borrow is `'static`.
143    ///
144    /// # Representation
145    ///
146    /// The created `HipStr` is _borrowed_.
147    ///
148    /// # Examples
149    ///
150    /// Basic usage:
151    ///
152    /// ```
153    /// # use hipstr::HipStr;
154    /// let s = HipStr::borrowed("hello");
155    /// assert_eq!(s.len(), 5);
156    /// ```
157    #[inline]
158    #[must_use]
159    pub const fn borrowed(value: &'borrow str) -> Self {
160        Self(HipByt::borrowed(value.as_bytes()))
161    }
162
163    /// Returns `true` if this `HipStr` uses the inline representation, `false` otherwise.
164    ///
165    /// # Examples
166    ///
167    /// Basic usage:
168    ///
169    /// ```
170    /// # use hipstr::HipStr;
171    /// let s = HipStr::borrowed("hello");
172    /// assert!(!s.is_inline());
173    ///
174    /// let s = HipStr::from("hello");
175    /// assert!(s.is_inline());
176    ///
177    /// let s = HipStr::from("hello".repeat(10));
178    /// assert!(!s.is_inline());
179    /// ```
180    #[inline]
181    #[must_use]
182    pub const fn is_inline(&self) -> bool {
183        self.0.is_inline()
184    }
185
186    /// Returns `true` if this `HipStr` is a string borrow, `false` otherwise.
187    ///
188    /// # Examples
189    ///
190    /// Basic usage:
191    ///
192    /// ```
193    /// # use hipstr::HipStr;
194    /// let s = HipStr::borrowed("hello");
195    /// assert!(s.is_borrowed());
196    ///
197    /// let s = HipStr::from("hello");
198    /// assert!(!s.is_borrowed());
199    ///
200    /// let s = HipStr::from("hello".repeat(10));
201    /// assert!(!s.is_borrowed());
202    /// ```
203    #[inline]
204    #[must_use]
205    pub const fn is_borrowed(&self) -> bool {
206        self.0.is_borrowed()
207    }
208
209    /// Returns `true` if this `HipStr` is a shared heap-allocated string, `false` otherwise.
210    ///
211    /// # Examples
212    ///
213    /// Basic usage:
214    ///
215    /// ```
216    /// # use hipstr::HipStr;
217    /// let s = HipStr::borrowed("hello");
218    /// assert!(!s.is_allocated());
219    ///
220    /// let s = HipStr::from("hello");
221    /// assert!(!s.is_allocated());
222    ///
223    /// let s = HipStr::from("hello".repeat(10));
224    /// assert!(s.is_allocated());
225    /// ```
226    #[inline]
227    #[must_use]
228    pub const fn is_allocated(&self) -> bool {
229        self.0.is_allocated()
230    }
231
232    /// Converts `self` into a string slice with the `'borrow` lifetime if this
233    /// `HipStr` is backed by a borrow.
234    ///
235    /// # Errors
236    ///
237    /// Returns `Err(self)` if this `HipStr` is not a borrow.
238    ///
239    /// # Examples
240    ///
241    /// Basic usage:
242    ///
243    /// ```
244    /// # use hipstr::HipStr;
245    /// let borrowed = "hipstr";
246    /// let s = HipStr::borrowed(borrowed);
247    /// let c = s.into_borrowed();
248    /// assert_eq!(c, Ok(borrowed));
249    /// assert!(std::ptr::eq(borrowed, c.unwrap()));
250    /// ```
251    #[inline]
252    pub fn into_borrowed(self) -> Result<&'borrow str, Self> {
253        self.0
254            .into_borrowed()
255            .map(|slice|
256                // SAFETY: type invariant
257                unsafe { core::str::from_utf8_unchecked(slice) })
258            .map_err(Self)
259    }
260
261    /// Returns the borrowed string slice if this `HipStr` is actually borrowed,
262    /// `None` otherwise.
263    ///
264    /// # Examples
265    ///
266    /// ```
267    /// # use hipstr::HipStr;
268    /// static S: &str = "abc";
269    /// let s = HipStr::borrowed(S);
270    /// let c: Option<&'static str> = s.as_borrowed();
271    /// assert_eq!(c, Some(S));
272    /// assert!(std::ptr::eq(S, c.unwrap()));
273    ///
274    /// let s2 = HipStr::from(S);
275    /// assert!(s2.as_borrowed().is_none());
276    /// ```
277    #[inline]
278    #[must_use]
279    pub const fn as_borrowed(&self) -> Option<&'borrow str> {
280        match self.0.as_borrowed() {
281            Some(slice) => Some(unsafe {
282                // SAFETY: type invariant
283                core::str::from_utf8_unchecked(slice)
284            }),
285            None => None,
286        }
287    }
288
289    /// Returns the length of this `HipStr`, in bytes, not [`char`]s or
290    /// graphemes. In other words, it might not be what a human considers the
291    /// length of the string.
292    ///
293    /// # Examples
294    ///
295    /// Basic usage:
296    ///
297    /// ```
298    /// # use hipstr::HipStr;
299    /// let a = HipStr::from("(c)");
300    /// assert_eq!(a.len(), 3);
301    ///
302    /// let b = HipStr::from("®");
303    /// assert_eq!(b.len(), 2);
304    /// assert_eq!(b.chars().count(), 1);
305    /// ```
306    #[inline]
307    #[must_use]
308    pub const fn len(&self) -> usize {
309        self.0.len()
310    }
311
312    /// Returns `true` if this `HipStr` has a length of zero, and `false` otherwise.
313    ///
314    /// # Examples
315    ///
316    /// Basic usage:
317    ///
318    /// ```
319    /// # use hipstr::HipStr;
320    /// let a = HipStr::new();
321    /// assert!(a.is_empty());
322    ///
323    /// let b = HipStr::borrowed("ab");
324    /// assert!(!b.is_empty());
325    /// ```
326    #[inline]
327    #[must_use]
328    pub const fn is_empty(&self) -> bool {
329        self.0.is_empty()
330    }
331
332    /// Extracts a raw pointer out of the `HipStr`.
333    ///
334    /// As strings are ultimately sequence of bytes, the raw pointer points to a
335    /// [`u8`]. This pointer will be pointing to the first byte of the string.
336    ///
337    /// It is your responsibility to make sure that:
338    ///
339    /// - This `HipStr` outlives the pointer this function returns.
340    ///
341    /// - This `HipStr` is not modified in another way before the use of the
342    ///   pointer. Modifying the byte sequence may change representation or
343    ///   reallocate, which would invalid the returned pointer.
344    ///
345    /// - The returned pointer is never written to. If you need to mutate the
346    ///   contents of the string slice, use [`as_mut_ptr`].
347    ///
348    /// [`as_mut_ptr`]: Self::as_mut_ptr
349    ///
350    /// # Examples
351    ///
352    /// ```
353    /// # use hipstr::HipStr;
354    /// let s = HipStr::from("Hello");
355    /// let ptr = s.as_ptr();
356    /// ```
357    #[inline]
358    #[must_use]
359    pub const fn as_ptr(&self) -> *const u8 {
360        self.0.as_ptr()
361    }
362
363    /// Extracts a mutable raw pointer out of this `HipStr` if it is not shared
364    /// or borrowed, `None` otherwise.
365    ///
366    /// As strings are ultimately sequence of bytes, the raw pointer points to
367    /// a [`u8`]. This pointer will be pointing to the first byte of the string.
368    ///
369    /// It is your responsibility to make sure that:
370    ///
371    /// - This `HipStr` outlives the pointer this function returns.
372    ///
373    /// - This `HipStr` is not modified in another way before the use of the
374    ///   pointer. Modifying the byte sequence may change representation or
375    ///   reallocate, which would invalid the returned pointer.
376    ///
377    /// - The byte sequence gets modified in a way that it remains valid UTF-8.
378    #[inline]
379    #[must_use]
380    pub fn as_mut_ptr(&mut self) -> Option<*mut u8> {
381        self.0.as_mut_ptr()
382    }
383
384    /// Extracts a mutable raw pointer out of this `HipStr`.
385    ///
386    /// As strings are ultimately sequence of bytes, the raw pointer points to
387    /// a [`u8`]. This pointer will be pointing to the first byte of the string.
388    ///
389    /// It is your responsibility to make sure that:
390    ///
391    /// - This `HipStr` outlives the pointer this function returns.
392    ///
393    /// - This `HipStr` is not modified in another way before the use of the
394    ///   pointer. Modifying the byte sequence may change representation or
395    ///   reallocate, which would invalid the returned pointer.
396    ///
397    /// - The byte sequence gets modified in a way that it remains valid UTF-8.
398    ///
399    /// # Safety
400    ///
401    /// The caller must ensure the sequence is actually unique: not shared and
402    /// not borrowed.
403    ///
404    /// # Panics
405    ///
406    /// In debug mode, this function panics if the sequence is borrowed or
407    /// shared.
408    #[inline]
409    #[must_use]
410    pub unsafe fn as_mut_ptr_unchecked(&mut self) -> *mut u8 {
411        unsafe { self.0.as_mut_ptr_unchecked() }
412    }
413
414    /// Converts a `HipStr` into a `HipByt`.
415    ///
416    /// It consumes the `HipStr` without copying the content
417    /// (if [shared][HipByt::is_allocated] or [static][HipByt::is_borrowed]).
418    ///
419    /// # Examples
420    ///
421    /// Basic usage:
422    ///
423    /// ```
424    /// # use hipstr::HipStr;
425    /// let s = HipStr::from("hello");
426    /// let b = s.into_bytes();
427    ///
428    /// assert_eq!(&[104, 101, 108, 108, 111][..], &b[..]);
429    /// ```
430    #[must_use]
431    pub fn into_bytes(self) -> HipByt<'borrow, B> {
432        self.0
433    }
434
435    /// Extracts a string slice of the entire `HipStr`.
436    ///
437    /// # Examples
438    ///
439    /// Basic usage:
440    ///
441    /// ```
442    /// # use hipstr::HipStr;
443    /// let s = HipStr::from("foobar");
444    ///
445    /// assert_eq!("foobar", s.as_str());
446    /// ```
447    #[inline]
448    #[must_use]
449    pub const fn as_str(&self) -> &str {
450        let slice = self.0.as_slice();
451        // SAFETY: type invariant
452        unsafe { core::str::from_utf8_unchecked(slice) }
453    }
454
455    /// Extracts a mutable string slice of the entire `HipStr` if possible.
456    ///
457    /// # Examples
458    ///
459    /// Basic usage:
460    ///
461    /// ```
462    /// # use hipstr::HipStr;
463    /// let mut s = HipStr::from("foo");
464    /// let slice = s.as_mut_str().unwrap();
465    /// slice.make_ascii_uppercase();
466    /// assert_eq!("FOO", slice);
467    /// ```
468    #[inline]
469    #[must_use]
470    pub fn as_mut_str(&mut self) -> Option<&mut str> {
471        self.0.as_mut_slice().map(|slice|
472                // SAFETY: type invariant
473                unsafe { core::str::from_utf8_unchecked_mut(slice) })
474    }
475
476    /// Extracts a mutable string slice of the entire `HipStr` changing the
477    /// representation (and thus _potentially reallocating_) if the current
478    /// representation cannot be mutated.
479    ///
480    /// # Examples
481    ///
482    /// Basic usage:
483    ///
484    /// ```
485    /// # use hipstr::HipStr;
486    /// let mut s = HipStr::borrowed("foo");
487    /// let slice = s.to_mut_str();
488    /// slice.make_ascii_uppercase();
489    /// assert_eq!("FOO", slice);
490    /// ```
491    #[inline]
492    #[doc(alias = "make_mut")]
493    pub fn to_mut_str(&mut self) -> &mut str {
494        let slice = self.0.to_mut_slice();
495        // SAFETY: type invariant
496        unsafe { core::str::from_utf8_unchecked_mut(slice) }
497    }
498
499    /// Extracts a slice as its own `HipStr`.
500    ///
501    /// # Panics
502    ///
503    /// Panics if the range is invalid: out of bounds or not at char boundaries.
504    ///
505    /// # Examples
506    ///
507    /// Basic usage:
508    ///
509    /// ```
510    /// # use hipstr::HipStr;
511    /// let a = HipStr::from("abc");
512    /// assert_eq!(a.slice(0..2), HipStr::from("ab"));
513    /// ```
514    #[must_use]
515    #[track_caller]
516    pub fn slice(&self, range: impl RangeBounds<usize>) -> Self {
517        match self.try_slice(range) {
518            Ok(result) => result,
519            Err(err) => panic!("{}", err),
520        }
521    }
522
523    /// Returns a `HipStr` of a range of bytes in this `HipStr`, if the range is
524    /// valid and at char boundaries.
525    ///
526    /// # Errors
527    ///
528    /// This function will return an error if the range is invalid or if the
529    /// range is not at char boundaries.
530    ///
531    /// # Examples
532    ///
533    /// Basic usage:
534    ///
535    /// ```
536    /// # use hipstr::HipStr;
537    /// let a = HipStr::from("Rust \u{1F980}");
538    /// assert_eq!(a.try_slice(0..4), Ok(HipStr::from("Rust")));
539    /// assert!(a.try_slice(5..6).is_err());
540    /// ```
541    pub fn try_slice(&self, range: impl RangeBounds<usize>) -> Result<Self, SliceError<B>> {
542        let range = simplify_range(range, self.len())
543            .map_err(|(start, end, kind)| SliceError::new(kind, start, end, self))?;
544
545        if !self.is_char_boundary(range.start) {
546            return Err(SliceError {
547                kind: SliceErrorKind::StartNotACharBoundary,
548                start: range.start,
549                end: range.end,
550                string: self,
551            });
552        }
553
554        if !self.is_char_boundary(range.end) {
555            return Err(SliceError {
556                kind: SliceErrorKind::EndNotACharBoundary,
557                start: range.start,
558                end: range.end,
559                string: self,
560            });
561        }
562
563        // SAFETY: range and char boundaries checked above
564        Ok(unsafe { self.slice_unchecked(range) })
565    }
566
567    /// Extracts a slice as its own `HipStr`.
568    ///
569    /// # Safety
570    ///
571    /// `range` must be a equivalent to some `a..b` with `a <= b <= len`.
572    /// Also, both ends should be **character boundaries**.
573    /// UB in release mode.
574    ///
575    /// # Panics
576    ///
577    /// Panics in debug mode if the safety condition is not ensured.
578    #[must_use]
579    pub unsafe fn slice_unchecked(&self, range: impl RangeBounds<usize>) -> Self {
580        #[cfg(debug_assertions)]
581        {
582            let range =
583                simplify_range((range.start_bound(), range.end_bound()), self.len()).unwrap();
584            assert!(self.is_char_boundary(range.start));
585            assert!(self.is_char_boundary(range.end));
586        }
587        Self(unsafe { self.0.slice_unchecked(range) })
588    }
589
590    /// Extracts a slice as its own `HipStr` based on the given subslice `&str`.
591    ///
592    /// # Panics
593    ///
594    /// Panics if `slice` is not part of `self`.
595    ///
596    /// # Examples
597    ///
598    /// Basic usage:
599    ///
600    /// ```
601    /// # use hipstr::HipStr;
602    /// let a = HipStr::from("abc");
603    /// let sl = &a[0..2];
604    /// assert_eq!(a.slice_ref(sl), HipStr::from("ab"));
605    /// ```
606    #[must_use]
607    #[track_caller]
608    pub fn slice_ref(&self, slice: &str) -> Self {
609        let Some(result) = self.try_slice_ref(slice) else {
610            panic!("slice {slice:p} is not a part of {self:p}")
611        };
612        result
613    }
614
615    /// Extracts a slice as its own `HipStr` based on the given subslice `&str`.
616    ///
617    /// # Safety
618    ///
619    /// The slice MUST be a part of this `HipStr`.
620    #[must_use]
621    pub unsafe fn slice_ref_unchecked(&self, slice: &str) -> Self {
622        let slice = slice.as_bytes();
623        unsafe { Self(self.0.slice_ref_unchecked(slice)) }
624    }
625
626    /// Returns a slice as it own `HipStr` based on the given subslice `&str`.
627    ///
628    /// # Errors
629    ///
630    /// Returns `None` if `slice` is not a part of `self`.
631    ///
632    /// # Examples
633    ///
634    /// Basic usage:
635    ///
636    /// ```
637    /// # use hipstr::HipStr;
638    /// let a = HipStr::from("abc");
639    /// let sl = &a[0..2];
640    /// assert_eq!(a.try_slice_ref(sl), Some(HipStr::from("ab")));
641    /// assert!(a.try_slice_ref("z").is_none());
642    /// ```
643    pub fn try_slice_ref(&self, range: &str) -> Option<Self> {
644        self.0.try_slice_ref(range.as_bytes()).map(Self)
645    }
646
647    /// Decodes a UTF-16–encoded vector `v` into a `HipStr`.
648    ///
649    /// # Errors
650    ///
651    /// Returns an [`FromUtf16Error`] if `v` contains any invalid data.
652    ///
653    /// [`FromUtf16Error`]: std::string::FromUtf16Error
654    ///
655    /// # Examples
656    ///
657    /// Basic usage:
658    ///
659    /// ```
660    /// # use hipstr::HipStr;
661    /// // 𝄞music
662    /// let v = &[0xD834, 0xDD1E, 0x006d, 0x0075,
663    ///           0x0073, 0x0069, 0x0063];
664    /// assert_eq!(HipStr::from("𝄞music"),
665    ///            HipStr::from_utf16(v).unwrap());
666    ///
667    /// // 𝄞mu<invalid>ic
668    /// let v = &[0xD834, 0xDD1E, 0x006d, 0x0075,
669    ///           0xD800, 0x0069, 0x0063];
670    /// assert!(HipStr::from_utf16(v).is_err());
671    /// ```
672    #[inline]
673    pub fn from_utf16(v: &[u16]) -> Result<Self, FromUtf16Error> {
674        String::from_utf16(v).map(Into::into)
675    }
676
677    /// Decodes a UTF-16–encoded slice `v` into a `HipStr`, replacing
678    /// invalid data with [the replacement character (`U+FFFD`)][U+FFFD].
679    ///
680    /// [U+FFFD]: core::char::REPLACEMENT_CHARACTER
681    ///
682    /// # Examples
683    ///
684    /// Basic usage:
685    ///
686    /// ```
687    /// # use hipstr::HipStr;
688    /// // 𝄞mus<invalid>ic<invalid>
689    /// let v = &[0xD834, 0xDD1E, 0x006d, 0x0075,
690    ///           0x0073, 0xDD1E, 0x0069, 0x0063,
691    ///           0xD834];
692    ///
693    /// assert_eq!("𝄞mus\u{FFFD}ic\u{FFFD}",
694    ///            HipStr::from_utf16_lossy(v));
695    /// ```
696    #[inline]
697    #[must_use]
698    pub fn from_utf16_lossy(v: &[u16]) -> Self {
699        String::from_utf16_lossy(v).into()
700    }
701
702    /// Converts a [`HipByt`] to a `HipStr` without checking that the
703    /// string contains valid UTF-8.
704    ///
705    /// See the safe version, [`from_utf8`](HipStr::from_utf8), for more details.
706    ///
707    /// # Safety
708    ///
709    /// This function is unsafe because it does not check that the bytes passed
710    /// to it are valid UTF-8. If this constraint is violated, it may cause
711    /// memory unsafety issues with future users of the `HipStr`, as the rest of
712    /// the library assumes that `HipStr`s are valid UTF-8.
713    ///
714    /// # Examples
715    ///
716    /// Basic usage:
717    ///
718    /// ```
719    /// // some bytes, in a vector
720    /// let sparkle_heart = vec![240, 159, 146, 150];
721    ///
722    /// let sparkle_heart = unsafe {
723    ///     String::from_utf8_unchecked(sparkle_heart)
724    /// };
725    ///
726    /// assert_eq!("💖", sparkle_heart);
727    /// ```
728    #[inline]
729    #[must_use]
730    pub const unsafe fn from_utf8_unchecked(byt: HipByt<'borrow, B>) -> Self {
731        Self(byt)
732    }
733
734    /// Converts a [`HipByt`] (a sequence of bytes) to a `HipStr`.
735    ///
736    /// Both [`HipByt`] and [`HipStr`] are made of bytes, so this function
737    /// converts between the two without any coping allocated data. However, not
738    /// all byte sequence are valid strings: `HipStr` (like `std`'s [`String`])
739    /// requires that it is valid UTF-8. `from_utf8()` checks to ensure that
740    /// the bytes are valid UTF-8, and then does the conversion.
741    ///
742    /// If you are sure that the byte slice is valid UTF-8, and you don't want
743    /// to incur the overhead of the validity check, there is an unsafe version
744    /// of this function, [`from_utf8_unchecked`], which has the same behavior
745    /// but skips the check.
746    ///
747    /// The inverse of this method is [`into_bytes`].
748    ///
749    /// # Errors
750    ///
751    /// Returns [`Err`] if the slice is not UTF-8 with a description as to why the
752    /// provided bytes are not UTF-8. The vector you moved in is also included.
753    ///
754    /// # Examples
755    ///
756    /// Basic usage:
757    ///
758    /// ```
759    /// # use hipstr::{HipByt, HipStr};
760    /// // some bytes, in a vector
761    /// let sparkle_heart = HipByt::borrowed(&[240, 159, 146, 150]);
762    ///
763    /// // We know these bytes are valid, so we'll use `unwrap()`.
764    /// let sparkle_heart = HipStr::from_utf8(sparkle_heart).unwrap();
765    ///
766    /// assert_eq!("💖", sparkle_heart);
767    /// ```
768    ///
769    /// Incorrect bytes:
770    ///
771    /// ```
772    /// # use hipstr::{HipByt, HipStr};
773    /// // some invalid bytes, in a vector
774    /// let sparkle_heart = HipByt::borrowed(&[0, 159, 146, 150]);
775    ///
776    /// assert!(HipStr::from_utf8(sparkle_heart).is_err());
777    /// ```
778    ///
779    /// See the docs for [`FromUtf8Error`] for more details on what you can do
780    /// with this error.
781    ///
782    /// [`from_utf8_unchecked`]: HipStr::from_utf8_unchecked
783    /// [`into_bytes`]: HipStr::into_bytes
784    #[inline]
785    pub const fn from_utf8(bytes: HipByt<'borrow, B>) -> Result<Self, FromUtf8Error<'borrow, B>> {
786        match core::str::from_utf8(bytes.as_slice()) {
787            Ok(_) => {
788                // SAFETY: checked above
789                Ok(unsafe { Self::from_utf8_unchecked(bytes) })
790            }
791            Err(e) => Err(FromUtf8Error { bytes, error: e }),
792        }
793    }
794
795    /// Converts a [`HipByt`] to a `HipStr`, including invalid characters.
796    ///
797    /// Strings are made of bytes ([`u8`]). However, not all byte sequences are
798    /// valid strings: strings are required to be valid UTF-8. During this
799    /// conversion, `from_utf8_lossy()` will replace any invalid UTF-8 sequences
800    /// with [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD], which looks like this: �
801    ///
802    /// [U+FFFD]: core::char::REPLACEMENT_CHARACTER
803    ///
804    /// If you are sure that the byte slice is valid UTF-8, and you don't want
805    /// to incur the overhead of the conversion, there is an unsafe version
806    /// of this function, [`from_utf8_unchecked`], which has the same behavior
807    /// but skips the checks.
808    ///
809    /// [`from_utf8_unchecked`]: HipStr::from_utf8_unchecked
810    ///
811    /// If our byte sequence is invalid UTF-8, then we need to insert the
812    /// replacement characters, which will change the size of the string, and
813    /// hence, require to allocate a new string. But if it's already valid
814    /// UTF-8, we don't need a new allocation and the output reuses the
815    /// allocated data of the source.
816    ///
817    /// # Examples
818    ///
819    /// Basic usage:
820    ///
821    /// ```
822    /// # use hipstr::{HipByt, HipStr};
823    /// // some bytes, in a vector
824    /// let sparkle_heart = HipByt::from(vec![240, 159, 146, 150]);
825    ///
826    /// let sparkle_heart = HipStr::from_utf8_lossy(sparkle_heart);
827    ///
828    /// assert_eq!("💖", sparkle_heart);
829    /// ```
830    ///
831    /// Incorrect bytes:
832    ///
833    /// ```
834    /// # use hipstr::{HipByt, HipStr};
835    /// // some invalid bytes
836    /// let input = HipByt::borrowed(b"Hello \xF0\x90\x80World");
837    /// let output = HipStr::from_utf8_lossy(input);
838    ///
839    /// assert_eq!("Hello �World", output);
840    /// ```
841    #[inline]
842    #[must_use]
843    pub fn from_utf8_lossy(bytes: HipByt<'borrow, B>) -> Self {
844        match String::from_utf8_lossy(&bytes) {
845            Cow::Borrowed(_) => Self(bytes),
846            Cow::Owned(s) => Self::from(s),
847        }
848    }
849
850    /// Returns the maximal length (in bytes) of inline string.
851    #[inline]
852    #[must_use]
853    pub const fn inline_capacity() -> usize {
854        HipByt::<B>::inline_capacity()
855    }
856
857    /// Returns the total number of bytes the backend can hold.
858    ///
859    /// # Example
860    ///
861    /// ```
862    /// # use hipstr::HipStr;
863    /// let mut s: String = String::with_capacity(42);
864    /// s.extend('a'..='z');
865    /// let string = HipStr::from(s);
866    /// assert_eq!(string.len(), 26);
867    /// assert_eq!(string.capacity(), 42);
868    ///
869    /// let string2 = string.clone();
870    /// assert_eq!(string.capacity(), 42);
871    /// ```
872    #[inline]
873    #[must_use]
874    pub fn capacity(&self) -> usize {
875        self.0.capacity()
876    }
877
878    /// Converts `self` into a [`String`] without clone or allocation if possible.
879    ///
880    /// # Errors
881    ///
882    /// Returns `Err(self)` if it is impossible to take ownership of the string
883    /// backing this `HipStr`.
884    #[inline]
885    pub fn into_string(self) -> Result<String, Self> {
886        self.0
887            .into_vec()
888            // SAFETY: type invariant
889            .map(|v| unsafe { String::from_utf8_unchecked(v) })
890            .map_err(Self)
891    }
892
893    /// Returns a mutable handle to the underlying [`String`].
894    ///
895    /// This operation may reallocate a new string if either:
896    ///
897    /// - the representation is not _allocated_ (i.e. _inline_ or _borrowed_),
898    /// - the underlying buffer is shared.
899    ///
900    /// At the end, when the [`RefMut`] is dropped, the underlying
901    /// representation will be owned and normalized. That is, if the actual
902    /// required capacity is less than or equal to the maximal inline capacity,
903    /// the representation is _inline_; otherwise, the representation is
904    /// _allocated_.
905    ///
906    /// # Examples
907    ///
908    /// ```rust
909    /// # use hipstr::HipStr;
910    /// let mut s = HipStr::borrowed("abc");
911    /// {
912    ///     let mut r = s.mutate();
913    ///     r.push_str("def");
914    ///     assert_eq!(r.as_str(), "abcdef");
915    /// }
916    /// assert_eq!(s, "abcdef");
917    /// ```
918    #[inline]
919    #[must_use]
920    pub fn mutate(&mut self) -> RefMut<'_, 'borrow, B> {
921        let vec = self.0.take_vec();
922        // SAFETY: type invariant
923        let owned = unsafe { String::from_utf8_unchecked(vec) };
924        RefMut {
925            result: self,
926            owned,
927        }
928    }
929
930    /// Shortens this string to the specified length.
931    ///
932    /// If `new_len` is greater than the string's current length, this has no
933    /// effect.
934    ///
935    /// # Panics
936    ///
937    /// Panics if `new_len` is not a char boundary.
938    ///
939    /// # Examples
940    /// ```
941    /// # use hipstr::HipStr;
942    /// let mut s = HipStr::from("abc");
943    /// s.truncate(1);
944    /// assert_eq!(s, "a");
945    /// ```
946    #[inline]
947    pub fn truncate(&mut self, new_len: usize) {
948        if new_len <= self.len() {
949            assert!(self.is_char_boundary(new_len), "char boundary");
950            self.0.truncate(new_len);
951        }
952    }
953
954    /// Truncates this `HipStr`, removing all contents.
955    ///
956    /// # Examples
957    ///
958    /// ```
959    /// # use hipstr::HipStr;
960    /// let mut s = HipStr::from("foo");
961    ///
962    /// s.clear();
963    ///
964    /// assert!(s.is_empty());
965    /// assert_eq!(0, s.len());
966    /// ```
967    #[inline]
968    pub fn clear(&mut self) {
969        self.0.clear();
970    }
971
972    /// Shrinks the capacity of the string as much as possible.
973    ///
974    /// The capacity will remain at least as large as the actual length of the
975    /// string.
976    ///
977    /// No-op if the representation is not allocated.
978    ///
979    /// # Representation stability
980    ///
981    /// The allocated representation may change to *inline* if the required
982    /// capacity is smaller than the inline capacity.
983    ///
984    /// # Examples
985    ///
986    /// ```rust
987    /// # use hipstr::HipStr;
988    /// let mut s = HipStr::with_capacity(100);
989    /// s.push_str("abc");
990    /// s.shrink_to_fit();
991    /// assert_eq!(s.capacity(), HipStr::inline_capacity());
992    /// ```
993    #[inline]
994    pub fn shrink_to_fit(&mut self) {
995        self.0.shrink_to_fit();
996    }
997
998    /// Shrinks the capacity of the string with a lower bound.
999    ///
1000    /// The capacity will remain at least as large as the given lower bound and
1001    /// the actual length of the string.
1002    ///
1003    /// No-op if the representation is not allocated.
1004    ///
1005    /// # Representation stability
1006    ///
1007    /// The allocated representation may change to *inline* if the required
1008    /// capacity is smaller than the inline capacity.
1009    ///
1010    /// # Examples
1011    ///
1012    /// ```rust
1013    /// # use hipstr::HipStr;
1014    /// let mut s = HipStr::with_capacity(100);
1015    /// s.shrink_to(4);
1016    /// assert_eq!(s.capacity(), HipStr::inline_capacity());
1017    /// ```
1018    #[inline]
1019    pub fn shrink_to(&mut self, min_capacity: usize) {
1020        self.0.shrink_to(min_capacity);
1021    }
1022
1023    /// Removes the last character from the string and returns it.
1024    ///
1025    /// Returns `None` if the string is empty.
1026    ///
1027    /// # Examples
1028    ///
1029    /// ```
1030    /// # use hipstr::HipStr;
1031    /// let mut s = HipStr::from("abc");
1032    /// assert_eq!(s.pop(), Some('c'));
1033    /// assert_eq!(s, "ab");
1034    /// ```
1035    #[inline]
1036    pub fn pop(&mut self) -> Option<char> {
1037        let (i, ch) = self.as_str().char_indices().next_back()?;
1038        self.truncate(i);
1039        Some(ch)
1040    }
1041
1042    /// Appends a given string slice onto the end of this `HipStr`.
1043    ///
1044    /// # Examples
1045    ///
1046    /// Basic usage:
1047    ///
1048    /// ```
1049    /// # use hipstr::HipStr;
1050    /// let mut s = HipStr::from("cork");
1051    /// s.push_str("screw");
1052    /// assert_eq!(s, "corkscrew");
1053    /// ```
1054    #[inline]
1055    pub fn push_str(&mut self, addition: &str) {
1056        self.0.push_slice(addition.as_bytes());
1057    }
1058
1059    /// Appends the given [`char`] to the end of this `HipStr`.
1060    ///
1061    /// # Examples
1062    ///
1063    /// Basic usage:
1064    ///
1065    /// ```
1066    /// # use hipstr::HipStr;
1067    /// let mut s = HipStr::from("abc");
1068    ///
1069    /// s.push('1');
1070    /// s.push('2');
1071    /// s.push('3');
1072    ///
1073    /// assert_eq!(s, "abc123");
1074    /// ```
1075    #[inline]
1076    pub fn push(&mut self, ch: char) {
1077        let mut data = [0; 4];
1078        let s = ch.encode_utf8(&mut data);
1079        self.0.push_slice(s.as_bytes());
1080    }
1081
1082    /// Makes the string owned, copying the data if it is actually borrowed.
1083    ///
1084    /// ```
1085    /// # use hipstr::HipStr;
1086    /// let s: String = ('a'..'z').collect();
1087    /// let h = HipStr::borrowed(&s[..]);
1088    /// // drop(s); // err, s is borrowed
1089    /// let h = h.into_owned();
1090    /// drop(s); // ok
1091    /// assert_eq!(h, ('a'..'z').collect::<String>());
1092    /// ```
1093    #[must_use]
1094    pub fn into_owned(self) -> HipStr<'static, B> {
1095        HipStr(self.0.into_owned())
1096    }
1097
1098    /// Returns a copy of this string where each character is mapped to its
1099    /// ASCII lower case equivalent.
1100    ///
1101    /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
1102    /// but non-ASCII letters are unchanged.
1103    ///
1104    /// To lowercase the value in-place, use [`make_ascii_lowercase`].
1105    ///
1106    /// To lowercase ASCII characters in addition to non-ASCII characters, use
1107    /// [`to_lowercase`].
1108    ///
1109    /// # Examples
1110    ///
1111    /// ```
1112    /// # use hipstr::HipStr;
1113    /// let s = HipStr::from("Grüße, Jürgen ❤");
1114    ///
1115    /// assert_eq!("grüße, jürgen ❤", s.to_ascii_lowercase());
1116    /// ```
1117    ///
1118    /// [`make_ascii_lowercase`]: Self::make_ascii_lowercase
1119    /// [`to_lowercase`]: Self::to_lowercase
1120    #[inline]
1121    #[must_use]
1122    pub fn to_ascii_lowercase(&self) -> Self {
1123        // SAFETY: changing ASCII letters only does not invalidate UTF-8.
1124        Self(self.0.to_ascii_lowercase())
1125    }
1126
1127    /// Returns a copy of this string where each character is mapped to its
1128    /// ASCII upper case equivalent.
1129    ///
1130    /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
1131    /// but non-ASCII letters are unchanged.
1132    ///
1133    /// To uppercase the value in-place, use [`make_ascii_uppercase`].
1134    ///
1135    /// To uppercase ASCII characters in addition to non-ASCII characters, use
1136    /// [`to_uppercase`].
1137    ///
1138    /// # Examples
1139    ///
1140    /// ```
1141    /// # use hipstr::HipStr;
1142    /// let s = HipStr::from("Grüße, Jürgen ❤");
1143    ///
1144    /// assert_eq!("GRüßE, JüRGEN ❤", s.to_ascii_uppercase());
1145    /// ```
1146    ///
1147    /// [`make_ascii_uppercase`]: Self::make_ascii_uppercase
1148    /// [`to_uppercase`]: Self::to_uppercase
1149    #[inline]
1150    #[must_use]
1151    pub fn to_ascii_uppercase(&self) -> Self {
1152        // SAFETY: changing ASCII letters only does not invalidate UTF-8.
1153        Self(self.0.to_ascii_uppercase())
1154    }
1155
1156    /// Converts this string to its ASCII upper case equivalent in-place.
1157    ///
1158    /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
1159    /// but non-ASCII letters are unchanged.
1160    ///
1161    /// To return a new uppercased value without modifying the existing one, use
1162    /// [`to_ascii_uppercase`].
1163    ///
1164    /// [`to_ascii_uppercase`]: Self::to_ascii_uppercase
1165    ///
1166    /// # Examples
1167    ///
1168    /// ```
1169    /// let mut s = String::from("Grüße, Jürgen ❤");
1170    ///
1171    /// s.make_ascii_uppercase();
1172    ///
1173    /// assert_eq!("GRüßE, JüRGEN ❤", s);
1174    /// ```
1175    #[inline]
1176    pub fn make_ascii_uppercase(&mut self) {
1177        // SAFETY: changing ASCII letters only does not invalidate UTF-8.
1178        self.0.make_ascii_uppercase();
1179    }
1180
1181    /// Converts this string to its ASCII lower case equivalent in-place.
1182    ///
1183    /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
1184    /// but non-ASCII letters are unchanged.
1185    ///
1186    /// To return a new lowercased value without modifying the existing one, use
1187    /// [`to_ascii_lowercase`].
1188    ///
1189    /// [`to_ascii_lowercase`]: Self::to_ascii_lowercase
1190    ///
1191    /// # Examples
1192    ///
1193    /// ```
1194    /// # use hipstr::HipStr;
1195    /// let mut s = HipStr::from("GRÜßE, JÜRGEN ❤");
1196    ///
1197    /// s.make_ascii_lowercase();
1198    ///
1199    /// assert_eq!("grÜße, jÜrgen ❤", s);
1200    /// ```
1201    #[inline]
1202    pub fn make_ascii_lowercase(&mut self) {
1203        // SAFETY: changing ASCII letters only does not invalidate UTF-8.
1204        self.0.make_ascii_lowercase();
1205    }
1206
1207    /// Returns the lowercase equivalent of this string, as a new `HipStr`.
1208    ///
1209    /// 'Lowercase' is defined according to the terms of the Unicode Derived Core Property
1210    /// `Lowercase`.
1211    ///
1212    /// Since some characters can expand into multiple characters when changing
1213    /// the case, this function returns a [`String`] instead of modifying the
1214    /// parameter in-place.
1215    ///
1216    /// # Examples
1217    ///
1218    /// Basic usage:
1219    ///
1220    /// ```
1221    /// # use hipstr::HipStr;
1222    /// let s = HipStr::from("HELLO");
1223    ///
1224    /// assert_eq!("hello", s.to_lowercase());
1225    /// ```
1226    ///
1227    /// A tricky example, with sigma:
1228    ///
1229    /// ```
1230    /// # use hipstr::HipStr;
1231    /// let sigma = HipStr::from("Σ");
1232    ///
1233    /// assert_eq!("σ", sigma.to_lowercase());
1234    ///
1235    /// // but at the end of a word, it's ς, not σ:
1236    /// let odysseus = HipStr::from("ὈΔΥΣΣΕΎΣ");
1237    ///
1238    /// assert_eq!("ὀδυσσεύς", odysseus.to_lowercase());
1239    /// ```
1240    ///
1241    /// Languages without case are not changed:
1242    ///
1243    /// ```
1244    /// # use hipstr::HipStr;
1245    /// let new_year = HipStr::from("农历新年");
1246    ///
1247    /// assert_eq!(new_year, new_year.to_lowercase());
1248    /// ```
1249    #[inline]
1250    #[must_use]
1251    pub fn to_lowercase(&self) -> Self {
1252        Self::from(self.as_str().to_lowercase())
1253    }
1254
1255    /// Returns the uppercase equivalent of this string, as a new `HipStr`.
1256    ///
1257    /// 'Uppercase' is defined according to the terms of the Unicode Derived Core Property
1258    /// `Uppercase`.
1259    ///
1260    /// Since some characters can expand into multiple characters when changing
1261    /// the case, this function returns a [`String`] instead of modifying the
1262    /// parameter in-place.
1263    ///
1264    /// # Examples
1265    ///
1266    /// Basic usage:
1267    ///
1268    /// ```
1269    /// # use hipstr::HipStr;
1270    /// let s = HipStr::from("hello");
1271    ///
1272    /// assert_eq!("HELLO", s.to_uppercase());
1273    /// ```
1274    ///
1275    /// Scripts without case are not changed:
1276    ///
1277    /// ```
1278    /// # use hipstr::HipStr;
1279    /// let new_year = HipStr::from("农历新年");
1280    ///
1281    /// assert_eq!(new_year, new_year.to_uppercase());
1282    /// ```
1283    ///
1284    /// One character can become multiple:
1285    ///
1286    /// ```
1287    /// # use hipstr::HipStr;
1288    /// let s = HipStr::from("tschüß");
1289    ///
1290    /// assert_eq!("TSCHÜSS", s.to_uppercase());
1291    /// ```
1292    #[inline]
1293    #[must_use]
1294    pub fn to_uppercase(&self) -> Self {
1295        Self::from(self.as_str().to_uppercase())
1296    }
1297
1298    /// Creates a new `HipStr` by repeating this one `n` times.
1299    ///
1300    /// # Panics
1301    ///
1302    /// This function will panic if the capacity would overflow.
1303    ///
1304    /// # Examples
1305    ///
1306    /// Basic usage:
1307    ///
1308    /// ```
1309    /// # use hipstr::HipStr;
1310    /// assert_eq!(HipStr::from("abc").repeat(4), HipStr::from("abcabcabcabc"));
1311    /// ```
1312    ///
1313    /// A panic upon overflow:
1314    ///
1315    /// ```should_panic
1316    /// # use hipstr::HipStr;
1317    /// // this will panic at runtime
1318    /// let huge = HipStr::from("0123456789abcdef").repeat(usize::MAX);
1319    /// ```
1320    #[inline]
1321    #[must_use]
1322    pub fn repeat(&self, n: usize) -> Self {
1323        Self(self.0.repeat(n))
1324    }
1325
1326    /// Returns a string with leading and trailing whitespace removed.
1327    ///
1328    /// 'Whitespace' is defined according to the terms of the Unicode Derived
1329    /// Core Property `White_Space`, which includes newlines.
1330    ///
1331    /// # Examples
1332    ///
1333    /// ```
1334    /// # use hipstr::HipStr;
1335    /// let s = HipStr::from("\n Hello\tworld\t\n");
1336    ///
1337    /// assert_eq!("Hello\tworld", s.trim());
1338    /// ```
1339    #[inline]
1340    #[must_use]
1341    pub fn trim(&self) -> Self {
1342        let s = self.as_str().trim();
1343        unsafe { self.slice_ref_unchecked(s) }
1344    }
1345
1346    /// Returns a string with leading whitespace removed.
1347    ///
1348    /// 'Whitespace' is defined according to the terms of the Unicode Derived
1349    /// Core Property `White_Space`, which includes newlines.
1350    ///
1351    /// # Examples
1352    ///
1353    /// ```
1354    /// # use hipstr::HipStr;
1355    /// let s = HipStr::from("\n Hello\tworld\t\n");
1356    ///
1357    /// assert_eq!("Hello\tworld\t\n", s.trim_start());
1358    /// ```
1359    #[inline]
1360    #[must_use]
1361    pub fn trim_start(&self) -> Self {
1362        let s = self.as_str().trim_start();
1363        unsafe { self.slice_ref_unchecked(s) }
1364    }
1365
1366    /// Returns a string with trailing whitespace removed.
1367    ///
1368    /// 'Whitespace' is defined according to the terms of the Unicode Derived
1369    /// Core Property `White_Space`, which includes newlines.
1370    ///
1371    /// # Examples
1372    ///
1373    /// ```
1374    /// # use hipstr::HipStr;
1375    /// let s = HipStr::from("\n Hello\tworld\t\n");
1376    ///
1377    /// assert_eq!("\n Hello\tworld", s.trim_end());
1378    /// ```
1379    #[inline]
1380    #[must_use]
1381    pub fn trim_end(&self) -> Self {
1382        let s = self.as_str().trim_end();
1383        unsafe { self.slice_ref_unchecked(s) }
1384    }
1385
1386    /// An iterator over substrings of this string, separated by
1387    /// characters matched by a pattern.
1388    ///
1389    /// Works like [`str::split`], but yields `HipStr`s rather than string slices.
1390    ///
1391    /// See [`str::split`], for examples and possible patterns.
1392    #[inline]
1393    pub fn split<P: Pattern>(&self, pattern: P) -> IterWrapper<'_, 'borrow, B, P::Split<'_>> {
1394        IterWrapper::new(self, pattern.split(self.as_str()))
1395    }
1396
1397    /// An iterator over substrings of this string, separated by
1398    /// characters matched by a pattern. Differs from the iterator produced by
1399    /// `split` in that `split_inclusive` leaves the matched part as the
1400    /// terminator of the substring.
1401    ///
1402    /// Works like [`str::split_inclusive`], but yields `HipStr`s rather than string slices.
1403    ///
1404    /// See [`str::split_inclusive`], for examples and possible patterns.
1405    #[inline]
1406    pub fn split_inclusive<P: Pattern>(
1407        &self,
1408        pattern: P,
1409    ) -> IterWrapper<'_, 'borrow, B, P::SplitInclusive<'_>> {
1410        IterWrapper::new(self, pattern.split_inclusive(self.as_str()))
1411    }
1412
1413    /// An iterator over substrings of this string, separated by
1414    /// characters matched by a pattern and yielded in reverse order.
1415    ///
1416    /// Works like [`str::rsplit`], but yields `HipStr`s rather than string slices.
1417    ///
1418    /// See [`str::rsplit`], for examples and possible patterns.
1419    #[inline]
1420    pub fn rsplit<P: ReversePattern>(
1421        &self,
1422        pattern: P,
1423    ) -> IterWrapper<'_, 'borrow, B, P::RSplit<'_>> {
1424        IterWrapper::new(self, pattern.rsplit(self.as_str()))
1425    }
1426
1427    /// An iterator over substrings of this string, separated by
1428    /// characters matched by a pattern.
1429    ///
1430    /// Equivalent to [`split`](Self::split), except that the trailing substring
1431    /// is skipped if empty.
1432    ///
1433    /// This method can be used for string data that is _terminated_,
1434    /// rather than _separated_ by a pattern.
1435    ///
1436    /// Works like [`str::split_terminator`], but yields `HipStr`s rather than string slices.
1437    ///
1438    /// See [`str::split_terminator`], for examples and possible patterns.
1439    #[inline]
1440    pub fn split_terminator<P: Pattern>(
1441        &self,
1442        pattern: P,
1443    ) -> IterWrapper<'_, 'borrow, B, P::SplitTerminator<'_>> {
1444        IterWrapper::new(self, pattern.split_terminator(self.as_str()))
1445    }
1446
1447    /// An iterator over substrings of this string, separated by
1448    /// characters matched by a pattern and yielded in reverse order.
1449    ///
1450    /// Equivalent to [`rsplit`](Self::rsplit), except that the trailing
1451    /// substring is skipped if empty.
1452    ///
1453    /// This method can be used for string data that is _terminated_,
1454    /// rather than _separated_ by a pattern.
1455    ///
1456    /// Works like [`str::rsplit_terminator`], but yields `HipStr`s rather than string slices.
1457    ///
1458    /// See [`str::rsplit_terminator`], for examples and possible patterns.
1459    #[inline]
1460    pub fn rsplit_terminator<P: ReversePattern>(
1461        &self,
1462        pattern: P,
1463    ) -> IterWrapper<'_, 'borrow, B, P::RSplitTerminator<'_>> {
1464        IterWrapper::new(self, pattern.rsplit_terminator(self.as_str()))
1465    }
1466
1467    /// An iterator over substrings of this string, separated by a
1468    /// pattern, restricted to returning at most `n` items.
1469    ///
1470    /// If `n` substrings are returned, the last substring (the `n`th substring)
1471    /// will contain the remainder of the string.
1472    ///
1473    /// Works like [`str::splitn`], but yields `HipStr`s rather than string slices.
1474    ///
1475    /// See [`str::splitn`], for examples and possible patterns.
1476    #[inline]
1477    pub fn splitn<P: Pattern>(
1478        &self,
1479        n: usize,
1480        pattern: P,
1481    ) -> IterWrapper<'_, 'borrow, B, P::SplitN<'_>> {
1482        IterWrapper::new(self, pattern.splitn(n, self.as_str()))
1483    }
1484
1485    /// An iterator over substrings of this string, separated by a
1486    /// pattern, starting from the end of the string, restricted to returning
1487    /// at most `n` items.
1488    ///
1489    /// If `n` substrings are returned, the last substring (the `n`th substring)
1490    /// will contain the remainder of the string.
1491    ///
1492    /// Works like [`str::rsplitn`], but yields `HipStr`s rather than string slices.
1493    ///
1494    /// See [`str::rsplitn`], for examples and possible patterns.
1495    #[inline]
1496    pub fn rsplitn<P: ReversePattern>(
1497        &self,
1498        n: usize,
1499        pattern: P,
1500    ) -> IterWrapper<'_, 'borrow, B, P::RSplitN<'_>> {
1501        IterWrapper::new(self, pattern.rsplitn(n, self.as_str()))
1502    }
1503
1504    /// Splits the string on the first occurrence of the specified delimiter and
1505    /// returns prefix before delimiter and suffix after delimiter.
1506    ///
1507    /// Works like [`str::split_once`], but returns `HipStr`s rather than string slices.
1508    ///
1509    /// # Examples
1510    ///
1511    /// ```
1512    /// # use hipstr::HipStr;
1513    /// assert_eq!(HipStr::from("cfg").split_once('='), None);
1514    /// assert_eq!(HipStr::from("cfg=").split_once('='), Some(("cfg".into(), "".into())));
1515    /// assert_eq!(HipStr::from("cfg=foo").split_once('='), Some(("cfg".into(), "foo".into())));
1516    /// assert_eq!(HipStr::from("cfg=foo=bar").split_once('='), Some(("cfg".into(), "foo=bar".into())));
1517    /// ```
1518    #[inline]
1519    pub fn split_once<P: Pattern>(&self, pattern: P) -> Option<(Self, Self)> {
1520        pattern
1521            .split_once(self.as_str())
1522            .map(|(a, b)| unsafe { (self.slice_ref_unchecked(a), self.slice_ref_unchecked(b)) })
1523    }
1524
1525    /// Splits the string on the last occurrence of the specified delimiter and
1526    /// returns prefix before delimiter and suffix after delimiter.
1527    ///
1528    /// Works like [`str::rsplit_once`], but returns `HipStr`s rather than string slices.
1529    ///
1530    /// # Examples
1531    ///
1532    /// ```
1533    /// # use hipstr::HipStr;
1534    /// assert_eq!(HipStr::from("cfg").split_once('='), None);
1535    /// assert_eq!(HipStr::from("cfg=foo").rsplit_once('='), Some(("cfg".into(), "foo".into())));
1536    /// assert_eq!(HipStr::from("cfg=foo=bar").rsplit_once('='), Some(("cfg=foo".into(), "bar".into())));
1537    /// ```
1538    #[inline]
1539    pub fn rsplit_once<P: ReversePattern>(&self, pattern: P) -> Option<(Self, Self)> {
1540        pattern
1541            .rsplit_once(self.as_str())
1542            .map(|(a, b)| unsafe { (self.slice_ref_unchecked(a), self.slice_ref_unchecked(b)) })
1543    }
1544
1545    /// An iterator over the disjoint matches of a pattern within the given string
1546    /// slice.
1547    ///
1548    /// Works like [`str::matches`], but yields `HipStr` rather than string slices.
1549    ///
1550    /// See [`str::matches`], for examples and possible patterns.
1551    #[inline]
1552    pub fn matches<P: Pattern>(&self, pattern: P) -> IterWrapper<'_, 'borrow, B, P::Matches<'_>> {
1553        IterWrapper::new(self, pattern.matches(self.as_str()))
1554    }
1555
1556    /// An iterator over the disjoint matches of a pattern within this string slice,
1557    /// yielded in reverse order.
1558    ///
1559    /// Works like [`str::rmatches`], but yields `HipStr` rather than string slices.
1560    ///
1561    /// See [`str::rmatches`], for examples and possible patterns.
1562    #[inline]
1563    pub fn rmatches<P: ReversePattern>(
1564        &self,
1565        pattern: P,
1566    ) -> IterWrapper<'_, 'borrow, B, P::RMatches<'_>> {
1567        IterWrapper::new(self, pattern.rmatches(self.as_str()))
1568    }
1569
1570    /// An iterator over the disjoint matches of a pattern within this string
1571    /// slice as well as the index that the match starts at.
1572    ///
1573    /// Works like [`str::match_indices`], but yields `(usize, HipStr)` pairs
1574    /// rather than `(usize, &str)` pairs.
1575    ///
1576    /// See [`str::match_indices`] for examples.
1577    #[inline]
1578    pub fn match_indices<P: Pattern>(
1579        &self,
1580        pattern: P,
1581    ) -> IterWrapper<'_, 'borrow, B, P::MatchIndices<'_>> {
1582        IterWrapper::new(self, pattern.match_indices(self.as_str()))
1583    }
1584
1585    /// An iterator over the disjoint matches of a pattern within `self`,
1586    /// yielded in reverse order along with the index of the match.
1587    ///
1588    /// Works like [`str::rmatch_indices`], but yields `(usize, HipStr)` pairs
1589    /// rather than `(usize, &str)` pairs.
1590    ///
1591    /// See [`str::rmatch_indices`] for examples.
1592    #[inline]
1593    pub fn rmatch_indices<P: ReversePattern>(
1594        &self,
1595        pattern: P,
1596    ) -> IterWrapper<'_, 'borrow, B, P::RMatchIndices<'_>> {
1597        IterWrapper::new(self, pattern.rmatch_indices(self.as_str()))
1598    }
1599
1600    /// Returns a new `HipStr` with leading and trailing whitespace removed.
1601    ///
1602    /// Works like [`str::trim_matches`], but returns a `HipStr` rather than a string slice.
1603    ///
1604    /// See [`str::trim_matches`] for examples and possible patterns.
1605    #[inline]
1606    #[must_use]
1607    pub fn trim_matches(&self, p: impl DoubleEndedPattern) -> Self {
1608        let s = p.trim_matches(self.as_str());
1609        unsafe { self.slice_ref_unchecked(s) }
1610    }
1611
1612    /// Returns a string slice with leading whitespace removed.
1613    ///
1614    /// Works like [`str::trim_start_matches`], but returns a `HipStr` rather than a string slice.
1615    ///
1616    /// See [`str::trim_start_matches`] for examples and possible patterns.
1617    #[inline]
1618    #[must_use]
1619    pub fn trim_start_matches(&self, p: impl Pattern) -> Self {
1620        let s = p.trim_start_matches(self.as_str());
1621        unsafe { self.slice_ref_unchecked(s) }
1622    }
1623
1624    /// Returns a string slice with trailing whitespace removed.
1625    ///
1626    /// Works like [`str::trim_end_matches`], but returns a `HipStr` rather than a string slice.
1627    ///
1628    /// See [`str::trim_end_matches`] for examples and possible patterns.
1629    #[inline]
1630    #[must_use]
1631    pub fn trim_end_matches(&self, p: impl ReversePattern) -> Self {
1632        let s = p.trim_end_matches(self.as_str());
1633        unsafe { self.slice_ref_unchecked(s) }
1634    }
1635
1636    /// Returns a string with the prefix removed.
1637    ///
1638    /// If the string starts with the pattern `prefix`, returns substring after the prefix, wrapped
1639    /// in `Some`. Unlike `trim_start_matches`, this method removes the prefix exactly once.
1640    ///
1641    /// If the string does not start with `prefix`, returns `None`.
1642    ///
1643    /// Works like [`str::strip_prefix`], but returns a `HipStr` rather than a string slice.
1644    ///
1645    /// See [`str::strip_prefix`] for examples and possible patterns.
1646    #[inline]
1647    pub fn strip_prefix(&self, prefix: impl Pattern) -> Option<Self> {
1648        prefix
1649            .strip_prefix(self.as_str())
1650            .map(|s| unsafe { self.slice_ref_unchecked(s) })
1651    }
1652
1653    /// Returns a string with the suffix removed.
1654    ///
1655    /// If the string ends with the pattern `suffix`, returns the substring before the suffix,
1656    /// wrapped in `Some`.  Unlike `trim_end_matches`, this method removes the suffix exactly once.
1657    ///
1658    /// If the string does not end with `suffix`, returns `None`.
1659    ///
1660    /// Works like [`str::strip_suffix`], but returns a `HipStr` rather than a
1661    /// string slice.
1662    ///
1663    /// See [`str::strip_suffix`] for examples and possible patterns.
1664    #[inline]
1665    pub fn strip_suffix(&self, suffix: impl ReversePattern) -> Option<Self> {
1666        suffix
1667            .strip_suffix(self.as_str())
1668            .map(|s| unsafe { self.slice_ref_unchecked(s) })
1669    }
1670
1671    /// Splits a string by whitespace.
1672    ///
1673    /// Works like [`str::split_whitespace`], but yields `HipStr`s rather than
1674    /// string slices.
1675    ///
1676    /// See [`str::split_whitespace`] for examples.
1677    #[inline]
1678    pub fn split_whitespace(&self) -> IterWrapper<'_, 'borrow, B, SplitWhitespace<'_>> {
1679        IterWrapper::new(self, self.as_str().split_whitespace())
1680    }
1681
1682    /// Splits a string by ASCII whitespace.
1683    ///
1684    /// Works like [`str::split_ascii_whitespace`], but yields `HipStr`s rather than
1685    /// string slices.
1686    ///
1687    /// See [`str::split_ascii_whitespace`] for examples.
1688    #[inline]
1689    pub fn split_ascii_whitespace(&self) -> IterWrapper<'_, 'borrow, B, SplitAsciiWhitespace<'_>> {
1690        IterWrapper::new(self, self.as_str().split_ascii_whitespace())
1691    }
1692
1693    /// An iterator over the lines of a string.
1694    ///
1695    /// Works like [`str::split_ascii_whitespace`], but yields `HipStr`s rather than
1696    /// string slices.
1697    ///
1698    /// See [`str::split_ascii_whitespace`] for examples.
1699    #[inline]
1700    pub fn lines(&self) -> IterWrapper<'_, 'borrow, B, Lines> {
1701        IterWrapper::new(self, self.as_str().lines())
1702    }
1703
1704    /// Concatenates some byte slices into a single `HipByt`.
1705    ///
1706    /// The related constructor [`HipStr::concat`] is more general but may be
1707    /// less efficient due to the absence of specialization in Rust.
1708    ///
1709    /// # Examples
1710    ///
1711    /// ```rust
1712    /// # use hipstr::HipByt;
1713    /// let c = HipByt::concat_slices(&[b"hello", b" world", b"!"]);
1714    /// assert_eq!(c, b"hello world!");
1715    /// ```
1716    #[inline]
1717    #[must_use]
1718    pub fn concat_slices(slices: &[&str]) -> Self {
1719        #[expect(clippy::transmute_ptr_to_ptr)]
1720        let slices: &[&[u8]] = unsafe { transmute(slices) };
1721
1722        Self(HipByt::concat_slices(slices))
1723    }
1724
1725    /// Concatenates string slices (or things than can be seen as string slices)
1726    /// together into a new `HipStr`.
1727    ///
1728    /// # Panics
1729    ///
1730    /// During the concatenation, the iterator is ran twice: once to get the
1731    /// expected new length, and again to do the actual copy.
1732    /// If the returned slices are not the same and the new length is greater
1733    /// than the expected length, the function panics (before actually
1734    /// overflowing).
1735    ///
1736    /// This behavior differs from [`std::slice::Concat`] that reallocates when
1737    /// needed.
1738    ///
1739    /// # Examples
1740    ///
1741    /// ```rust
1742    /// # use hipstr::HipStr;
1743    /// let c  = HipStr::concat(&["hello", " world", "!"]);
1744    /// assert_eq!(c, "hello world!");
1745    ///
1746    /// let c2 = HipStr::concat(["hello".to_string(), " world".to_string(), "!".to_string()]);
1747    /// assert_eq!(c2, "hello world!");
1748    ///
1749    /// let c3 = HipStr::concat(vec!["hello", " world", "!"].iter());
1750    /// assert_eq!(c3, "hello world!");
1751    /// ```
1752    pub fn concat<E, I>(slices: I) -> Self
1753    where
1754        E: AsRef<str>,
1755        I: IntoIterator<Item = E>,
1756        I::IntoIter: Clone,
1757    {
1758        Self(HipByt::concat(slices.into_iter().map(AsBytes)))
1759    }
1760
1761    /// Joins some string slices with the given separator string slice into a
1762    /// new `HipByt`, that is, concatenates the strings inserting the
1763    /// separator between each pair of adjacent strings.
1764    ///
1765    /// The related constructor [`HipStr::join`] is more general but may be less
1766    /// efficient due to the absence of specialization in Rust.
1767    ///
1768    /// # Examples
1769    ///
1770    /// ```rust
1771    /// # use hipstr::HipStr;
1772    /// let s = HipStr::join_slices(&["hello", "world", "rust"], ", ");
1773    /// assert_eq!(s, "hello, world, rust");
1774    /// ```
1775    #[inline]
1776    #[must_use]
1777    pub fn join_slices(slices: &[&str], sep: &str) -> Self {
1778        #[expect(clippy::transmute_ptr_to_ptr)]
1779        let slices: &[&[u8]] = unsafe { transmute(slices) };
1780
1781        Self(HipByt::join_slices(slices, sep.as_bytes()))
1782    }
1783
1784    /// Joins strings together with the given separator string into a new `HipStr`,
1785    /// that is, concatenates the strings inserting the separator between each pair of
1786    /// adjacent strings.
1787    ///
1788    /// # Panics
1789    ///
1790    /// During the concatenation the iterator is ran twice: once to get the
1791    /// expected new length, and again to do the actual copy.
1792    /// If the returned strings are not the same and the new length is greater
1793    /// than the expected length, the function panics (before actually
1794    /// overflowing).
1795    ///
1796    /// This behavior differs from [`std::slice::Join`] that reallocates if needed.
1797    ///
1798    /// # Examples
1799    ///
1800    /// Basic usage:
1801    ///
1802    /// ```
1803    /// # use hipstr::HipStr;
1804    /// let slices = &["hello", "world", "rust"];
1805    /// let sep = ", ";
1806    /// let joined = HipStr::join(slices, sep);
1807    /// assert_eq!(joined, "hello, world, rust");
1808    ///
1809    /// let joined = HipStr::join(["hello".to_string(), "world".to_string(), "rust".to_string()].iter(), sep.to_string());
1810    /// assert_eq!(joined, "hello, world, rust");
1811    ///
1812    /// let joined = HipStr::join(slices.to_vec().iter(), sep);
1813    /// assert_eq!(joined, "hello, world, rust");
1814    /// ```
1815    pub fn join<E, I>(slices: I, sep: impl AsRef<str>) -> Self
1816    where
1817        E: AsRef<str>,
1818        I: IntoIterator<Item = E>,
1819        I::IntoIter: Clone,
1820    {
1821        let iter = slices.into_iter().map(AsBytes);
1822        Self(HipByt::join(iter, sep.as_ref().as_bytes()))
1823    }
1824}
1825
1826impl<B> HipStr<'static, B>
1827where
1828    B: Backend,
1829{
1830    /// Creates a new `HipStr` from a `'static` string slice without copying the slice.
1831    ///
1832    /// Handy shortcut to make a `HipStr<'static, _>` out of a `&'static str`.
1833    ///
1834    /// # Representation
1835    ///
1836    /// The created `HipStr` is _borrowed_.
1837    ///
1838    /// # Examples
1839    ///
1840    /// Basic usage:
1841    ///
1842    /// ```
1843    /// # use hipstr::HipStr;
1844    /// let s = HipStr::from_static("hello");
1845    /// assert_eq!(s.len(), 5);
1846    /// ```
1847    #[inline]
1848    #[must_use]
1849    pub const fn from_static(value: &'static str) -> Self {
1850        Self::borrowed(value)
1851    }
1852}
1853
1854// Manual implementation needed to remove trait bound on B::RawPointer.
1855impl<B> Clone for HipStr<'_, B>
1856where
1857    B: Backend,
1858{
1859    #[inline]
1860    fn clone(&self) -> Self {
1861        Self(self.0.clone())
1862    }
1863}
1864
1865// Manual implementation needed to remove trait bound on B::RawPointer.
1866impl<B> Default for HipStr<'_, B>
1867where
1868    B: Backend,
1869{
1870    #[inline]
1871    fn default() -> Self {
1872        Self::new()
1873    }
1874}
1875
1876impl<B> Deref for HipStr<'_, B>
1877where
1878    B: Backend,
1879{
1880    type Target = str;
1881
1882    #[inline]
1883    fn deref(&self) -> &Self::Target {
1884        self.as_str()
1885    }
1886}
1887
1888impl<B> Borrow<str> for HipStr<'_, B>
1889where
1890    B: Backend,
1891{
1892    #[inline]
1893    fn borrow(&self) -> &str {
1894        self.as_str()
1895    }
1896}
1897
1898impl<B> Hash for HipStr<'_, B>
1899where
1900    B: Backend,
1901{
1902    #[inline]
1903    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
1904        self.as_str().hash(state);
1905    }
1906}
1907
1908// Formatting
1909
1910impl<B> fmt::Debug for HipStr<'_, B>
1911where
1912    B: Backend,
1913{
1914    #[inline]
1915    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1916        fmt::Debug::fmt(self.as_str(), f)
1917    }
1918}
1919
1920impl<B> fmt::Display for HipStr<'_, B>
1921where
1922    B: Backend,
1923{
1924    #[inline]
1925    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1926        fmt::Display::fmt(self.as_str(), f)
1927    }
1928}
1929
1930/// Slice error kinds.
1931#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1932pub enum SliceErrorKind {
1933    /// Start index should be less or equal to the end index.
1934    StartGreaterThanEnd,
1935
1936    /// Start index out of bounds.
1937    StartOutOfBounds,
1938
1939    /// End index out of bounds.
1940    EndOutOfBounds,
1941
1942    /// Start index is not at a char boundary.
1943    StartNotACharBoundary,
1944
1945    /// End index is not at a char boundary.
1946    EndNotACharBoundary,
1947}
1948
1949/// A possible error value when slicing a [`HipStr`].
1950///
1951/// This type is the error type for [`HipStr::try_slice`].
1952pub struct SliceError<'a, 'borrow, B>
1953where
1954    B: Backend,
1955{
1956    kind: SliceErrorKind,
1957    start: usize,
1958    end: usize,
1959    string: &'a HipStr<'borrow, B>,
1960}
1961
1962impl<B> Eq for SliceError<'_, '_, B> where B: Backend {}
1963
1964impl<B> PartialEq for SliceError<'_, '_, B>
1965where
1966    B: Backend,
1967{
1968    fn eq(&self, other: &Self) -> bool {
1969        self.kind == other.kind
1970            && self.start == other.start
1971            && self.end == other.end
1972            && self.string == other.string
1973    }
1974}
1975
1976impl<B> Clone for SliceError<'_, '_, B>
1977where
1978    B: Backend,
1979{
1980    fn clone(&self) -> Self {
1981        *self
1982    }
1983}
1984
1985impl<B> Copy for SliceError<'_, '_, B> where B: Backend {}
1986
1987impl<'a, 'borrow, B> SliceError<'a, 'borrow, B>
1988where
1989    B: Backend,
1990{
1991    const fn new(
1992        kind: ByteSliceErrorKind,
1993        start: usize,
1994        end: usize,
1995        string: &'a HipStr<'borrow, B>,
1996    ) -> Self {
1997        let kind = match kind {
1998            ByteSliceErrorKind::StartGreaterThanEnd => SliceErrorKind::StartGreaterThanEnd,
1999            ByteSliceErrorKind::StartOutOfBounds => SliceErrorKind::StartOutOfBounds,
2000            ByteSliceErrorKind::EndOutOfBounds => SliceErrorKind::EndOutOfBounds,
2001        };
2002        Self {
2003            kind,
2004            start,
2005            end,
2006            string,
2007        }
2008    }
2009
2010    /// Returns the kind of error.
2011    #[inline]
2012    #[must_use]
2013    pub const fn kind(&self) -> SliceErrorKind {
2014        self.kind
2015    }
2016
2017    /// Returns the start of the requested range.
2018    #[inline]
2019    #[must_use]
2020    pub const fn start(&self) -> usize {
2021        self.start
2022    }
2023
2024    /// Returns the end of the requested range.
2025    #[inline]
2026    #[must_use]
2027    pub const fn end(&self) -> usize {
2028        self.end
2029    }
2030
2031    /// Returns the _normalized_ requested range.
2032    #[inline]
2033    #[must_use]
2034    pub const fn range(&self) -> Range<usize> {
2035        self.start..self.end
2036    }
2037
2038    /// Returns a reference to the source `HipByt` to slice.
2039    #[inline]
2040    #[must_use]
2041    pub const fn source(&self) -> &HipStr<'borrow, B> {
2042        self.string
2043    }
2044}
2045
2046impl<B> fmt::Debug for SliceError<'_, '_, B>
2047where
2048    B: Backend,
2049{
2050    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2051        f.debug_struct("SliceError")
2052            .field("kind", &self.kind)
2053            .field("start", &self.start)
2054            .field("end", &self.end)
2055            .field("string", &self.string)
2056            .finish()
2057    }
2058}
2059
2060impl<B> fmt::Display for SliceError<'_, '_, B>
2061where
2062    B: Backend,
2063{
2064    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2065        match self.kind {
2066            SliceErrorKind::StartGreaterThanEnd => write!(
2067                f,
2068                "range starts at {} but ends at {} when slicing `{}`",
2069                self.start, self.end, self.string
2070            ),
2071            SliceErrorKind::StartOutOfBounds => write!(
2072                f,
2073                "range start index {} is out of bounds of `{}`",
2074                self.start, self.string
2075            ),
2076            SliceErrorKind::EndOutOfBounds => write!(
2077                f,
2078                "range end index {} is out of bounds of `{}`",
2079                self.end, self.string
2080            ),
2081            SliceErrorKind::StartNotACharBoundary => write!(
2082                f,
2083                "range start index {} is not a char boundary of `{}`",
2084                self.start, self.string
2085            ),
2086            SliceErrorKind::EndNotACharBoundary => write!(
2087                f,
2088                "range end index {} is not a char boundary of `{}`",
2089                self.end, self.string
2090            ),
2091        }
2092    }
2093}
2094
2095impl<B> Error for SliceError<'_, '_, B> where B: Backend {}
2096
2097/// A possible error value when converting a [`HipStr`] from a [`HipByt`].
2098///
2099/// This type is the error type for the [`from_utf8`] method on [`HipStr`]. It
2100/// is designed in such a way to carefully avoid reallocations: the
2101/// [`into_bytes`] method will give back the byte vector that was used in the
2102/// conversion attempt.
2103///
2104/// [`from_utf8`]: HipStr::from_utf8
2105/// [`into_bytes`]: FromUtf8Error::into_bytes
2106///
2107/// The [`Utf8Error`] type provided by [`std::str`] represents an error that may
2108/// occur when converting a slice of [`u8`]s to a [`&str`]. In this sense, it's
2109/// an analogue to `FromUtf8Error`, and you can get one from a `FromUtf8Error`
2110/// through the [`utf8_error`] method.
2111///
2112/// [`Utf8Error`]: std::str::Utf8Error
2113/// [`std::str`]: std::str
2114/// [`&str`]: prim@str "&str"
2115/// [`utf8_error`]: FromUtf8Error::utf8_error
2116///
2117/// # Examples
2118///
2119/// Basic usage:
2120///
2121/// ```
2122/// // some invalid bytes, in a vector
2123/// let bytes = vec![0, 159];
2124///
2125/// let value = String::from_utf8(bytes);
2126///
2127/// assert!(value.is_err());
2128/// assert_eq!(vec![0, 159], value.unwrap_err().into_bytes());
2129/// ```
2130pub struct FromUtf8Error<'borrow, B>
2131where
2132    B: Backend,
2133{
2134    pub(super) bytes: HipByt<'borrow, B>,
2135    pub(super) error: Utf8Error,
2136}
2137
2138impl<B> Eq for FromUtf8Error<'_, B> where B: Backend {}
2139
2140impl<B> PartialEq for FromUtf8Error<'_, B>
2141where
2142    B: Backend,
2143{
2144    fn eq(&self, other: &Self) -> bool {
2145        self.bytes == other.bytes && self.error == other.error
2146    }
2147}
2148
2149impl<B> Clone for FromUtf8Error<'_, B>
2150where
2151    B: Backend,
2152{
2153    fn clone(&self) -> Self {
2154        Self {
2155            bytes: self.bytes.clone(),
2156            error: self.error,
2157        }
2158    }
2159}
2160
2161impl<B> fmt::Debug for FromUtf8Error<'_, B>
2162where
2163    B: Backend,
2164{
2165    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2166        f.debug_struct("FromUtf8Error")
2167            .field("bytes", &self.bytes)
2168            .field("error", &self.error)
2169            .finish()
2170    }
2171}
2172
2173impl<'borrow, B> FromUtf8Error<'borrow, B>
2174where
2175    B: Backend,
2176{
2177    /// Returns a slice of [`u8`]s bytes that were attempted to convert to a `HipStr`.
2178    ///
2179    /// # Examples
2180    ///
2181    /// Basic usage:
2182    ///
2183    /// ```
2184    /// # use hipstr::{HipStr, HipByt};
2185    /// // some invalid bytes, in a vector
2186    /// let bytes = HipByt::from(vec![0, 159]);
2187    ///
2188    /// let value = HipStr::from_utf8(bytes);
2189    ///
2190    /// assert_eq!(&[0, 159], value.unwrap_err().as_bytes());
2191    /// ```
2192    #[must_use]
2193    pub const fn as_bytes(&self) -> &[u8] {
2194        self.bytes.as_slice()
2195    }
2196
2197    /// Returns the bytes that were attempted to convert to a `HipStr`.
2198    ///
2199    /// This method is carefully constructed to avoid allocation. It will
2200    /// consume the error, moving out the bytes, so that a copy of the bytes
2201    /// does not need to be made.
2202    ///
2203    /// # Examples
2204    ///
2205    /// Basic usage:
2206    ///
2207    /// ```
2208    /// # use hipstr::{HipStr, HipByt};
2209    /// // some invalid bytes, in a vector
2210    /// let bytes = HipByt::from(vec![0, 159]);
2211    ///
2212    /// let value = HipStr::from_utf8(bytes.clone());
2213    ///
2214    /// assert_eq!(bytes, value.unwrap_err().into_bytes());
2215    /// ```
2216    // #[allow(clippy::missing_const_for_fn)] // cannot const it for now, clippy bug
2217    #[must_use]
2218    pub fn into_bytes(self) -> HipByt<'borrow, B> {
2219        self.bytes
2220    }
2221
2222    /// Fetch a `Utf8Error` to get more details about the conversion failure.
2223    ///
2224    /// The [`Utf8Error`] type provided by [`std::str`] represents an error that may
2225    /// occur when converting a slice of [`u8`]s to a [`&str`]. In this sense, it's
2226    /// an analogue to `FromUtf8Error`. See its documentation for more details
2227    /// on using it.
2228    ///
2229    /// [`std::str`]: core::str "std::str"
2230    /// [`&str`]: prim@str "&str"
2231    ///
2232    /// # Examples
2233    ///
2234    /// Basic usage:
2235    ///
2236    /// ```
2237    /// # use hipstr::{HipStr, HipByt};
2238    /// // some invalid bytes, in a vector
2239    /// let bytes = HipByt::from(vec![0, 159]);
2240    ///
2241    /// let error = HipStr::from_utf8(bytes).unwrap_err().utf8_error();
2242    ///
2243    /// // the first byte is invalid here
2244    /// assert_eq!(1, error.valid_up_to());
2245    /// ```
2246    #[must_use]
2247    pub const fn utf8_error(&self) -> Utf8Error {
2248        self.error
2249    }
2250}
2251
2252impl<B> fmt::Display for FromUtf8Error<'_, B>
2253where
2254    B: Backend,
2255{
2256    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2257        fmt::Display::fmt(&self.error, f)
2258    }
2259}
2260
2261impl<B> Error for FromUtf8Error<'_, B> where B: Backend {}
2262
2263/// A wrapper type for a mutably borrowed [`String`] out of a [`HipStr`].
2264pub struct RefMut<'a, 'borrow, B>
2265where
2266    B: Backend,
2267{
2268    result: &'a mut HipStr<'borrow, B>,
2269    owned: String,
2270}
2271
2272impl<B> Drop for RefMut<'_, '_, B>
2273where
2274    B: Backend,
2275{
2276    fn drop(&mut self) {
2277        let owned = core::mem::take(&mut self.owned);
2278        *self.result = HipStr::from(owned);
2279    }
2280}
2281
2282impl<B> Deref for RefMut<'_, '_, B>
2283where
2284    B: Backend,
2285{
2286    type Target = String;
2287    fn deref(&self) -> &Self::Target {
2288        &self.owned
2289    }
2290}
2291
2292impl<B> DerefMut for RefMut<'_, '_, B>
2293where
2294    B: Backend,
2295{
2296    fn deref_mut(&mut self) -> &mut Self::Target {
2297        &mut self.owned
2298    }
2299}
2300
2301#[derive(Clone, Copy)]
2302struct AsBytes<T>(T);
2303
2304impl<T: AsRef<str>> AsRef<[u8]> for AsBytes<T> {
2305    #[inline]
2306    fn as_ref(&self) -> &[u8] {
2307        self.0.as_ref().as_bytes()
2308    }
2309}