hipstr/
bytes.rs

1//! Bytes.
2//!
3//! This module provides the [`HipByt`] type as well as the associated helper
4//! and error types.
5
6use alloc::fmt;
7use alloc::vec::Vec;
8use core::borrow::Borrow;
9use core::error::Error;
10use core::hash::Hash;
11use core::hint::unreachable_unchecked;
12use core::mem::{ManuallyDrop, MaybeUninit};
13use core::ops::{Bound, Deref, DerefMut, Range, RangeBounds};
14use core::ptr;
15
16use raw::borrowed::Borrowed;
17use raw::{Inline, Split, SplitMut, Tag, Union};
18
19use self::raw::try_range_of;
20pub use self::raw::HipByt;
21use crate::Backend;
22
23mod cmp;
24mod convert;
25mod raw;
26
27#[cfg(feature = "borsh")]
28mod borsh;
29#[cfg(feature = "bstr")]
30mod bstr;
31#[cfg(feature = "serde")]
32pub mod serde;
33
34#[cfg(test)]
35mod tests;
36
37#[cfg(feature = "bstr")]
38type Owned = ::bstr::BString;
39
40#[cfg(not(feature = "bstr"))]
41type Owned = Vec<u8>;
42
43#[cfg(feature = "bstr")]
44type Slice = ::bstr::BStr;
45
46#[cfg(not(feature = "bstr"))]
47type Slice = [u8];
48
49impl<'borrow, B> HipByt<'borrow, B>
50where
51    B: Backend,
52{
53    /// Creates an empty `HipByt`.
54    ///
55    /// Function provided for [`Vec::new`] replacement.
56    ///
57    /// # Representation
58    ///
59    /// <div class=warning>
60    ///
61    /// The used representation of the empty string is unspecified.
62    /// It may be _borrowed_ or _inlined_ but will never be allocated.
63    ///
64    /// </div>
65    ///
66    /// # Examples
67    ///
68    /// Basic usage:
69    ///
70    /// ```
71    /// # use hipstr::HipByt;
72    /// let s = HipByt::new();
73    /// ```
74    #[inline]
75    #[must_use]
76    pub const fn new() -> Self {
77        Self::inline_empty()
78    }
79
80    /// Creates a new inline `HipByt` by copying the given slice.
81    /// The slice **must not** be too large to be inlined.
82    ///
83    /// # Representation
84    ///
85    /// The created `HipByt` is _inline_.
86    ///
87    /// # Panics
88    ///
89    /// It panics if the slice is too large.
90    ///
91    /// # Examples
92    ///
93    /// Basic usage:
94    ///
95    /// ```
96    /// # use hipstr::HipByt;
97    /// let s = HipByt::inline(b"hello\0");
98    /// assert_eq!(s, b"hello\0");
99    /// ```
100    #[must_use]
101    pub const fn inline(bytes: &[u8]) -> Self {
102        assert!(bytes.len() <= Self::inline_capacity(), "slice too large");
103
104        // SAFETY: length checked above
105        unsafe { Self::inline_unchecked(bytes) }
106    }
107
108    /// Creates a new inline `HipByt` by copying the given the slice.
109    /// Return `None` if the given slice is too large to be inlined.
110    ///
111    /// # Representation
112    ///
113    /// In case of success, the created `HipByt` is _inline_.
114    ///
115    /// # Examples
116    ///
117    /// Basic usage:
118    ///
119    /// ```
120    /// # use hipstr::HipByt;
121    /// let s = HipByt::try_inline(b"hello\0").unwrap();
122    /// assert_eq!(s, b"hello\0");
123    /// ```
124    #[must_use]
125    pub const fn try_inline(bytes: &[u8]) -> Option<Self> {
126        if bytes.len() <= Self::inline_capacity() {
127            // SAFETY: length checked above
128            Some(unsafe { Self::inline_unchecked(bytes) })
129        } else {
130            None
131        }
132    }
133
134    /// Creates a new `HipByt` with the given capacity.
135    ///
136    /// The final capacity depends on the representation and is not guaranteed
137    /// to be exact. However, the returned `HipByt` will be able to hold at
138    /// least `capacity` bytes without reallocating or changing representation.
139    ///
140    /// # Representation
141    ///
142    /// If the capacity is less or equal to the inline capacity, the
143    /// representation will be *inline*.
144    ///
145    /// Otherwise, it will be *allocated*.
146    ///
147    /// The representation is **not normalized**.
148    ///
149    /// # Examples
150    ///
151    /// Basic usage:
152    ///
153    /// ```
154    /// # use hipstr::HipByt;
155    /// let mut s = HipByt::with_capacity(42);
156    /// let p = s.as_ptr();
157    /// for _ in 0..42 {
158    ///     s.push(b'*');
159    /// }
160    /// assert_eq!(s, [b'*'; 42]);
161    /// assert_eq!(s.as_ptr(), p);
162    /// ```
163    #[inline]
164    #[must_use]
165    pub fn with_capacity(capacity: usize) -> Self {
166        if capacity <= Self::inline_capacity() {
167            Self::inline_empty()
168        } else {
169            Self::from_vec(Vec::with_capacity(capacity))
170        }
171    }
172
173    /// Creates a new `HipByt` from a byte slice.
174    /// No heap allocation is performed.
175    /// **The slice is not copied.**
176    ///
177    /// # Examples
178    ///
179    /// Basic usage:
180    ///
181    /// ```
182    /// # use hipstr::HipByt;
183    /// let b = HipByt::borrowed(b"hello\0");
184    /// assert_eq!(b.len(), 6);
185    /// ```
186    #[must_use]
187    #[inline]
188    pub const fn borrowed(bytes: &'borrow [u8]) -> Self {
189        Union {
190            borrowed: Borrowed::new(bytes),
191        }
192        .into_raw()
193    }
194
195    /// Returns the length of this `HipByt`.
196    ///
197    /// # Example
198    ///
199    /// Basic usage:
200    ///
201    /// ```
202    /// # use hipstr::HipByt;
203    /// let a = HipByt::borrowed(b"\xDE\xAD\xBE\xEF");
204    /// assert_eq!(a.len(), 4);
205    /// ```
206    #[inline]
207    #[must_use]
208    pub const fn len(&self) -> usize {
209        match self.split() {
210            Split::Inline(inline) => inline.len(),
211            Split::Allocated(heap) => heap.len(),
212            Split::Borrowed(borrowed) => borrowed.len(),
213        }
214    }
215
216    /// Returns `true` if this `HipByt` has a length of zero, and `false` otherwise.
217    ///
218    ///
219    /// Basic usage:
220    ///
221    /// ```
222    /// # use hipstr::HipByt;
223    /// let a = HipByt::new();
224    /// assert!(a.is_empty());
225    ///
226    /// let b = HipByt::borrowed(b"ab");
227    /// assert!(!b.is_empty());
228    /// ```
229    #[inline]
230    #[must_use]
231    pub const fn is_empty(&self) -> bool {
232        self.len() == 0
233    }
234
235    /// Returns a raw pointer to the start of the byte sequence.
236    ///
237    /// The caller must ensure the `HipByt` outlives the pointer this function
238    /// returns, or else it will end up dangling.
239    /// Modifying the byte sequence may change representation or reallocate,
240    /// which would invalid the returned pointer.
241    #[inline]
242    #[must_use]
243    pub const fn as_ptr(&self) -> *const u8 {
244        match self.split() {
245            Split::Inline(inline) => inline.as_ptr(),
246            Split::Allocated(heap) => heap.as_ptr(),
247            Split::Borrowed(borrowed) => borrowed.as_ptr(),
248        }
249    }
250
251    /// Returns a raw mutable pointer to the start of the byte sequence.
252    ///
253    /// The caller must ensure the `HipByt` outlives the pointer this function
254    /// returns, or else it will end up dangling.
255    /// Modifying the byte sequence may change representation or reallocate,
256    /// which would invalid the returned pointer.
257    #[inline]
258    #[must_use]
259    pub fn as_mut_ptr(&mut self) -> Option<*mut u8> {
260        match self.split_mut() {
261            SplitMut::Inline(inline) => Some(inline.as_mut_ptr()),
262            SplitMut::Allocated(heap) => heap.as_mut_ptr(),
263            SplitMut::Borrowed(_) => None,
264        }
265    }
266
267    /// Returns a raw mutable pointer to the start of the byte sequence.
268    ///
269    /// The caller must ensure the `HipByt` outlives the pointer this function
270    /// returns, or else it will end up dangling. Modifying the byte sequence
271    /// may change representation or reallocate, which would invalid the
272    /// returned pointer.
273    ///
274    /// # Safety
275    ///
276    /// The caller must ensure the sequence is actually unique: not shared and
277    /// not borrowed.
278    ///
279    /// # Panics
280    ///
281    /// In debug mode, this function panics if the sequence is borrowed or
282    /// shared.
283    #[inline]
284    #[must_use]
285    pub unsafe fn as_mut_ptr_unchecked(&mut self) -> *mut u8 {
286        match self.split_mut() {
287            SplitMut::Inline(inline) => inline.as_mut_ptr(),
288            SplitMut::Allocated(heap) => unsafe { heap.as_mut_ptr_unchecked() },
289            SplitMut::Borrowed(_) => {
290                if cfg!(debug_assertions) {
291                    panic!("mutable pointer of borrowed string");
292                } else {
293                    unsafe {
294                        unreachable_unchecked();
295                    }
296                }
297            }
298        }
299    }
300
301    /// Extracts a slice of the entire `HipByt`.
302    ///
303    /// # Examples
304    ///
305    /// Basic usage:
306    ///
307    /// ```
308    /// # use hipstr::HipByt;
309    /// let s = HipByt::from(b"foobar");
310    ///
311    /// assert_eq!(b"foobar", s.as_slice());
312    /// ```
313    #[inline]
314    #[must_use]
315    pub const fn as_slice(&self) -> &[u8] {
316        match self.split() {
317            Split::Inline(inline) => inline.as_slice(),
318            Split::Allocated(heap) => heap.as_slice(),
319            Split::Borrowed(borrowed) => borrowed.as_slice(),
320        }
321    }
322
323    /// Extracts a mutable slice of the entire `HipByt` if possible.
324    ///
325    /// # Examples
326    ///
327    /// Basic usage:
328    ///
329    /// ```
330    /// # use hipstr::HipByt;
331    /// let mut s = HipByt::from(b"foo");
332    /// let slice = s.as_mut_slice().unwrap();
333    /// slice.copy_from_slice(b"bar");
334    /// assert_eq!(b"bar", slice);
335    /// ```
336    #[inline]
337    #[must_use]
338    pub fn as_mut_slice(&mut self) -> Option<&mut [u8]> {
339        match self.split_mut() {
340            SplitMut::Inline(inline) => Some(inline.as_mut_slice()),
341            SplitMut::Allocated(allocated) => allocated.as_mut_slice(),
342            SplitMut::Borrowed(_) => None,
343        }
344    }
345
346    /// Extracts a mutable slice of the entire `HipByt`.
347    ///
348    /// # Safety
349    ///
350    /// This `HipByt` should not be shared or borrowed.
351    ///
352    /// # Panics
353    ///
354    /// In debug mode, panics if the sequence is borrowed or shared.
355    #[inline]
356    pub unsafe fn as_mut_slice_unchecked(&mut self) -> &mut [u8] {
357        match self.split_mut() {
358            SplitMut::Inline(inline) => inline.as_mut_slice(),
359            SplitMut::Allocated(allocated) => unsafe { allocated.as_mut_slice_unchecked() },
360            SplitMut::Borrowed(_) => {
361                if cfg!(debug_assertions) {
362                    panic!("mutable slice of borrowed string");
363                } else {
364                    unsafe { unreachable_unchecked() }
365                }
366            }
367        }
368    }
369
370    /// Extracts a mutable slice of the entire `HipByt` changing the
371    /// representation (and thus _potentially reallocating_) if the current
372    /// representation cannot be mutated.
373    ///
374    /// # Examples
375    ///
376    /// Basic usage:
377    ///
378    /// ```
379    /// # use hipstr::HipByt;
380    /// let mut s = HipByt::borrowed(b"foo");
381    /// let slice = s.to_mut_slice(); // change the representation to inline
382    /// slice.copy_from_slice(b"bar");
383    /// assert_eq!(b"bar", slice);
384    /// ```
385    #[inline]
386    #[doc(alias = "make_mut")]
387    pub fn to_mut_slice(&mut self) -> &mut [u8] {
388        self.make_unique();
389        // SAFETY: `make_unique` above ensures that it is uniquely owned
390        unsafe { self.as_mut_slice_unchecked() }
391    }
392
393    /// Returns `true` if this `HipByt` uses the inline representation, `false` otherwise.
394    ///
395    /// # Examples
396    ///
397    /// Basic usage:
398    ///
399    /// ```
400    /// # use hipstr::HipByt;
401    /// let s = HipByt::borrowed(b"hello");
402    /// assert!(!s.is_inline());
403    ///
404    /// let s = HipByt::from(b"hello");
405    /// assert!(s.is_inline());
406    ///
407    /// let s = HipByt::from(b"hello".repeat(10));
408    /// assert!(!s.is_inline());
409    /// ```
410    #[inline]
411    #[must_use]
412    pub const fn is_inline(&self) -> bool {
413        matches!(self.tag(), Tag::Inline)
414    }
415
416    /// Returns `true` if this `HipByt` is a slice borrow, `false` otherwise.
417    ///
418    /// # Examples
419    ///
420    /// Basic usage:
421    ///
422    /// ```
423    /// # use hipstr::HipByt;
424    /// let s = HipByt::borrowed(b"hello");
425    /// assert!(s.is_borrowed());
426    ///
427    /// let s = HipByt::from(b"hello");
428    /// assert!(!s.is_borrowed());
429    ///
430    /// let s = HipByt::from(b"hello".repeat(10));
431    /// assert!(!s.is_borrowed());
432    /// ```
433    #[inline]
434    #[must_use]
435    pub const fn is_borrowed(&self) -> bool {
436        matches!(self.tag(), Tag::Borrowed)
437    }
438
439    /// Converts `self` into a borrowed slice if this `HipByt` is backed by a
440    /// borrow.
441    ///
442    /// # Errors
443    ///
444    /// Returns `Err(self)` if this `HipByt` is not borrowed.
445    ///
446    /// # Examples
447    ///
448    /// Basic usage:
449    ///
450    /// ```
451    /// # use hipstr::HipByt;
452    /// static SEQ: &[u8] = &[1 ,2, 3];
453    /// let s = HipByt::borrowed(SEQ);
454    /// let c = s.into_borrowed();
455    /// assert_eq!(c, Ok(SEQ));
456    /// assert!(std::ptr::eq(SEQ, c.unwrap()));
457    /// ```
458    pub const fn into_borrowed(self) -> Result<&'borrow [u8], Self> {
459        match self.split() {
460            Split::Allocated(_) | Split::Inline(_) => Err(self),
461            Split::Borrowed(borrowed) => {
462                let result = borrowed.as_slice();
463                core::mem::forget(self); // not needed
464                Ok(result)
465            }
466        }
467    }
468
469    /// Returns the borrowed slice if this `HipByt` is actually borrowed, `None`
470    /// otherwise.
471    ///
472    /// # Examples
473    ///
474    /// ```
475    /// # use hipstr::HipByt;
476    /// static SEQ: &[u8] = &[1 ,2, 3];
477    /// let s = HipByt::borrowed(SEQ);
478    /// let c: Option<&'static [u8]> = s.as_borrowed();
479    /// assert_eq!(c, Some(SEQ));
480    /// assert!(std::ptr::eq(SEQ, c.unwrap()));
481    ///
482    /// let s2 = HipByt::from(SEQ);
483    /// assert!(s2.as_borrowed().is_none());
484    /// ```
485    #[inline]
486    #[must_use]
487    pub const fn as_borrowed(&self) -> Option<&'borrow [u8]> {
488        match self.split() {
489            Split::Allocated(_) | Split::Inline(_) => None,
490            Split::Borrowed(borrowed) => Some(borrowed.as_slice()),
491        }
492    }
493
494    /// Returns `true` if this `HipByt` is a shared heap-allocated byte sequence, `false` otherwise.
495    ///
496    /// # Examples
497    ///
498    /// Basic usage:
499    ///
500    /// ```
501    /// # use hipstr::HipByt;
502    /// let s = HipByt::borrowed(b"hello");
503    /// assert!(!s.is_allocated());
504    ///
505    /// let s = HipByt::from(b"hello");
506    /// assert!(!s.is_allocated());
507    ///
508    /// let s = HipByt::from(b"hello".repeat(10));
509    /// assert!(s.is_allocated());
510    /// ```
511    #[inline]
512    #[must_use]
513    pub const fn is_allocated(&self) -> bool {
514        matches!(self.tag(), Tag::Allocated)
515    }
516
517    /// Returns `true` if the representation is normalized.
518    #[inline]
519    #[must_use]
520    pub const fn is_normalized(&self) -> bool {
521        self.is_inline() || self.is_borrowed() || self.len() > Self::inline_capacity()
522    }
523
524    /// Returns the maximal length for inline byte sequence.
525    #[inline]
526    #[must_use]
527    pub const fn inline_capacity() -> usize {
528        Inline::capacity()
529    }
530
531    /// Returns the total number of bytes the backend can hold.
532    ///
533    /// # Example
534    ///
535    /// ```
536    /// # use hipstr::HipByt;
537    /// let mut vec: Vec<u8> = Vec::with_capacity(42);
538    /// vec.extend(0..30);
539    /// let bytes = HipByt::from(vec);
540    /// assert_eq!(bytes.len(), 30);
541    /// assert_eq!(bytes.capacity(), 42);
542    ///
543    /// let start = bytes.slice(0..29);
544    /// assert_eq!(bytes.capacity(), 42); // same backend, same capacity
545    /// ```
546    #[inline]
547    #[must_use]
548    pub fn capacity(&self) -> usize {
549        match self.split() {
550            Split::Inline(_) => Self::inline_capacity(),
551            Split::Borrowed(borrowed) => borrowed.len(), // provide something to simplify the API
552            Split::Allocated(allocated) => allocated.capacity(),
553        }
554    }
555
556    /// Converts `self` into a [`Vec`] without clone or allocation if possible.
557    ///
558    /// # Errors
559    ///
560    /// Returns `Err(self)` if it is impossible to take ownership of the vector
561    /// backing this `HipByt`.
562    #[inline]
563    #[allow(clippy::option_if_let_else)]
564    pub fn into_vec(self) -> Result<Vec<u8>, Self> {
565        let mut this = ManuallyDrop::new(self);
566        if let Some(allocated) = this.take_allocated() {
567            allocated
568                .try_into_vec()
569                .map_err(|allocated| Union { allocated }.into_raw())
570        } else {
571            Err(ManuallyDrop::into_inner(this))
572        }
573    }
574
575    /// Makes the data owned, copying it if the data is actually borrowed.
576    ///
577    /// Returns a new `HipByt` consuming this one.
578    ///
579    /// # Examples
580    ///
581    /// ```
582    /// # use hipstr::HipByt;
583    /// let v = vec![42; 42];
584    /// let h = HipByt::borrowed(&v[..]);
585    /// // drop(v); // err, v is borrowed
586    /// let h = h.into_owned();
587    /// drop(v); // ok
588    /// assert_eq!(h, [42; 42]);
589    /// ```
590    #[inline]
591    #[must_use]
592    pub fn into_owned(self) -> HipByt<'static, B> {
593        let tag = self.tag();
594        let old = self.union_move(); // self is not dropped!
595
596        // SAFETY: tag representation
597        unsafe {
598            match tag {
599                Tag::Allocated => HipByt::from_allocated(old.allocated),
600                Tag::Borrowed => HipByt::from_slice(old.borrowed.as_slice()),
601                Tag::Inline => HipByt::from_inline(old.inline),
602            }
603        }
604    }
605
606    /// Extracts a slice as its own `HipByt`.
607    ///
608    /// # Panics
609    ///
610    /// Panics if the range is invalid: out of bounds or not at char boundaries.
611    ///
612    /// # Examples
613    ///
614    /// Basic usage:
615    ///
616    /// ```
617    /// # use hipstr::HipByt;
618    /// let a = HipByt::from(b"abc");
619    /// assert_eq!(a.slice(0..2), HipByt::from(b"ab"));
620    /// ```
621    #[must_use]
622    #[track_caller]
623    pub fn slice(&self, range: impl RangeBounds<usize>) -> Self {
624        match self.try_slice(range) {
625            Ok(result) => result,
626            Err(err) => panic!("{}", err),
627        }
628    }
629
630    /// Returns a `HipByt` of a range of bytes in this `HipByt`, if the range is
631    /// valid.
632    ///
633    /// # Errors
634    ///
635    /// This function will return an error if the range is invalid.
636    ///
637    /// # Examples
638    ///
639    /// Basic usage:
640    ///
641    /// ```
642    /// # use hipstr::HipByt;
643    /// let a = HipByt::from(b"abc");
644    /// assert_eq!(a.try_slice(0..2), Ok(HipByt::from(b"ab")));
645    /// assert!(a.try_slice(0..4).is_err());
646    /// ```
647    pub fn try_slice(&self, range: impl RangeBounds<usize>) -> Result<Self, SliceError<B>> {
648        let range = simplify_range(range, self.len())
649            .map_err(|(start, end, kind)| SliceError::new(kind, start, end, self))?;
650        let slice = unsafe { self.range_unchecked(range) };
651        Ok(slice)
652    }
653
654    /// Extracts a slice as its own `HipByt`.
655    ///
656    /// # Safety
657    ///
658    /// `range` must be equivalent to some `a..b` with `a <= b <= len`.
659    ///
660    /// Panics in debug mode. UB in release mode.
661    #[must_use]
662    pub unsafe fn slice_unchecked(&self, range: impl RangeBounds<usize>) -> Self {
663        let start = match range.start_bound() {
664            Bound::Excluded(&n) => n + 1,
665            Bound::Included(&n) => n,
666            Bound::Unbounded => 0,
667        };
668        let end = match range.end_bound() {
669            Bound::Excluded(&n) => n,
670            Bound::Included(&n) => n + 1,
671            Bound::Unbounded => self.len(),
672        };
673        unsafe { self.range_unchecked(start..end) }
674    }
675
676    /// Extracts a slice as its own `HipByt` based on the given subslice `&[u8]`.
677    ///
678    /// # Panics
679    ///
680    /// Panics if `slice` is not part of `self`.
681    ///
682    /// # Examples
683    ///
684    /// Basic usage:
685    ///
686    /// ```
687    /// # use hipstr::HipByt;
688    /// let a = HipByt::from(b"abc");
689    /// let sl = &a[0..2];
690    /// assert_eq!(a.slice_ref(sl), HipByt::from(b"ab"));
691    /// ```
692    #[must_use]
693    #[track_caller]
694    pub fn slice_ref(&self, slice: &[u8]) -> Self {
695        let Some(result) = self.try_slice_ref(slice) else {
696            panic!("slice {slice:p} is not a part of {self:p}")
697        };
698        result
699    }
700
701    /// Returns a slice as it own `HipByt` based on the given subslice `&[u8]`.
702    ///
703    /// # Errors
704    ///
705    /// Returns `None` if `slice` is not a part of `self`.
706    ///
707    /// # Examples
708    ///
709    /// Basic usage:
710    ///
711    /// ```
712    /// # use hipstr::HipByt;
713    /// let a = HipByt::from(b"abc");
714    /// let sl = &a[0..2];
715    /// assert_eq!(a.try_slice_ref(sl), Some(HipByt::from(b"ab")));
716    /// assert!(a.try_slice_ref(b"z").is_none());
717    /// ```
718    #[must_use]
719    pub fn try_slice_ref(&self, range: &[u8]) -> Option<Self> {
720        let slice = range;
721        let range = try_range_of(self.as_slice(), slice)?;
722        Some(unsafe { self.slice_unchecked(range) })
723    }
724
725    /// Returns a mutable handle to the underlying [`Vec`].
726    ///
727    /// This operation may reallocate a new vector if either:
728    ///
729    /// - the representation is not _allocated_ (i.e. _inline_ or _borrowed_),
730    /// - the underlying buffer is shared.
731    ///
732    /// At the end, when the [`RefMut`] is dropped, the underlying
733    /// representation will be owned and normalized. That is, if the actual
734    /// required capacity is less than or equal to the maximal inline capacity,
735    /// the representation is _inline_; otherwise, the representation is
736    /// _allocated_.
737    ///
738    /// # Examples
739    ///
740    /// ```rust
741    /// # use hipstr::HipByt;
742    /// let mut s = HipByt::borrowed(b"abc");
743    /// {
744    ///     let mut r = s.mutate();
745    ///     r.extend_from_slice(b"def");
746    ///     assert_eq!(r.as_slice(), b"abcdef");
747    /// }
748    /// assert_eq!(s, b"abcdef");
749    /// ```
750    #[inline]
751    #[must_use]
752    pub fn mutate(&mut self) -> RefMut<'_, 'borrow, B> {
753        let owned = self.take_vec();
754
755        #[cfg(feature = "bstr")]
756        let owned = owned.into();
757
758        RefMut {
759            result: self,
760            owned,
761        }
762    }
763
764    /// Truncates this `HipByt`, removing all contents.
765    ///
766    /// # Examples
767    ///
768    /// ```
769    /// # use hipstr::HipByt;
770    /// let mut s = HipByt::from(b"foo");
771    ///
772    /// s.clear();
773    ///
774    /// assert!(s.is_empty());
775    /// assert_eq!(0, s.len());
776    /// ```
777    #[inline]
778    pub fn clear(&mut self) {
779        self.truncate(0);
780    }
781
782    /// Removes the last element from this `HipByt` and returns it, or [`None`]
783    /// if it is empty.
784    ///
785    /// # Examples
786    ///
787    /// ```
788    /// # use hipstr::HipByt;
789    ///
790    /// let mut h = HipByt::from(&[1, 2, 3]);
791    /// assert_eq!(h.pop(), Some(3));
792    /// assert_eq!(h, [1, 2]);
793    /// ```
794    pub fn pop(&mut self) -> Option<u8> {
795        let len = self.len();
796        if len == 0 {
797            None
798        } else {
799            let result = unsafe { *self.as_slice().get_unchecked(len - 1) };
800            self.truncate(len - 1);
801            Some(result)
802        }
803    }
804
805    /// Appends a byte to this `HipByt`.
806    ///
807    /// # Examples
808    ///
809    /// ```
810    /// # use hipstr::HipByt;
811    /// let mut bytes = HipByt::from(b"abc");
812    /// bytes.push(b'1');
813    /// bytes.push(b'2');
814    /// bytes.push(b'3');
815    /// assert_eq!(bytes, b"abc123");
816    /// ```
817    #[inline]
818    pub fn push(&mut self, value: u8) {
819        self.push_slice(&[value]);
820    }
821
822    /// Appends all bytes of the slice to this `HipByt`.
823    ///
824    /// # Examples
825    ///
826    /// ```
827    /// # use hipstr::HipByt;
828    /// let mut bytes = HipByt::from(b"abc");
829    /// bytes.push_slice(b"123");
830    /// assert_eq!(bytes, b"abc123");
831    /// ```
832    #[inline]
833    #[doc(alias = "extend_from_slice", alias = "append")]
834    pub fn push_slice(&mut self, addition: &[u8]) {
835        let new_len = self.len() + addition.len();
836
837        if self.is_allocated() {
838            // current allocation may be pushed into it directly?
839
840            // SAFETY: repr checked above
841            let allocated = unsafe { &mut self.union_mut().allocated };
842
843            if allocated.is_unique() {
844                // SAFETY: uniqueness is checked above
845                unsafe {
846                    allocated.push_slice_unchecked(addition);
847                }
848                return;
849            }
850        }
851
852        if new_len <= Self::inline_capacity() {
853            if !self.is_inline() {
854                // make it inline first
855                // SAFETY: `new_len` is checked before, so current len <= INLINE_CAPACITY
856                *self = unsafe { Self::inline_unchecked(self.as_slice()) };
857            }
858
859            // SAFETY: `new_len` is checked above
860            unsafe {
861                self.union_mut().inline.push_slice_unchecked(addition);
862            }
863            return;
864        }
865
866        // requires a new vector
867        let mut vec = Vec::with_capacity(new_len);
868        vec.extend_from_slice(self.as_slice());
869        vec.extend_from_slice(addition);
870
871        // SAFETY: vec's len (new_len) is checked above to be > INLINE_CAPACITY
872        *self = Self::from_vec(vec);
873    }
874
875    /// Creates a new `HipByt` by copying this one `n` times.
876    ///
877    /// This function **will not allocate** if the new length is less than or
878    /// equal to the maximum inline capacity.
879    ///
880    /// # Panics
881    ///
882    /// This function will panic if the capacity would overflow.
883    ///
884    /// # Examples
885    ///
886    /// Basic usage:
887    ///
888    /// ```
889    /// # use hipstr::HipByt;
890    /// assert_eq!(HipByt::from(&[1, 2]).repeat(3), HipByt::from(&[1, 2, 1, 2, 1, 2]));
891    /// ```
892    ///
893    /// A panic upon overflow:
894    ///
895    /// ```should_panic
896    /// // this will panic at runtime
897    /// # use hipstr::HipByt;
898    /// HipByt::from(b"0123456789abcdef").repeat(usize::MAX);
899    /// ```
900    #[must_use]
901    pub fn repeat(&self, n: usize) -> Self {
902        if self.is_empty() || n == 1 {
903            return self.clone();
904        }
905
906        let src_len = self.len();
907        let new_len = src_len.checked_mul(n).expect("capacity overflow");
908        if new_len <= Self::inline_capacity() {
909            let mut inline = Inline::zeroed(new_len);
910            let src = self.as_slice().as_ptr();
911            let mut dst = inline.as_mut_slice().as_mut_ptr();
912
913            // SAFETY: copy only `new_len` bytes with an
914            // upper bound of `INLINE_CAPACITY` checked above
915            unsafe {
916                // could be better from an algorithmic standpoint
917                // but no expected gain for at most 23 bytes on 64 bit platform
918                for _ in 0..n {
919                    ptr::copy_nonoverlapping(src, dst, src_len);
920                    dst = dst.add(src_len);
921                }
922            }
923
924            Self::from_inline(inline)
925        } else {
926            let vec = self.as_slice().repeat(n);
927            Self::from_vec(vec)
928        }
929    }
930
931    /// Returns the remaining spare capacity of the vector as a slice of
932    /// `MaybeUninit<T>`.
933    ///
934    /// The returned slice can be used to fill the vector with data (e.g. by
935    /// reading from a file) before marking the data as initialized using the
936    /// [`set_len`] method.
937    ///
938    /// [`set_len`]: HipByt::set_len
939    #[inline]
940    pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<u8>] {
941        match self.split_mut() {
942            SplitMut::Borrowed(_) => &mut [],
943            SplitMut::Inline(inline) => inline.spare_capacity_mut(),
944            SplitMut::Allocated(allocated) => allocated.spare_capacity_mut(),
945        }
946    }
947
948    /// Forces the length of the vector to `new_len`.
949    ///
950    /// Does not normalize!
951    ///
952    /// # Safety
953    ///
954    /// * If the repr is inline, `new_len` should be must be less than or equal to `INLINE_CAPACITY`.
955    /// * If `new_len` is greater than the current length:
956    ///   * The elements at `old_len..new_len` must be initialized.
957    ///   * The vector should not be shared.
958    pub unsafe fn set_len(&mut self, new_len: usize) {
959        match self.split_mut() {
960            SplitMut::Borrowed(borrowed) => unsafe {
961                borrowed.set_len(new_len);
962            },
963            SplitMut::Inline(inline) => unsafe { inline.set_len(new_len) },
964            SplitMut::Allocated(allocated) => unsafe { allocated.set_len(new_len) },
965        }
966    }
967
968    /// Shortens this `HipByt` to the specified length.
969    ///
970    /// If the new length is greater than the current length, this has no effect.
971    ///
972    /// # Examples
973    ///
974    /// Basic usage:
975    ///
976    /// ```
977    /// # use hipstr::HipByt;
978    /// let mut a = HipByt::from(b"abc");
979    /// a.truncate(1);
980    /// assert_eq!(a, b"a");
981    /// ```
982    #[inline]
983    pub fn truncate(&mut self, new_len: usize) {
984        if new_len < self.len() {
985            if self.is_allocated() && new_len <= Self::inline_capacity() {
986                let new =
987                    unsafe { Self::inline_unchecked(self.as_slice().get_unchecked(..new_len)) };
988                *self = new;
989            } else {
990                // SAFETY: `new_len` is checked above
991                unsafe { self.set_len(new_len) }
992            }
993        }
994        debug_assert!(self.is_normalized());
995    }
996
997    /// Shrinks the capacity of the vector with a lower bound.
998    ///
999    /// The capacity will remain at least as large as the given bound and the
1000    /// actual length of the vector.
1001    ///
1002    /// No-op if the representation is not allocated.
1003    ///
1004    /// # Representation stability
1005    ///
1006    /// The representation may change to inline if the required capacity is
1007    /// smaller than the inline capacity.
1008    ///
1009    /// # Examples
1010    ///
1011    /// ```rust
1012    /// # use hipstr::HipByt;
1013    /// let mut s = HipByt::with_capacity(100);
1014    /// s.shrink_to(4);
1015    /// assert_eq!(s.capacity(), HipByt::inline_capacity());
1016    /// assert!(s.is_inline());
1017    /// ```
1018    pub fn shrink_to(&mut self, min_capacity: usize) {
1019        if self.is_allocated() {
1020            let min_capacity = min_capacity.max(self.len());
1021
1022            if min_capacity > Self::inline_capacity() {
1023                let allocated = unsafe { &mut self.union_mut().allocated };
1024                allocated.shrink_to(min_capacity);
1025            } else {
1026                let new = unsafe { Self::inline_unchecked(self.as_slice()) };
1027                *self = new;
1028            }
1029        }
1030    }
1031
1032    /// Shrinks the capacity of the vector as much as possible.
1033    ///
1034    /// The capacity will remain at least as large as the actual length of the
1035    /// vector.
1036    ///
1037    /// No-op if the representation is not allocated.
1038    ///
1039    /// # Representation stability
1040    ///
1041    /// The allocated representation may change to *inline* if the required
1042    /// capacity is smaller than the inline capacity.
1043    ///
1044    /// # Examples
1045    ///
1046    /// ```rust
1047    /// # use hipstr::HipByt;
1048    /// let mut s = HipByt::with_capacity(100);
1049    /// s.push_slice(b"abc");
1050    /// s.shrink_to_fit();
1051    /// assert_eq!(s.capacity(), HipByt::inline_capacity());
1052    /// ```
1053    pub fn shrink_to_fit(&mut self) {
1054        self.shrink_to(self.len());
1055    }
1056
1057    /// Returns a new `HipByt` containing a copy of this slice where each byte
1058    /// is mapped to its ASCII lower case equivalent.
1059    ///
1060    /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
1061    /// but non-ASCII letters are unchanged.
1062    ///
1063    /// To lowercase the value in-place, use [`make_ascii_lowercase`].
1064    ///
1065    /// # Examples
1066    ///
1067    /// ```rust
1068    /// # use hipstr::HipByt;
1069    /// let h = HipByt::from(b"!abc\0OK\x80");
1070    /// let h2 = h.to_ascii_lowercase();
1071    /// assert_eq!(h2, b"!abc\0ok\x80");
1072    /// ```
1073    ///
1074    /// [`make_ascii_lowercase`]: Self::make_ascii_lowercase
1075    #[inline]
1076    #[must_use]
1077    pub fn to_ascii_lowercase(&self) -> Self {
1078        let mut other = self.clone();
1079        other.to_mut_slice().make_ascii_lowercase();
1080        other
1081    }
1082
1083    /// Converts this slice to its ASCII lower case equivalent in-place.
1084    ///
1085    /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
1086    /// but non-ASCII letters are unchanged.
1087    ///
1088    /// To return a new lowercased value without modifying the existing one, use
1089    /// [`to_ascii_lowercase`].
1090    ///
1091    /// # Examples
1092    ///
1093    /// ```rust
1094    /// # use hipstr::HipByt;
1095    /// let mut h = HipByt::from(b"!abc\0OK\x80");
1096    /// h.make_ascii_lowercase();
1097    /// assert_eq!(h, b"!abc\0ok\x80");
1098    /// ```
1099    ///
1100    /// [`to_ascii_lowercase`]: Self::to_ascii_lowercase
1101    #[inline]
1102    pub fn make_ascii_lowercase(&mut self) {
1103        self.to_mut_slice().make_ascii_lowercase();
1104    }
1105
1106    /// Returns a new `HipByt` containing a copy of this slice where each byte
1107    /// is mapped to its ASCII lower case equivalent.
1108    ///
1109    /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
1110    /// but non-ASCII letters are unchanged.
1111    ///
1112    /// To lowercase the value in-place, use [`make_ascii_lowercase`].
1113    ///
1114    /// # Examples
1115    ///
1116    /// ```rust
1117    /// # use hipstr::HipByt;
1118    /// let h = HipByt::from(b"!abc\0OK\x80");
1119    /// let h2: HipByt = h.to_ascii_uppercase();
1120    /// assert_eq!(h2, b"!ABC\0OK\x80");
1121    /// ```
1122    ///
1123    /// [`make_ascii_lowercase`]: Self::make_ascii_lowercase
1124    #[inline]
1125    #[must_use]
1126    pub fn to_ascii_uppercase(&self) -> Self {
1127        let mut other = self.clone();
1128        other.to_mut_slice().make_ascii_uppercase();
1129        other
1130    }
1131
1132    /// Converts this slice to its ASCII upper case equivalent in-place.
1133    ///
1134    /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
1135    /// but non-ASCII letters are unchanged.
1136    ///
1137    /// To return a new uppercased value without modifying the existing one, use
1138    /// [`to_ascii_uppercase`].
1139    ///
1140    /// # Examples
1141    ///
1142    /// ```rust
1143    /// # use hipstr::HipByt;
1144    /// let mut h = HipByt::from(b"!abc\0OK\x80");
1145    /// h.make_ascii_uppercase();
1146    /// assert_eq!(h, b"!ABC\0OK\x80");
1147    /// ```
1148    ///
1149    /// [`to_ascii_uppercase`]: Self::to_ascii_uppercase
1150    #[inline]
1151    pub fn make_ascii_uppercase(&mut self) {
1152        self.to_mut_slice().make_ascii_uppercase();
1153    }
1154
1155    /// Concatenates some byte slices into a single `HipByt`.
1156    ///
1157    /// The related constructor [`HipByt::concat`] is more general but may be
1158    /// less efficient due to the absence of specialization in Rust.
1159    ///
1160    /// # Examples
1161    ///
1162    /// ```rust
1163    /// # use hipstr::HipByt;
1164    /// let c = HipByt::concat_slices(&[b"hello", b" world", b"!"]);
1165    /// assert_eq!(c, b"hello world!");
1166    /// ```
1167    #[must_use]
1168    pub fn concat_slices(slices: &[&[u8]]) -> Self {
1169        let new_len = slices.iter().map(|e| e.len()).sum();
1170
1171        if new_len == 0 {
1172            return Self::new();
1173        }
1174
1175        let mut new = Self::with_capacity(new_len);
1176        let dst = new.spare_capacity_mut();
1177        let dst_ptr = dst.as_mut_ptr().cast();
1178        let final_ptr = slices.iter().fold(dst_ptr, |dst_ptr, slice| {
1179            let len = slice.len();
1180            unsafe {
1181                ptr::copy_nonoverlapping(slice.as_ptr(), dst_ptr, len);
1182                dst_ptr.add(len)
1183            }
1184        });
1185
1186        debug_assert_eq!(
1187            {
1188                #[expect(clippy::cast_sign_loss)]
1189                let diff_u = unsafe { final_ptr.offset_from(dst_ptr) } as usize;
1190                diff_u
1191            },
1192            new_len
1193        );
1194
1195        unsafe { new.set_len(new_len) };
1196
1197        // check end pointer
1198        debug_assert_eq!(final_ptr.cast_const(), new.as_slice().as_ptr_range().end);
1199
1200        new
1201    }
1202
1203    /// Concatenates some byte slices (or things than can be seen as byte slice) into a new `HipByt`.
1204    ///
1205    /// # Panics
1206    ///
1207    /// During the concatenation, the iterator is ran twice: once to get the
1208    /// expected new length, and again to do the actual copy.
1209    /// If the returned slices are not the same and the new length is greater
1210    /// than the expected length, the function panics (before actually
1211    /// overflowing).
1212    ///
1213    /// This behavior differs from [`std::slice::Concat`] that reallocates when
1214    /// needed.
1215    ///
1216    /// # Examples
1217    ///
1218    /// ```rust
1219    /// # use hipstr::HipByt;
1220    /// let c  = HipByt::concat(&[b"hello".as_slice(), b" world", b"!"]);
1221    /// assert_eq!(c, b"hello world!");
1222    ///
1223    /// let c2 = HipByt::concat([b"hello".to_vec(), b" world".to_vec(), b"!".to_vec()]);
1224    /// assert_eq!(c2, b"hello world!");
1225    ///
1226    /// let c3 = HipByt::concat(vec![b"hello".as_slice(), b" world", b"!"].iter());
1227    /// assert_eq!(c3, b"hello world!");
1228    /// ```
1229    #[must_use]
1230    pub fn concat<E, I>(slices: I) -> Self
1231    where
1232        E: AsRef<[u8]>,
1233        I: IntoIterator<Item = E>,
1234        I::IntoIter: Clone,
1235    {
1236        let slices = slices.into_iter();
1237        let new_len = slices.clone().map(|e| e.as_ref().len()).sum();
1238        if new_len == 0 {
1239            return Self::new();
1240        }
1241
1242        let mut new = Self::with_capacity(new_len);
1243        let dst = new.spare_capacity_mut();
1244        let dst_ptr: *mut u8 = dst.as_mut_ptr().cast();
1245
1246        // compute the final pointer
1247        let final_ptr = unsafe { dst_ptr.add(new_len) };
1248
1249        let _ = slices.fold(dst_ptr, |dst_ptr, slice| {
1250            let slice = slice.as_ref();
1251            let len = slice.len();
1252            let end_ptr = unsafe { dst_ptr.add(len) };
1253            assert!(end_ptr <= final_ptr, "slices changed during concat");
1254            unsafe {
1255                ptr::copy_nonoverlapping(slice.as_ptr(), dst_ptr, len);
1256                end_ptr
1257            }
1258        });
1259
1260        unsafe { new.set_len(new_len) };
1261        debug_assert_eq!(final_ptr.cast_const(), new.as_slice().as_ptr_range().end);
1262
1263        new
1264    }
1265
1266    /// Joins some byte slices with the given separator into a new `HipByt`, i.e.
1267    /// concatenates some byte slices, with a separator byte inserted between
1268    /// each pair of byte slices.
1269    ///
1270    /// The related constructor [`HipByt::join`] is more general but may be less
1271    /// efficient due to the absence of specialization in Rust.
1272    ///
1273    /// # Examples
1274    ///
1275    /// ```
1276    /// # use hipstr::HipByt;
1277    /// let slices: &[&[u8]] = &[b"hello", b"world", b"rust"];
1278    /// let sep = b", ";
1279    /// let joined = HipByt::join_slices(slices, sep);
1280    /// assert_eq!(joined, b"hello, world, rust");
1281    /// ```
1282    #[must_use]
1283    pub fn join_slices(slices: &[&[u8]], sep: impl AsRef<[u8]>) -> Self {
1284        let slices_len = slices.len();
1285        if slices_len == 0 {
1286            return Self::new();
1287        }
1288
1289        let sep = sep.as_ref();
1290        let sep_len = sep.len();
1291
1292        // computes the final length
1293        let slices_sum: usize = slices.iter().copied().map(<[_]>::len).sum();
1294        let new_len = (slices_len - 1) * sep_len + slices_sum;
1295        if new_len == 0 {
1296            return Self::new();
1297        }
1298
1299        let mut new = Self::with_capacity(new_len);
1300        let dst = new.spare_capacity_mut();
1301        let dst_ptr: *mut u8 = dst.as_mut_ptr().cast();
1302
1303        // compute the final pointer
1304        let final_ptr = unsafe { dst_ptr.add(new_len) };
1305
1306        let mut iter = slices.iter().copied();
1307
1308        // get first slice
1309        // SAFETY: segments > 0 is checked above
1310        let slice = unsafe { iter.next().unwrap_unchecked() };
1311        let len = slice.len();
1312        // SAFETY: dst_ptr + len cannot overflow
1313        let end_ptr = unsafe { dst_ptr.add(len) };
1314        debug_assert!(end_ptr <= final_ptr, "slices changed during concat");
1315        unsafe {
1316            ptr::copy_nonoverlapping(slice.as_ptr(), dst_ptr, len);
1317        }
1318
1319        // remainder
1320        let _ = iter.fold(end_ptr, |mut dst_ptr, slice| {
1321            let end_ptr = unsafe { dst_ptr.add(sep_len) };
1322            debug_assert!(end_ptr <= final_ptr, "slices changed during concat");
1323            unsafe {
1324                ptr::copy_nonoverlapping(sep.as_ptr(), dst_ptr, sep_len);
1325            }
1326            dst_ptr = end_ptr;
1327
1328            let len = slice.len();
1329            let end_ptr = unsafe { dst_ptr.add(len) };
1330            debug_assert!(end_ptr <= final_ptr, "slices changed during concat");
1331            unsafe {
1332                ptr::copy_nonoverlapping(slice.as_ptr(), dst_ptr, len);
1333            }
1334
1335            end_ptr
1336        });
1337
1338        unsafe { new.set_len(new_len) };
1339        debug_assert_eq!(final_ptr.cast_const(), new.as_slice().as_ptr_range().end);
1340
1341        new
1342    }
1343
1344    /// Joins some byte slices (or things than can be seen as byte slice) with
1345    /// the given separator into a new `HipByt`.
1346    ///
1347    ///
1348    /// # Panics
1349    ///
1350    /// During the concatenation the iterator is ran twice: once to get the
1351    /// expected new length, and again to do the actual copy.
1352    /// If the returned strings are not the same and the new length is greater
1353    /// than the expected length, the function panics (before actually
1354    /// overflowing).
1355    ///
1356    /// This behavior differs from [`std::slice::Join`] that reallocates if needed.
1357    ///
1358    /// # Examples
1359    ///
1360    /// ```rust
1361    /// # use hipstr::HipByt;
1362    /// let slices: &[&[u8]] = &[b"hello", b"world", b"rust"];
1363    /// let sep = b", ";
1364    /// let joined = HipByt::join(slices, sep);
1365    /// assert_eq!(joined, b"hello, world, rust");
1366    ///
1367    /// let joined = HipByt::join([b"hello".to_vec(), b"world".to_vec(), b"rust".to_vec()], sep.to_vec());
1368    /// assert_eq!(joined, b"hello, world, rust");
1369    ///
1370    /// let joined = HipByt::join(slices.to_vec().iter(), sep);
1371    /// assert_eq!(joined, b"hello, world, rust");
1372    /// ```
1373    #[must_use]
1374    pub fn join<E, I>(slices: I, sep: impl AsRef<[u8]>) -> Self
1375    where
1376        E: AsRef<[u8]>,
1377        I: IntoIterator<Item = E>,
1378        I::IntoIter: Clone,
1379    {
1380        let mut iter = slices.into_iter();
1381
1382        // computes the final length
1383        let (segments, segments_len) = iter.clone().fold((0, 0), |(count, length), e| {
1384            (count + 1, length + e.as_ref().len())
1385        });
1386        if segments == 0 {
1387            return Self::new();
1388        }
1389        let sep = sep.as_ref();
1390        let sep_len = sep.len();
1391        let new_len = (segments - 1) * sep_len + segments_len;
1392
1393        let mut new = Self::with_capacity(new_len);
1394        let dst = new.spare_capacity_mut();
1395        let dst_ptr: *mut u8 = dst.as_mut_ptr().cast();
1396
1397        // computes the final pointer
1398        // SAFETY: `new_len` is the length of raw
1399        let final_ptr = unsafe { dst_ptr.add(new_len) };
1400
1401        if let Some(first) = iter.next() {
1402            let first = first.as_ref();
1403            let len = first.len();
1404
1405            let end_ptr = unsafe { dst_ptr.add(first.len()) };
1406            assert!(end_ptr <= final_ptr, "slices changed during concat");
1407            unsafe {
1408                ptr::copy_nonoverlapping(first.as_ptr(), dst_ptr, len);
1409            }
1410
1411            let _ = iter.fold(end_ptr, |mut dst_ptr, slice| {
1412                let end_ptr = unsafe { dst_ptr.add(sep_len) };
1413                assert!(end_ptr <= final_ptr, "slices changed during concat");
1414                unsafe {
1415                    ptr::copy_nonoverlapping(sep.as_ptr(), dst_ptr, sep_len);
1416                }
1417                dst_ptr = end_ptr;
1418
1419                let slice = slice.as_ref();
1420                let len = slice.len();
1421                let end_ptr = unsafe { dst_ptr.add(len) };
1422                assert!(end_ptr <= final_ptr, "slices changed during concat");
1423                unsafe {
1424                    ptr::copy_nonoverlapping(slice.as_ptr(), dst_ptr, len);
1425                }
1426                end_ptr
1427            });
1428        }
1429
1430        unsafe { new.set_len(new_len) };
1431        debug_assert_eq!(final_ptr.cast_const(), new.as_slice().as_ptr_range().end);
1432
1433        new
1434    }
1435}
1436
1437impl<B> HipByt<'static, B>
1438where
1439    B: Backend,
1440{
1441    /// Creates a new `HipByt` from a `'static` slice without copying the slice.
1442    ///
1443    /// Handy shortcut to make a `HipByt<'static, _>` out of a `&'static [u8]`.
1444    ///
1445    /// # Representation
1446    ///
1447    /// The created `HipByt` is _borrowed_.
1448    ///
1449    /// # Examples
1450    ///
1451    /// Basic usage:
1452    ///
1453    /// ```
1454    /// # use hipstr::HipByt;
1455    /// let b = HipByt::from_static(b"hello\0");
1456    /// assert_eq!(b.len(), 6);
1457    /// ```
1458    #[inline]
1459    #[must_use]
1460    pub const fn from_static(bytes: &'static [u8]) -> Self {
1461        Self::borrowed(bytes)
1462    }
1463}
1464
1465impl<B> Default for HipByt<'_, B>
1466where
1467    B: Backend,
1468{
1469    #[inline]
1470    fn default() -> Self {
1471        Self::new()
1472    }
1473}
1474
1475impl<B> Deref for HipByt<'_, B>
1476where
1477    B: Backend,
1478{
1479    type Target = Slice;
1480
1481    #[inline]
1482    fn deref(&self) -> &Self::Target {
1483        self.as_ref()
1484    }
1485}
1486
1487impl<B> Borrow<[u8]> for HipByt<'_, B>
1488where
1489    B: Backend,
1490{
1491    #[inline]
1492    fn borrow(&self) -> &[u8] {
1493        self.as_slice()
1494    }
1495}
1496
1497impl<B> Hash for HipByt<'_, B>
1498where
1499    B: Backend,
1500{
1501    #[inline]
1502    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
1503        self.as_slice().hash(state);
1504    }
1505}
1506
1507// Formatting
1508
1509impl<B> fmt::Debug for HipByt<'_, B>
1510where
1511    B: Backend,
1512{
1513    #[inline]
1514    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1515        self.as_slice().fmt(f)
1516    }
1517}
1518
1519/// Slice error kinds.
1520#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1521pub enum SliceErrorKind {
1522    /// Start index should be less or equal to the end index
1523    StartGreaterThanEnd,
1524
1525    /// Start index out of bounds
1526    StartOutOfBounds,
1527
1528    /// End index out of bounds
1529    EndOutOfBounds,
1530}
1531
1532/// Normalizes any [`RangeBounds`] to a [`Range`].
1533pub(crate) fn simplify_range(
1534    range: impl RangeBounds<usize>,
1535    len: usize,
1536) -> Result<Range<usize>, (usize, usize, SliceErrorKind)> {
1537    simplify_range_mono(
1538        range.start_bound().cloned(),
1539        range.end_bound().cloned(),
1540        len,
1541    )
1542}
1543
1544const fn simplify_range_mono(
1545    start: Bound<usize>,
1546    end: Bound<usize>,
1547    len: usize,
1548) -> Result<Range<usize>, (usize, usize, SliceErrorKind)> {
1549    let start = match start {
1550        Bound::Included(start) => start,
1551        Bound::Excluded(start) => start + 1,
1552        Bound::Unbounded => 0,
1553    };
1554    let end = match end {
1555        Bound::Included(end) => end + 1,
1556        Bound::Excluded(end) => end,
1557        Bound::Unbounded => len,
1558    };
1559    if start > len {
1560        Err((start, end, SliceErrorKind::StartOutOfBounds))
1561    } else if end > len {
1562        Err((start, end, SliceErrorKind::EndOutOfBounds))
1563    } else if start > end {
1564        Err((start, end, SliceErrorKind::StartGreaterThanEnd))
1565    } else {
1566        Ok(Range { start, end })
1567    }
1568}
1569
1570/// A possible error value when slicing a [`HipByt`].
1571///
1572/// This type is the error type for [`HipByt::try_slice`].
1573pub struct SliceError<'a, 'borrow, B>
1574where
1575    B: Backend,
1576{
1577    kind: SliceErrorKind,
1578    start: usize,
1579    end: usize,
1580    bytes: &'a HipByt<'borrow, B>,
1581}
1582
1583impl<B> Clone for SliceError<'_, '_, B>
1584where
1585    B: Backend,
1586{
1587    fn clone(&self) -> Self {
1588        *self
1589    }
1590}
1591
1592impl<B> Copy for SliceError<'_, '_, B> where B: Backend {}
1593
1594impl<B> Eq for SliceError<'_, '_, B> where B: Backend {}
1595
1596impl<B> PartialEq for SliceError<'_, '_, B>
1597where
1598    B: Backend,
1599{
1600    fn eq(&self, other: &Self) -> bool {
1601        self.kind == other.kind
1602            && self.start == other.start
1603            && self.end == other.end
1604            && self.bytes == other.bytes
1605    }
1606}
1607
1608impl<'a, B> SliceError<'_, 'a, B>
1609where
1610    B: Backend,
1611{
1612    const fn new(kind: SliceErrorKind, start: usize, end: usize, bytes: &'a HipByt<B>) -> Self {
1613        Self {
1614            kind,
1615            start,
1616            end,
1617            bytes,
1618        }
1619    }
1620
1621    /// Returns the kind of error.
1622    #[inline]
1623    #[must_use]
1624    pub const fn kind(&self) -> SliceErrorKind {
1625        self.kind
1626    }
1627
1628    /// Returns the start of the requested range.
1629    #[inline]
1630    #[must_use]
1631    pub const fn start(&self) -> usize {
1632        self.start
1633    }
1634
1635    /// Returns the end of the requested range.
1636    #[inline]
1637    #[must_use]
1638    pub const fn end(&self) -> usize {
1639        self.end
1640    }
1641
1642    /// Returns the _normalized_ requested range.
1643    #[inline]
1644    #[must_use]
1645    pub const fn range(&self) -> Range<usize> {
1646        self.start..self.end
1647    }
1648
1649    /// Returns a reference to the source `HipByt` to slice.
1650    #[inline]
1651    #[must_use]
1652    pub const fn source(&self) -> &HipByt<B> {
1653        self.bytes
1654    }
1655}
1656
1657impl<B> fmt::Debug for SliceError<'_, '_, B>
1658where
1659    B: Backend,
1660{
1661    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1662        f.debug_struct("SliceError")
1663            .field("kind", &self.kind)
1664            .field("start", &self.start)
1665            .field("end", &self.end)
1666            .field("bytes", &self.bytes)
1667            .finish()
1668    }
1669}
1670
1671impl<B> fmt::Display for SliceError<'_, '_, B>
1672where
1673    B: Backend,
1674{
1675    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1676        match self.kind {
1677            SliceErrorKind::StartGreaterThanEnd => {
1678                write!(f, "range starts at {} but ends at {}", self.start, self.end)
1679            }
1680            SliceErrorKind::StartOutOfBounds => write!(
1681                f,
1682                "range start index {} out of bounds for slice of length {}",
1683                self.start,
1684                self.bytes.len()
1685            ),
1686            SliceErrorKind::EndOutOfBounds => {
1687                write!(
1688                    f,
1689                    "range end index {} out of bounds for slice of length {}",
1690                    self.end,
1691                    self.bytes.len()
1692                )
1693            }
1694        }
1695    }
1696}
1697
1698impl<B> Error for SliceError<'_, '_, B> where B: Backend {}
1699
1700/// A wrapper type for a mutably borrowed vector out of a [`HipByt`].
1701pub struct RefMut<'a, 'borrow, B>
1702where
1703    B: Backend,
1704{
1705    result: &'a mut HipByt<'borrow, B>,
1706    owned: Owned,
1707}
1708
1709impl<B> Drop for RefMut<'_, '_, B>
1710where
1711    B: Backend,
1712{
1713    fn drop(&mut self) {
1714        let owned = core::mem::take(&mut self.owned);
1715        *self.result = HipByt::from(owned);
1716    }
1717}
1718
1719impl<B> Deref for RefMut<'_, '_, B>
1720where
1721    B: Backend,
1722{
1723    type Target = Owned;
1724
1725    fn deref(&self) -> &Self::Target {
1726        &self.owned
1727    }
1728}
1729
1730impl<B> DerefMut for RefMut<'_, '_, B>
1731where
1732    B: Backend,
1733{
1734    fn deref_mut(&mut self) -> &mut Self::Target {
1735        &mut self.owned
1736    }
1737}