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 #[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 #[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}