arc_slice/
inlined.rs

1use alloc::{borrow::Cow, boxed::Box, vec::Vec};
2use core::{
3    borrow::Borrow,
4    cmp,
5    convert::Infallible,
6    fmt,
7    hash::{Hash, Hasher},
8    mem,
9    mem::{size_of, ManuallyDrop, MaybeUninit},
10    ops::{Deref, RangeBounds},
11    ptr::addr_of,
12    slice,
13    str::FromStr,
14};
15
16use either::Either;
17
18use crate::{
19    buffer::{Buffer, StringBuffer},
20    layout::{Compact, Layout, Plain},
21    msrv::ptr,
22    str::{check_char_boundary, FromUtf8Error, StringBufWrapper},
23    utils::{debug_slice, offset_len, panic_out_of_range},
24    ArcBytes, ArcStr,
25};
26
27const INLINED_FLAG: u8 = 0x80;
28
29pub trait InlinedLayout {
30    const LEN: usize;
31    type Data: Copy;
32    const DEFAULT: Self::Data;
33}
34
35const COMPACT_LEN: usize = 3 * size_of::<usize>() - 2;
36const PLAIN_LEN: usize = 4 * size_of::<usize>() - 2;
37
38impl InlinedLayout for Compact {
39    const LEN: usize = COMPACT_LEN;
40    type Data = [MaybeUninit<u8>; COMPACT_LEN];
41    const DEFAULT: Self::Data = [MaybeUninit::uninit(); COMPACT_LEN];
42}
43
44impl InlinedLayout for Plain {
45    const LEN: usize = PLAIN_LEN;
46    type Data = [MaybeUninit<u8>; PLAIN_LEN];
47    const DEFAULT: Self::Data = [MaybeUninit::uninit(); PLAIN_LEN];
48}
49
50#[repr(C)]
51pub struct SmallBytes<L: Layout> {
52    #[cfg(target_endian = "big")]
53    tagged_length: u8,
54    data: <L as InlinedLayout>::Data,
55    offset: u8,
56    #[cfg(target_endian = "little")]
57    tagged_length: u8,
58}
59
60impl<L: Layout> SmallBytes<L> {
61    const MAX_LEN: usize = L::LEN;
62
63    #[inline]
64    pub fn new(slice: &[u8]) -> Option<Self> {
65        if slice.len() > Self::MAX_LEN {
66            return None;
67        }
68        let mut this = Self {
69            data: L::DEFAULT,
70            offset: 0,
71            tagged_length: slice.len() as u8 | INLINED_FLAG,
72        };
73        let data = ptr::from_mut(&mut this.data).cast::<u8>();
74        unsafe { ptr::copy_nonoverlapping(slice.as_ptr(), data, slice.len()) }
75        Some(this)
76    }
77
78    #[inline(always)]
79    const fn is_inlined(this: *const Self) -> bool {
80        unsafe { (*addr_of!((*this).tagged_length)) & INLINED_FLAG != 0 }
81    }
82
83    #[inline]
84    pub const fn len(&self) -> usize {
85        (self.tagged_length & !INLINED_FLAG) as usize
86    }
87
88    #[inline]
89    pub const fn is_empty(&self) -> bool {
90        self.len() == 0
91    }
92
93    #[inline]
94    pub const fn as_slice(&self) -> &[u8] {
95        let data = ptr::from_ref(&self.data).cast::<u8>();
96        unsafe { slice::from_raw_parts(data.add(self.offset as usize), self.len()) }
97    }
98
99    #[inline]
100    pub fn truncate(&mut self, len: usize) {
101        if len < self.len() {
102            self.tagged_length = len as u8 | INLINED_FLAG;
103        }
104    }
105
106    #[inline]
107    pub fn advance(&mut self, offset: usize) {
108        if offset > self.len() {
109            panic_out_of_range()
110        }
111        self.offset += offset as u8;
112        self.tagged_length -= offset as u8;
113    }
114
115    #[inline]
116    pub fn subslice(&self, range: impl RangeBounds<usize>) -> Self {
117        let (offset, len) = offset_len(self.len(), range);
118        Self {
119            offset: self.offset + offset as u8,
120            tagged_length: len as u8 | INLINED_FLAG,
121            ..*self
122        }
123    }
124}
125
126impl<L: Layout> Clone for SmallBytes<L> {
127    #[inline]
128    fn clone(&self) -> Self {
129        *self
130    }
131}
132
133impl<L: Layout> Copy for SmallBytes<L> {}
134
135impl<L: Layout> Deref for SmallBytes<L> {
136    type Target = [u8];
137
138    #[inline]
139    fn deref(&self) -> &Self::Target {
140        self.as_slice()
141    }
142}
143
144impl<L: Layout> AsRef<[u8]> for SmallBytes<L> {
145    #[inline]
146    fn as_ref(&self) -> &[u8] {
147        self
148    }
149}
150
151impl<L: Layout> Hash for SmallBytes<L> {
152    #[inline]
153    fn hash<H>(&self, state: &mut H)
154    where
155        H: Hasher,
156    {
157        self.as_slice().hash(state);
158    }
159}
160
161impl<L: Layout> Borrow<[u8]> for SmallBytes<L> {
162    #[inline]
163    fn borrow(&self) -> &[u8] {
164        self
165    }
166}
167
168impl<L: Layout> Default for SmallBytes<L> {
169    #[inline]
170    fn default() -> Self {
171        Self::new(&[]).unwrap()
172    }
173}
174
175impl<L: Layout> fmt::Debug for SmallBytes<L> {
176    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177        debug_slice(self, f)
178    }
179}
180
181impl<L: Layout> fmt::LowerHex for SmallBytes<L> {
182    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183        for &b in self.as_slice() {
184            write!(f, "{:02x}", b)?;
185        }
186        Ok(())
187    }
188}
189
190impl<L: Layout> fmt::UpperHex for SmallBytes<L> {
191    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
192        for &b in self.as_slice() {
193            write!(f, "{:02X}", b)?;
194        }
195        Ok(())
196    }
197}
198
199impl<L: Layout> PartialEq for SmallBytes<L> {
200    fn eq(&self, other: &SmallBytes<L>) -> bool {
201        self.as_slice() == other.as_slice()
202    }
203}
204
205impl<L: Layout> Eq for SmallBytes<L> {}
206
207impl<L: Layout> PartialOrd for SmallBytes<L> {
208    fn partial_cmp(&self, other: &SmallBytes<L>) -> Option<cmp::Ordering> {
209        Some(self.cmp(other))
210    }
211}
212
213impl<L: Layout> Ord for SmallBytes<L> {
214    fn cmp(&self, other: &SmallBytes<L>) -> cmp::Ordering {
215        self.as_slice().cmp(other.as_slice())
216    }
217}
218
219pub struct SmallArcBytes<L: Layout = Compact>(Inner<L>);
220
221#[repr(C)]
222union Inner<L: Layout> {
223    small: SmallBytes<L>,
224    arc: ManuallyDrop<ArcBytes<L>>,
225}
226
227impl<L: Layout> SmallArcBytes<L> {
228    #[inline]
229    pub fn new<B: Buffer<u8>>(buffer: B) -> Self {
230        if buffer.is_array() {
231            if let Some(small) = SmallBytes::new(buffer.as_slice()) {
232                return Self(Inner { small });
233            }
234        }
235        Self(Inner {
236            arc: ManuallyDrop::new(ArcBytes::new(buffer)),
237        })
238    }
239
240    #[inline]
241    pub fn from_slice(slice: &[u8]) -> Self {
242        if let Some(small) = SmallBytes::new(slice) {
243            return Self(Inner { small });
244        }
245        Self(Inner {
246            arc: ManuallyDrop::new(ArcBytes::new(slice.to_vec())),
247        })
248    }
249
250    #[inline(always)]
251    pub const fn as_either(&self) -> Either<&SmallBytes<L>, &ArcBytes<L>> {
252        if unsafe { SmallBytes::is_inlined(addr_of!(self.0.small)) } {
253            Either::Left(unsafe { &self.0.small })
254        } else {
255            Either::Right(unsafe { &*ptr::from_ref(&self.0.arc).cast() })
256        }
257    }
258
259    #[inline(always)]
260    pub fn as_either_mut(&mut self) -> Either<&mut SmallBytes<L>, &mut ArcBytes<L>> {
261        if unsafe { SmallBytes::is_inlined(addr_of!(self.0.small)) } {
262            Either::Left(unsafe { &mut self.0.small })
263        } else {
264            Either::Right(unsafe { &mut self.0.arc })
265        }
266    }
267
268    #[inline(always)]
269    pub fn into_either(self) -> Either<SmallBytes<L>, ArcBytes<L>> {
270        let mut this = ManuallyDrop::new(self);
271        if unsafe { SmallBytes::is_inlined(addr_of!(this.0.small)) } {
272            Either::Left(unsafe { this.0.small })
273        } else {
274            Either::Right(unsafe { ManuallyDrop::take(&mut this.0.arc) })
275        }
276    }
277
278    #[inline]
279    pub const fn len(&self) -> usize {
280        match self.as_either() {
281            Either::Left(bytes) => bytes.len(),
282            Either::Right(bytes) => bytes.len(),
283        }
284    }
285
286    #[inline]
287    pub const fn is_empty(&self) -> bool {
288        self.len() == 0
289    }
290
291    #[inline]
292    pub const fn as_slice(&self) -> &[u8] {
293        match self.as_either() {
294            Either::Left(bytes) => bytes.as_slice(),
295            Either::Right(bytes) => bytes.as_slice(),
296        }
297    }
298
299    #[inline]
300    pub fn subslice(&self, range: impl RangeBounds<usize>) -> Self {
301        match self.as_either() {
302            Either::Left(bytes) => Self(Inner {
303                small: bytes.subslice(range),
304            }),
305            Either::Right(bytes) => Self(Inner {
306                arc: ManuallyDrop::new(bytes.subslice(range)),
307            }),
308        }
309    }
310}
311
312impl<L: Layout> Drop for SmallArcBytes<L> {
313    #[inline]
314    fn drop(&mut self) {
315        if let Either::Right(bytes) = self.as_either_mut() {
316            unsafe { ptr::drop_in_place(bytes) }
317        }
318    }
319}
320
321impl<L: Layout> Clone for SmallArcBytes<L> {
322    #[inline]
323    fn clone(&self) -> Self {
324        match self.as_either() {
325            Either::Left(bytes) => Self(Inner { small: *bytes }),
326            Either::Right(bytes) => Self(Inner {
327                arc: ManuallyDrop::new(bytes.clone()),
328            }),
329        }
330    }
331}
332
333impl<L: Layout> Deref for SmallArcBytes<L> {
334    type Target = [u8];
335
336    #[inline]
337    fn deref(&self) -> &Self::Target {
338        self.as_slice()
339    }
340}
341
342impl<L: Layout> AsRef<[u8]> for SmallArcBytes<L> {
343    #[inline]
344    fn as_ref(&self) -> &[u8] {
345        self
346    }
347}
348
349impl<L: Layout> Hash for SmallArcBytes<L> {
350    #[inline]
351    fn hash<H>(&self, state: &mut H)
352    where
353        H: Hasher,
354    {
355        self.as_slice().hash(state);
356    }
357}
358
359impl<L: Layout> Borrow<[u8]> for SmallArcBytes<L> {
360    #[inline]
361    fn borrow(&self) -> &[u8] {
362        self
363    }
364}
365
366#[cfg(not(all(loom, test)))]
367impl<L: Layout> Default for SmallArcBytes<L> {
368    #[inline]
369    fn default() -> Self {
370        ArcBytes::new_static(&[]).into()
371    }
372}
373
374impl<L: Layout> fmt::Debug for SmallArcBytes<L> {
375    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
376        debug_slice(self, f)
377    }
378}
379
380impl<L: Layout> fmt::LowerHex for SmallArcBytes<L> {
381    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
382        for &b in self.as_slice() {
383            write!(f, "{:02x}", b)?;
384        }
385        Ok(())
386    }
387}
388
389impl<L: Layout> fmt::UpperHex for SmallArcBytes<L> {
390    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
391        for &b in self.as_slice() {
392            write!(f, "{:02X}", b)?;
393        }
394        Ok(())
395    }
396}
397
398impl<L: Layout> PartialEq for SmallArcBytes<L> {
399    fn eq(&self, other: &SmallArcBytes<L>) -> bool {
400        self.as_slice() == other.as_slice()
401    }
402}
403
404impl<L: Layout> Eq for SmallArcBytes<L> {}
405
406impl<L: Layout> PartialOrd for SmallArcBytes<L> {
407    fn partial_cmp(&self, other: &SmallArcBytes<L>) -> Option<cmp::Ordering> {
408        Some(self.cmp(other))
409    }
410}
411
412impl<L: Layout> Ord for SmallArcBytes<L> {
413    fn cmp(&self, other: &SmallArcBytes<L>) -> cmp::Ordering {
414        self.as_slice().cmp(other.as_slice())
415    }
416}
417
418macro_rules! std_impl {
419    ($($(@$N:ident)? $ty:ty $(: $bound:path)?),*) => {$(
420        impl<L: Layout, $(const $N: usize,)?> From<$ty> for SmallArcBytes<L> {
421
422    #[inline]
423            fn from(value: $ty) -> Self {
424                Self::new(value)
425            }
426        }
427    )*};
428}
429std_impl!(&'static [u8], @N &'static [u8; N], @N [u8; N], Box<[u8]>, Vec<u8>, Cow<'static, [u8]>: Clone);
430
431impl<L: Layout> From<Either<SmallBytes<L>, ArcBytes<L>>> for SmallArcBytes<L> {
432    #[inline]
433    fn from(value: Either<SmallBytes<L>, ArcBytes<L>>) -> Self {
434        match value {
435            Either::Left(bytes) => Self(Inner { small: bytes }),
436            Either::Right(bytes) => Self(Inner {
437                arc: ManuallyDrop::new(bytes),
438            }),
439        }
440    }
441}
442
443impl<L: Layout> From<SmallBytes<L>> for SmallArcBytes<L> {
444    #[inline]
445    fn from(value: SmallBytes<L>) -> Self {
446        Either::<_, ArcBytes<L>>::Left(value).into()
447    }
448}
449
450impl<L: Layout> From<ArcBytes<L>> for SmallArcBytes<L> {
451    #[inline]
452    fn from(value: ArcBytes<L>) -> Self {
453        Either::<SmallBytes<L>, _>::Right(value).into()
454    }
455}
456
457#[repr(transparent)]
458pub struct SmallStr<L: Layout = Compact>(SmallBytes<L>);
459
460impl<L: Layout> SmallStr<L> {
461    #[inline]
462    pub fn new(s: &str) -> Option<Self> {
463        SmallBytes::new(s.as_bytes()).map(Self)
464    }
465
466    /// # Safety
467    ///
468    /// Bytes must be valid UTF-8.
469    #[inline]
470    pub const unsafe fn from_utf8_unchecked(bytes: SmallBytes<L>) -> Self {
471        Self(bytes)
472    }
473
474    #[inline]
475    pub const fn len(&self) -> usize {
476        self.0.len()
477    }
478
479    #[inline]
480    pub const fn is_empty(&self) -> bool {
481        self.len() == 0
482    }
483
484    #[inline]
485    pub const fn as_str(&self) -> &str {
486        unsafe { core::str::from_utf8_unchecked(self.0.as_slice()) }
487    }
488
489    #[inline]
490    pub fn truncate(&mut self, len: usize) {
491        check_char_boundary(self, len);
492        self.0.truncate(len);
493    }
494
495    #[inline]
496    pub fn advance(&mut self, offset: usize) {
497        check_char_boundary(self, offset);
498        self.0.advance(offset);
499    }
500
501    #[inline]
502    pub fn subslice(&self, range: impl RangeBounds<usize>) -> Self {
503        let (offset, len) = offset_len(self.len(), range);
504        check_char_boundary(self, offset);
505        check_char_boundary(self, offset + len);
506        Self(self.0.subslice(offset..offset + len))
507    }
508
509    #[inline]
510    pub fn as_slice(&self) -> &SmallBytes<L> {
511        &self.0
512    }
513
514    #[inline]
515    pub fn into_slice(self) -> SmallBytes<L> {
516        self.0
517    }
518}
519
520impl<L: Layout> Clone for SmallStr<L> {
521    #[inline]
522    fn clone(&self) -> Self {
523        *self
524    }
525}
526
527impl<L: Layout> Copy for SmallStr<L> {}
528
529impl<L: Layout> Deref for SmallStr<L> {
530    type Target = str;
531
532    #[inline]
533    fn deref(&self) -> &Self::Target {
534        self.as_str()
535    }
536}
537
538impl<L: Layout> AsRef<str> for SmallStr<L> {
539    #[inline]
540    fn as_ref(&self) -> &str {
541        self
542    }
543}
544
545impl<L: Layout> AsRef<[u8]> for SmallStr<L> {
546    #[inline]
547    fn as_ref(&self) -> &[u8] {
548        self.as_bytes()
549    }
550}
551
552impl<L: Layout> Hash for SmallStr<L> {
553    #[inline]
554    fn hash<H>(&self, state: &mut H)
555    where
556        H: Hasher,
557    {
558        self.as_bytes().hash(state);
559    }
560}
561
562impl<L: Layout> Borrow<str> for SmallStr<L> {
563    #[inline]
564    fn borrow(&self) -> &str {
565        self
566    }
567}
568
569impl<L: Layout> Default for SmallStr<L> {
570    #[inline]
571    fn default() -> Self {
572        Self::new("").unwrap()
573    }
574}
575
576impl<L: Layout> fmt::Debug for SmallStr<L> {
577    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
578        (**self).fmt(f)
579    }
580}
581
582impl<L: Layout> fmt::Display for SmallStr<L> {
583    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
584        (**self).fmt(f)
585    }
586}
587
588impl<L: Layout> PartialEq for SmallStr<L> {
589    fn eq(&self, other: &SmallStr<L>) -> bool {
590        self.as_str() == other.as_str()
591    }
592}
593
594impl<L: Layout> Eq for SmallStr<L> {}
595
596impl<L: Layout> PartialOrd for SmallStr<L> {
597    fn partial_cmp(&self, other: &SmallStr<L>) -> Option<cmp::Ordering> {
598        Some(self.cmp(other))
599    }
600}
601
602impl<L: Layout> Ord for SmallStr<L> {
603    fn cmp(&self, other: &SmallStr<L>) -> cmp::Ordering {
604        self.as_str().cmp(other.as_str())
605    }
606}
607
608pub struct SmallArcStr<L: Layout = Compact>(SmallArcBytes<L>);
609
610impl<L: Layout> SmallArcStr<L> {
611    #[inline]
612    pub fn new<B: StringBuffer>(buffer: B) -> Self {
613        unsafe { Self::from_utf8_unchecked(SmallArcBytes::new(StringBufWrapper(buffer))) }
614    }
615
616    #[inline]
617    pub fn from_utf8(bytes: SmallArcBytes<L>) -> Result<Self, FromUtf8Error<SmallArcBytes<L>>> {
618        match core::str::from_utf8(bytes.as_slice()) {
619            Ok(_) => Ok(Self(bytes)),
620            Err(error) => Err(FromUtf8Error { bytes, error }),
621        }
622    }
623
624    /// # Safety
625    ///
626    /// Bytes must be valid UTF-8.
627    #[inline]
628    pub const unsafe fn from_utf8_unchecked(bytes: SmallArcBytes<L>) -> Self {
629        Self(bytes)
630    }
631
632    #[inline(always)]
633    pub fn as_either(&self) -> Either<&SmallStr<L>, &ArcStr<L>> {
634        match self.0.as_either() {
635            Either::Left(bytes) => unsafe {
636                Either::Left(mem::transmute::<&SmallBytes<L>, &SmallStr<L>>(bytes))
637            },
638            Either::Right(bytes) => unsafe {
639                Either::Right(mem::transmute::<&ArcBytes<L>, &ArcStr<L>>(bytes))
640            },
641        }
642    }
643
644    #[inline(always)]
645    pub fn as_either_mut(&mut self) -> Either<&mut SmallStr<L>, &mut ArcStr<L>> {
646        match self.0.as_either_mut() {
647            Either::Left(bytes) => unsafe {
648                Either::Left(mem::transmute::<&mut SmallBytes<L>, &mut SmallStr<L>>(
649                    bytes,
650                ))
651            },
652            Either::Right(bytes) => unsafe {
653                Either::Right(mem::transmute::<&mut ArcBytes<L>, &mut ArcStr<L>>(bytes))
654            },
655        }
656    }
657
658    #[inline(always)]
659    pub fn into_either(self) -> Either<SmallStr<L>, ArcStr<L>> {
660        match self.0.into_either() {
661            Either::Left(bytes) => unsafe { Either::Left(SmallStr::from_utf8_unchecked(bytes)) },
662            Either::Right(bytes) => unsafe { Either::Right(ArcStr::from_utf8_unchecked(bytes)) },
663        }
664    }
665
666    #[inline]
667    pub const fn len(&self) -> usize {
668        self.0.len()
669    }
670
671    #[inline]
672    pub const fn is_empty(&self) -> bool {
673        self.len() == 0
674    }
675
676    #[inline]
677    pub const fn as_str(&self) -> &str {
678        unsafe { core::str::from_utf8_unchecked(self.0.as_slice()) }
679    }
680
681    #[inline]
682    pub fn subslice(&self, range: impl RangeBounds<usize>) -> Self {
683        Self(self.0.subslice(range))
684    }
685}
686
687impl<L: Layout> Clone for SmallArcStr<L> {
688    #[inline]
689    fn clone(&self) -> Self {
690        Self(self.0.clone())
691    }
692}
693
694impl<L: Layout> Deref for SmallArcStr<L> {
695    type Target = str;
696
697    #[inline]
698    fn deref(&self) -> &Self::Target {
699        self.as_str()
700    }
701}
702
703impl<L: Layout> AsRef<str> for SmallArcStr<L> {
704    #[inline]
705    fn as_ref(&self) -> &str {
706        self
707    }
708}
709
710impl<L: Layout> AsRef<[u8]> for SmallArcStr<L> {
711    #[inline]
712    fn as_ref(&self) -> &[u8] {
713        self.as_bytes()
714    }
715}
716
717impl<L: Layout> Hash for SmallArcStr<L> {
718    #[inline]
719    fn hash<H>(&self, state: &mut H)
720    where
721        H: Hasher,
722    {
723        self.as_str().hash(state);
724    }
725}
726
727impl<L: Layout> Borrow<str> for SmallArcStr<L> {
728    #[inline]
729    fn borrow(&self) -> &str {
730        self
731    }
732}
733
734#[cfg(not(all(loom, test)))]
735impl<L: Layout> Default for SmallArcStr<L> {
736    #[inline]
737    fn default() -> Self {
738        ArcStr::new_static("").into()
739    }
740}
741
742impl<L: Layout> fmt::Debug for SmallArcStr<L> {
743    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
744        (**self).fmt(f)
745    }
746}
747
748impl<L: Layout> fmt::Display for SmallArcStr<L> {
749    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
750        (**self).fmt(f)
751    }
752}
753
754impl<L: Layout> PartialEq for SmallArcStr<L> {
755    fn eq(&self, other: &SmallArcStr<L>) -> bool {
756        self.as_str() == other.as_str()
757    }
758}
759
760impl<L: Layout> Eq for SmallArcStr<L> {}
761
762impl<L: Layout> PartialOrd for SmallArcStr<L> {
763    fn partial_cmp(&self, other: &SmallArcStr<L>) -> Option<cmp::Ordering> {
764        Some(self.cmp(other))
765    }
766}
767
768impl<L: Layout> Ord for SmallArcStr<L> {
769    fn cmp(&self, other: &SmallArcStr<L>) -> cmp::Ordering {
770        self.as_str().cmp(other.as_str())
771    }
772}
773
774macro_rules! std_impl {
775    ($($ty:ty),*) => {$(
776        impl<L: Layout> From<$ty> for SmallArcStr<L> {
777
778            #[inline]
779            fn from(value: $ty) -> Self {
780                Self::new(value)
781            }
782        }
783    )*};
784}
785std_impl!(
786    &'static str,
787    Box<str>,
788    alloc::string::String,
789    Cow<'static, str>
790);
791
792impl<L: Layout> FromStr for SmallArcStr<L> {
793    type Err = Infallible;
794
795    #[inline]
796    fn from_str(s: &str) -> Result<Self, Self::Err> {
797        Ok(Self(SmallArcBytes::from_slice(s.as_bytes())))
798    }
799}
800
801impl<L: Layout> From<Either<SmallStr<L>, ArcStr<L>>> for SmallArcStr<L> {
802    #[inline]
803    fn from(value: Either<SmallStr<L>, ArcStr<L>>) -> Self {
804        Self(match value {
805            Either::Left(bytes) => bytes.into_slice().into(),
806            Either::Right(bytes) => bytes.into_slice().into(),
807        })
808    }
809}
810
811impl<L: Layout> From<SmallStr<L>> for SmallArcStr<L> {
812    #[inline]
813    fn from(value: SmallStr<L>) -> Self {
814        Either::<_, ArcStr<L>>::Left(value).into()
815    }
816}
817
818impl<L: Layout> From<ArcStr<L>> for SmallArcStr<L> {
819    #[inline]
820    fn from(value: ArcStr<L>) -> Self {
821        Either::<SmallStr<L>, _>::Right(value).into()
822    }
823}