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}