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}