faststr_fork/
lib.rs

1#![cfg_attr(not(doctest), doc = include_str!("../README.md"))]
2
3use bytes::{Bytes, BytesMut};
4use simdutf8::basic::{from_utf8, Utf8Error};
5use std::{
6    borrow::{Borrow, Cow},
7    cmp::Ordering,
8    convert::Infallible,
9    fmt, hash,
10    hint::unreachable_unchecked,
11    iter,
12    mem::MaybeUninit,
13    ops::Deref,
14    str::FromStr,
15    sync::Arc,
16};
17
18/// `FastStr` is a string type that try to avoid the cost of clone.
19#[derive(Clone)]
20pub struct FastStr(Repr);
21
22#[cfg(all(test, target_pointer_width = "64"))]
23mod size_asserts {
24    static_assertions::assert_eq_size!(super::FastStr, [u8; 40]); // 40 bytes
25}
26
27impl FastStr {
28    /// Create a new `FastStr` from any type `T` that can be converted to a string slice
29    /// (e.g., `String`, `&str`, `Arc<String>`, `Arc<str>`).
30    ///
31    /// For small strings (up to 24 bytes), this avoids heap allocation, and copies on stack.
32    #[inline]
33    pub fn new<T>(text: T) -> Self
34    where
35        T: AsRef<str>,
36    {
37        Self(Repr::new(text))
38    }
39
40    /// Create a new inline `FastStr` (up to 24 bytes long) from a string slice `s`.
41    ///
42    /// This constructor panics if the length of `s` is greater than 24.
43    ///
44    /// Note: the inline length is not guaranteed.
45    #[inline]
46    #[doc(hidden)]
47    #[deprecated(
48        since = "0.2.13",
49        note = "The inline threshold is not stable. Please use `FastStr::new()` instead."
50    )]
51    pub fn new_inline(s: &str) -> Self {
52        Self(Repr::new_inline(s))
53    }
54
55    /// Create a new `FastStr` from a byte slice `v`, returning a
56    /// `Result<FastStr, Utf8Error>` if the bytes are not valid UTF-8.
57    #[inline]
58    pub fn new_u8_slice(v: &[u8]) -> Result<Self, Utf8Error> {
59        let s = from_utf8(v)?;
60        Ok(Self::new(s))
61    }
62
63    /// Create a new `FastStr` from a byte slice `v`. This is an unsafe method because
64    /// the caller must ensure that the bytes passed to it are valid UTF-8.
65    ///
66    /// # Safety
67    ///
68    /// `v` must be valid UTF-8.
69    #[inline]
70    pub unsafe fn new_u8_slice_unchecked(v: &[u8]) -> Self {
71        let s = unsafe { std::str::from_utf8_unchecked(v) };
72        Self::new(s)
73    }
74
75    /// Create an empty `FastStr`.
76    #[inline]
77    pub const fn empty() -> Self {
78        Self(Repr::empty())
79    }
80
81    /// Create a new `FastStr` from an `Arc<str>`.
82    #[inline]
83    pub fn from_arc_str(s: Arc<str>) -> Self {
84        Self(Repr::from_arc_str(s))
85    }
86
87    /// Create a new `FastStr` from a `String`.
88    #[inline]
89    pub fn from_string(s: String) -> Self {
90        Self(Repr::from_string(s))
91    }
92
93    /// Create a new `FastStr` from an `Arc<String>`.
94    #[inline]
95    pub fn from_arc_string(s: Arc<String>) -> Self {
96        Self(Repr::from_arc_string(s))
97    }
98
99    /// Create a new `FastStr` from a `BytesMut` object, returning a
100    /// `Result<FastStr, Utf8Error>` if the bytes are not valid UTF-8.
101    #[inline]
102    pub fn from_bytes(b: Bytes) -> Result<Self, Utf8Error> {
103        from_utf8(&b)?;
104        // Safety: we have checked b is utf-8 valid
105        Ok(unsafe { Self::from_bytes_unchecked(b) })
106    }
107
108    /// Create a new `FastStr` from a `Bytes` object. This is an unsafe method
109    /// because the caller must ensure that the bytes passed to it are valid UTF-8.
110    ///
111    /// # Safety
112    ///
113    /// `b` must be valid UTF-8.
114    #[inline]
115    pub unsafe fn from_bytes_unchecked(b: Bytes) -> Self {
116        Self(Repr::from_bytes_unchecked(b))
117    }
118
119    /// Create a new `FastStr` from a `BytesMut` object, returning a
120    /// `Result<FastStr, Utf8Error>` if the bytes are not valid UTF-8.
121    #[inline]
122    pub fn from_bytes_mut(b: BytesMut) -> Result<Self, Utf8Error> {
123        from_utf8(&b)?;
124        // Safety: we have checked b is utf-8 valid
125        Ok(unsafe { Self::from_bytes_mut_unchecked(b) })
126    }
127
128    /// Create a new `FastStr` from a `BytesMut` object. This is an unsafe method
129    /// because the caller must ensure that the bytes passed to it are valid UTF-8.
130    ///
131    /// # Safety
132    ///
133    /// `b` must be valid UTF-8.
134    #[inline]
135    pub unsafe fn from_bytes_mut_unchecked(b: BytesMut) -> Self {
136        let v = b.freeze();
137        Self::from_bytes_unchecked(v)
138    }
139
140    /// Create a new `FastStr` from a static string slice.
141    #[inline]
142    pub const fn from_static_str(s: &'static str) -> Self {
143        Self(Repr::StaticStr(s))
144    }
145
146    /// Create a new `FastStr` from a `Vec<u8>`, returning a
147    /// `Result<FastStr, Utf8Error>` if the bytes are not valid UTF-8.
148    #[inline]
149    pub fn from_vec_u8(v: Vec<u8>) -> Result<Self, Utf8Error> {
150        from_utf8(&v)?;
151        // Safety: we have checked b is utf-8 valid
152        Ok(unsafe { Self::from_vec_u8_unchecked(v) })
153    }
154
155    /// Create a new `FastStr` from a `Vec<u8>`. This is an unsafe method because
156    /// the caller must ensure that the bytes passed to it are valid UTF-8.
157    ///
158    /// # Safety
159    ///
160    /// `v` must be valid UTF-8.
161    #[inline]
162    pub unsafe fn from_vec_u8_unchecked(v: Vec<u8>) -> Self {
163        Self::from_bytes_unchecked(v.into())
164    }
165
166    /// Create a new `FastStr` from a byte slice `v`, returning a
167    /// `Result<FastStr, Utf8Error>` if the bytes are not valid UTF-8.
168    #[deprecated(
169        since = "0.2.13",
170        note = "This method is not really zero-cost. Use `new_u8_slice` instead."
171    )]
172    #[inline]
173    pub fn from_u8_slice(v: &[u8]) -> Result<Self, Utf8Error> {
174        Self::new_u8_slice(v)
175    }
176
177    /// Create a new `FastStr` from a byte slice `v`. This is an unsafe method because
178    /// the caller must ensure that the bytes passed to it are valid UTF-8.
179    ///
180    /// # Safety
181    ///
182    /// `v` must be valid UTF-8.
183    #[deprecated(
184        since = "0.2.13",
185        note = "This method is not really zero-cost. Use `new_u8_slice_unchecked` instead."
186    )]
187    #[inline]
188    pub unsafe fn from_u8_slice_unchecked(v: &[u8]) -> Self {
189        Self::new_u8_slice_unchecked(v)
190    }
191}
192
193impl FastStr {
194    /// Return the `FastStr` as a string slice.
195    #[inline(always)]
196    pub fn as_str(&self) -> &str {
197        self.0.as_str()
198    }
199
200    /// Consumes and converts the `FastStr` into a `Bytes` object.
201    #[inline(always)]
202    pub fn into_bytes(self) -> Bytes {
203        self.0.into_bytes()
204    }
205
206    /// Return the `FastStr` length.
207    #[inline(always)]
208    pub fn len(&self) -> usize {
209        self.0.len()
210    }
211
212    /// Return `true` if the `FastStr` is empty.
213    #[inline(always)]
214    pub fn is_empty(&self) -> bool {
215        self.0.is_empty()
216    }
217
218    /// Return a new `FastStr` that represents a subset of the current string.
219    #[inline(always)]
220    pub fn slice_ref(&self, subset: &str) -> Self {
221        Self(self.0.slice_ref(subset.as_bytes()))
222    }
223
224    /// Return a new `FastStr` starting at index `start` and ending at index `end`. `[start..end)`
225    ///
226    /// # Safety
227    ///
228    /// The caller must guarantee that the string between `start` and `end` is valid utf-8.
229    #[inline(always)]
230    pub unsafe fn index(&self, start: usize, end: usize) -> Self {
231        Self(self.0.slice_ref(&self.as_bytes()[start..end]))
232    }
233
234    /// Consumes and converts the `FastStr` into a `String` at best effort.
235    #[deprecated(
236        since = "0.2.13",
237        note = "This method does not really express the `into` semantic. Use `to_string` instead."
238    )]
239    #[inline(always)]
240    pub fn into_string(self) -> String {
241        #[allow(deprecated)]
242        self.0.into_string()
243    }
244
245    /// If the inner repr of FastStr is a Bytes, then it will be deep cloned and returned as a new FastStr.
246    /// Otherwise, it will return a new FastStr with the same repr which has no cost.
247    ///
248    /// This is used to free the original memory of the Bytes.
249    ///
250    /// This is not stable and may be removed or renamed in the future.
251    #[inline]
252    #[doc(hidden)]
253    pub fn deep_clone_bytes(&self) -> Self {
254        Self(self.0.deep_clone_bytes())
255    }
256
257    fn from_char_iter<I: iter::Iterator<Item = char>>(mut iter: I) -> Self {
258        let (min_size, _) = iter.size_hint();
259        if min_size > INLINE_CAP {
260            let s: String = iter.collect();
261            return Self(Repr::Bytes(Bytes::from(s)));
262        }
263        let mut len = 0;
264        let mut buf = [0u8; INLINE_CAP];
265        while let Some(ch) = iter.next() {
266            let size = ch.len_utf8();
267            if size + len > INLINE_CAP {
268                let (min_remaining, _) = iter.size_hint();
269                let mut s = String::with_capacity(size + len + min_remaining);
270                s.push_str(unsafe { core::str::from_utf8_unchecked(&buf[..len]) });
271                s.push(ch);
272                s.extend(iter);
273                return Self(Repr::Bytes(Bytes::from(s)));
274            }
275            ch.encode_utf8(&mut buf[len..]);
276            len += size;
277        }
278        Self(Repr::Inline { len: len as u8, buf })
279    }
280}
281
282impl Default for FastStr {
283    #[inline]
284    fn default() -> Self {
285        Self::empty()
286    }
287}
288
289impl AsRef<[u8]> for FastStr {
290    #[inline]
291    fn as_ref(&self) -> &[u8] {
292        self.0.as_ref()
293    }
294}
295
296impl AsRef<str> for FastStr {
297    #[inline(always)]
298    fn as_ref(&self) -> &str {
299        self.as_str()
300    }
301}
302impl Deref for FastStr {
303    type Target = str;
304
305    #[inline]
306    fn deref(&self) -> &str {
307        self.as_str()
308    }
309}
310
311impl From<FastStr> for String {
312    #[inline]
313    fn from(val: FastStr) -> Self {
314        #[allow(deprecated)]
315        val.into_string()
316    }
317}
318
319impl From<FastStr> for Bytes {
320    #[inline]
321    fn from(val: FastStr) -> Self {
322        val.into_bytes()
323    }
324}
325
326impl PartialEq<FastStr> for FastStr {
327    #[inline]
328    fn eq(&self, other: &FastStr) -> bool {
329        self.as_str() == other.as_str()
330    }
331}
332
333impl Eq for FastStr {}
334
335impl PartialEq<str> for FastStr {
336    #[inline]
337    fn eq(&self, other: &str) -> bool {
338        self.as_str() == other
339    }
340}
341
342impl PartialEq<FastStr> for str {
343    #[inline]
344    fn eq(&self, other: &FastStr) -> bool {
345        other == self
346    }
347}
348
349impl<'a> PartialEq<&'a str> for FastStr {
350    #[inline]
351    fn eq(&self, other: &&'a str) -> bool {
352        self == *other
353    }
354}
355
356impl<'a> PartialEq<FastStr> for &'a str {
357    #[inline]
358    fn eq(&self, other: &FastStr) -> bool {
359        *self == other
360    }
361}
362
363impl PartialEq<String> for FastStr {
364    #[inline]
365    fn eq(&self, other: &String) -> bool {
366        self.as_str() == other
367    }
368}
369
370impl PartialEq<FastStr> for String {
371    #[inline]
372    fn eq(&self, other: &FastStr) -> bool {
373        other == self
374    }
375}
376
377impl<'a> PartialEq<&'a String> for FastStr {
378    #[inline]
379    fn eq(&self, other: &&'a String) -> bool {
380        self == *other
381    }
382}
383
384impl<'a> PartialEq<FastStr> for &'a String {
385    #[inline]
386    fn eq(&self, other: &FastStr) -> bool {
387        *self == other
388    }
389}
390
391impl Ord for FastStr {
392    #[inline]
393    fn cmp(&self, other: &FastStr) -> Ordering {
394        self.as_str().cmp(other.as_str())
395    }
396}
397
398impl PartialOrd for FastStr {
399    #[inline]
400    fn partial_cmp(&self, other: &FastStr) -> Option<Ordering> {
401        Some(self.cmp(other))
402    }
403}
404
405impl hash::Hash for FastStr {
406    #[inline]
407    fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
408        self.as_str().hash(hasher)
409    }
410}
411
412impl fmt::Debug for FastStr {
413    #[inline]
414    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
415        fmt::Debug::fmt(self.as_str(), f)
416    }
417}
418
419impl fmt::Display for FastStr {
420    #[inline]
421    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
422        fmt::Display::fmt(self.as_str(), f)
423    }
424}
425
426impl iter::FromIterator<char> for FastStr {
427    #[inline]
428    fn from_iter<I: iter::IntoIterator<Item = char>>(iter: I) -> FastStr {
429        let iter = iter.into_iter();
430        Self::from_char_iter(iter)
431    }
432}
433
434fn build_from_str_iter<T>(mut iter: impl Iterator<Item = T>) -> FastStr
435where
436    T: AsRef<str>,
437    String: iter::Extend<T>,
438{
439    let mut len = 0;
440    let mut buf = [0u8; INLINE_CAP];
441    while let Some(slice) = iter.next() {
442        let slice = slice.as_ref();
443        let size = slice.len();
444        if size + len > INLINE_CAP {
445            let mut s = String::with_capacity(size + len);
446            s.push_str(unsafe { core::str::from_utf8_unchecked(&buf[..len]) });
447            s.push_str(slice);
448            s.extend(iter);
449            return FastStr(Repr::Bytes(Bytes::from(s)));
450        }
451        buf[len..][..size].copy_from_slice(slice.as_bytes());
452        len += size;
453    }
454    FastStr(Repr::Inline { len: len as u8, buf })
455}
456
457impl iter::FromIterator<String> for FastStr {
458    #[inline]
459    fn from_iter<I: iter::IntoIterator<Item = String>>(iter: I) -> FastStr {
460        build_from_str_iter(iter.into_iter())
461    }
462}
463
464impl<'a> iter::FromIterator<&'a String> for FastStr {
465    #[inline]
466    fn from_iter<I: iter::IntoIterator<Item = &'a String>>(iter: I) -> FastStr {
467        FastStr::from_iter(iter.into_iter().map(|x| x.as_str()))
468    }
469}
470
471impl<'a> iter::FromIterator<&'a str> for FastStr {
472    #[inline]
473    fn from_iter<I: iter::IntoIterator<Item = &'a str>>(iter: I) -> FastStr {
474        build_from_str_iter(iter.into_iter())
475    }
476}
477
478impl Borrow<str> for FastStr {
479    #[inline]
480    fn borrow(&self) -> &str {
481        self.as_str()
482    }
483}
484
485impl FromStr for FastStr {
486    type Err = Infallible;
487
488    #[inline]
489    fn from_str(s: &str) -> Result<FastStr, Self::Err> {
490        Ok(FastStr::new(s))
491    }
492}
493
494// We need to wait for specilization to be stable to implement this.
495// impl<T> From<T> for FastStr
496// where
497//     T: AsRef<str>,
498// {
499//     #[inline]
500//     fn from(text: T) -> Self {
501//         Self::new(text)
502//     }
503// }
504
505impl From<Arc<str>> for FastStr {
506    #[inline]
507    fn from(val: Arc<str>) -> Self {
508        Self::from_arc_str(val)
509    }
510}
511
512impl From<String> for FastStr {
513    #[inline]
514    fn from(val: String) -> Self {
515        Self::new(val)
516    }
517}
518
519impl From<Arc<String>> for FastStr {
520    #[inline]
521    fn from(val: Arc<String>) -> Self {
522        Self::from_arc_string(val)
523    }
524}
525
526impl From<&'static str> for FastStr {
527    #[inline]
528    fn from(val: &'static str) -> Self {
529        Self::from_static_str(val)
530    }
531}
532
533impl From<Cow<'static, str>> for FastStr {
534    #[inline]
535    fn from(val: Cow<'static, str>) -> Self {
536        match val {
537            Cow::Borrowed(s) => Self::from_static_str(s),
538            Cow::Owned(s) => Self::from_string(s),
539        }
540    }
541}
542
543#[derive(Debug, Clone, PartialEq, Eq, Hash)]
544pub struct FastStrOption(Option<FastStr>);
545
546impl FastStrOption {
547    pub fn new(inner: Option<FastStr>) -> Self {
548        Self(inner)
549    }
550}
551
552impl Deref for FastStrOption {
553    type Target = Option<FastStr>;
554
555    #[inline]
556    fn deref(&self) -> &Self::Target {
557        &self.0
558    }
559}
560
561impl From<Option<String>> for FastStrOption {
562    #[inline]
563    fn from(val: Option<String>) -> Self {
564        Self(val.map(FastStr::from))
565    }
566}
567
568const INLINE_CAP: usize = 38;
569
570#[derive(Clone)]
571enum Repr {
572    Empty,
573    Bytes(Bytes),
574    ArcStr(Arc<str>),
575    ArcString(Arc<String>),
576    StaticStr(&'static str),
577    Inline { len: u8, buf: [u8; INLINE_CAP] },
578}
579
580impl Repr {
581    #[inline]
582    fn new<T>(text: T) -> Self
583    where
584        T: AsRef<str>,
585    {
586        let text = text.as_ref();
587        if text.is_empty() {
588            return Self::Empty;
589        }
590        {
591            let len = text.len();
592            if len <= INLINE_CAP {
593                // Safety: we have checked the length of text <= `INLINE_CAP`.
594                return unsafe { Self::new_inline_impl(text) };
595            }
596        }
597        Self::ArcString(Arc::new(text.to_string()))
598        // Self::Bytes(Bytes::copy_from_slice(text.as_bytes()))
599    }
600
601    fn new_inline(s: &str) -> Self {
602        if s.len() > INLINE_CAP {
603            panic!("[FastStr] string is too long to inline");
604        }
605        // Safety: we have checked the length of s <= `INLINE_CAP`.
606        unsafe { Self::new_inline_impl(s) }
607    }
608
609    /// # Safety
610    ///
611    /// The length of `s` must be <= `INLINE_CAP`.
612    unsafe fn new_inline_impl(s: &str) -> Self {
613        #[allow(invalid_value, clippy::uninit_assumed_init)]
614        let mut inl = Self::Inline {
615            len: s.len() as u8,
616            buf: MaybeUninit::uninit().assume_init(),
617        };
618        match inl {
619            Self::Inline {
620                ref mut len,
621                ref mut buf,
622            } => {
623                // We can't guarantee if it's nonoverlapping here, so we can only use std::ptr::copy.
624                std::ptr::copy(s.as_ptr(), buf.as_mut_ptr(), s.len());
625                *len = s.len() as u8;
626            }
627            _ => unreachable_unchecked(),
628        }
629        inl
630    }
631
632    #[inline]
633    const fn empty() -> Self {
634        Self::Empty
635    }
636
637    #[inline]
638    fn from_arc_str(s: Arc<str>) -> Self {
639        Self::ArcStr(s)
640    }
641
642    #[inline]
643    fn from_string(s: String) -> Self {
644        Self::new(s)
645    }
646
647    #[inline]
648    fn from_arc_string(s: Arc<String>) -> Self {
649        match Arc::try_unwrap(s) {
650            Ok(s) => Self::from_string(s),
651            Err(s) => Self::ArcString(s),
652        }
653    }
654
655    /// Safety: the caller must guarantee that the bytes `v` are valid UTF-8.
656    #[inline]
657    unsafe fn from_bytes_unchecked(bytes: Bytes) -> Self {
658        if bytes.is_empty() {
659            return Self::Empty;
660        }
661        if bytes.len() <= INLINE_CAP {
662            let mut buf = [0; INLINE_CAP];
663            buf[..bytes.len()].copy_from_slice(bytes.as_ref());
664            return Self::Inline {
665                len: bytes.len() as u8,
666                buf,
667            };
668        }
669        Self::Bytes(bytes)
670    }
671
672    #[inline]
673    fn len(&self) -> usize {
674        match self {
675            Self::Empty => 0,
676            Self::Bytes(bytes) => bytes.len(),
677            Self::ArcStr(arc_str) => arc_str.len(),
678            Self::ArcString(arc_string) => arc_string.len(),
679            Self::StaticStr(s) => s.len(),
680            Self::Inline { len, .. } => *len as usize,
681        }
682    }
683
684    #[inline]
685    fn is_empty(&self) -> bool {
686        match self {
687            Self::Empty => true,
688            Self::Bytes(bytes) => bytes.is_empty(),
689            Self::ArcStr(arc_str) => arc_str.is_empty(),
690            Self::ArcString(arc_string) => arc_string.is_empty(),
691            Self::StaticStr(s) => s.is_empty(),
692            Self::Inline { len, .. } => *len == 0,
693        }
694    }
695
696    #[inline]
697    fn as_str(&self) -> &str {
698        match self {
699            Self::Empty => "",
700            // Safety: this is guaranteed by the user when creating the `FastStr`.
701            Self::Bytes(bytes) => unsafe { std::str::from_utf8_unchecked(bytes) },
702            Self::ArcStr(arc_str) => arc_str,
703            Self::ArcString(arc_string) => arc_string,
704            Self::StaticStr(s) => s,
705            Self::Inline { len, buf } => unsafe { std::str::from_utf8_unchecked(&buf[..*len as usize]) },
706        }
707    }
708
709    #[inline]
710    #[deprecated]
711    fn into_string(self) -> String {
712        match self {
713            Self::Empty => String::new(),
714            Self::Bytes(bytes) => unsafe { String::from_utf8_unchecked(bytes.into()) },
715            Self::ArcStr(arc_str) => arc_str.to_string(),
716            Self::ArcString(arc_string) => {
717                Arc::try_unwrap(arc_string).unwrap_or_else(|arc| (*arc).clone())
718            }
719            Self::StaticStr(s) => s.to_string(),
720            Self::Inline { len, buf } => unsafe {
721                String::from_utf8_unchecked(buf[..len as usize].to_vec())
722            },
723        }
724    }
725
726    #[inline]
727    fn into_bytes(self) -> Bytes {
728        match self {
729            Self::Empty => Bytes::new(),
730            Self::Bytes(bytes) => bytes,
731            Self::ArcStr(arc_str) => Bytes::from(arc_str.as_bytes().to_vec()),
732            Self::ArcString(arc_string) => {
733                Bytes::from(Arc::try_unwrap(arc_string).unwrap_or_else(|arc| (*arc).clone()))
734            }
735            Self::StaticStr(s) => Bytes::from_static(s.as_bytes()),
736            Self::Inline { len, buf } => Bytes::from(buf[..len as usize].to_vec()),
737        }
738    }
739
740    #[inline]
741    fn deep_clone_bytes(&self) -> Self {
742        match self {
743            Self::Empty => Self::Empty,
744            // Safety: this is guaranteed by the user when creating the `FastStr`.
745            Self::Bytes(bytes) => unsafe { Self::new(std::str::from_utf8_unchecked(bytes)) },
746            Self::ArcStr(arc_str) => Self::ArcStr(Arc::clone(arc_str)),
747            Self::ArcString(arc_string) => Self::ArcString(Arc::clone(arc_string)),
748            Self::StaticStr(s) => Self::StaticStr(s),
749            Self::Inline { len, buf } => Self::Inline {
750                len: *len,
751                buf: *buf,
752            },
753        }
754    }
755
756    #[inline]
757    fn slice_ref(&self, subset: &[u8]) -> Self {
758        if subset.is_empty() {
759            return Self::Empty;
760        }
761        let bytes_p = self.as_ref().as_ptr() as usize;
762        let bytes_len = self.len();
763
764        let sub_p = subset.as_ptr() as usize;
765        let sub_len = subset.len();
766
767        assert!(
768            sub_p >= bytes_p,
769            "subset pointer ({:p}) is smaller than self pointer ({:p})",
770            subset.as_ptr(),
771            self.as_ref().as_ptr(),
772        );
773        assert!(
774            sub_p + sub_len <= bytes_p + bytes_len,
775            "subset is out of bounds: self = ({:p}, {}), subset = ({:p}, {})",
776            self.as_ref().as_ptr(),
777            bytes_len,
778            subset.as_ptr(),
779            sub_len,
780        );
781
782        let sub_offset = sub_p - bytes_p;
783        match self {
784            Repr::Empty => panic!("invalid slice ref, self is empty but subset is not"),
785            Repr::Bytes(b) => Self::Bytes(b.slice_ref(subset)),
786            Repr::ArcStr(s) => Self::Bytes(Bytes::copy_from_slice(
787                s[sub_offset..sub_offset + sub_len].as_bytes(),
788            )),
789            Repr::ArcString(s) => Self::Bytes(Bytes::copy_from_slice(
790                s[sub_offset..sub_offset + sub_len].as_bytes(),
791            )),
792            Repr::StaticStr(s) => Self::StaticStr(unsafe {
793                std::str::from_utf8_unchecked(&s.as_bytes()[sub_offset..sub_offset + sub_len])
794            }),
795            Repr::Inline { len: _, buf } => Self::Inline {
796                len: sub_len as u8,
797                buf: {
798                    let mut new_buf = [0; INLINE_CAP];
799                    new_buf[..sub_len].copy_from_slice(&buf[sub_offset..sub_offset + sub_len]);
800                    new_buf
801                },
802            },
803        }
804    }
805}
806
807impl AsRef<[u8]> for Repr {
808    #[inline]
809    fn as_ref(&self) -> &[u8] {
810        match self {
811            Self::Empty => &[],
812            Self::Bytes(bytes) => bytes.as_ref(),
813            Self::ArcStr(arc_str) => arc_str.as_bytes(),
814            Self::ArcString(arc_string) => arc_string.as_bytes(),
815            Self::StaticStr(s) => s.as_bytes(),
816            Self::Inline { len, buf } => &buf[..*len as usize],
817        }
818    }
819}
820#[cfg(feature = "redis")]
821mod redis;
822
823#[cfg(feature = "serde")]
824mod serde;
825
826#[cfg(feature = "sqlx")]
827mod sqlx;