faststr/
lib.rs

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