arc_slice/
inlined.rs

1//! [Small String Optimization] support for [`ArcSlice`].
2//!
3//! [Small String Optimization]: https://cppdepend.com/blog/understanding-small-string-optimization-sso-in-stdstring/
4
5use alloc::{string::String, vec::Vec};
6use core::{
7    borrow::Borrow,
8    cmp, fmt,
9    hash::{Hash, Hasher},
10    marker::PhantomData,
11    mem::{size_of, ManuallyDrop, MaybeUninit},
12    ops::{Deref, RangeBounds},
13    ptr::addr_of,
14    slice,
15};
16
17use either::Either;
18pub(crate) use private::InlinedLayout;
19
20#[cfg(feature = "oom-handling")]
21use crate::layout::AnyBufferLayout;
22#[cfg(not(feature = "oom-handling"))]
23use crate::layout::CloneNoAllocLayout;
24use crate::{
25    buffer::{Emptyable, Slice, SliceExt, Subsliceable},
26    error::AllocError,
27    layout::{ArcLayout, BoxedSliceLayout, DefaultLayout, Layout, StaticLayout, VecLayout},
28    msrv::ptr,
29    utils::{debug_slice, lower_hex, panic_out_of_range, range_offset_len, upper_hex},
30    ArcSlice,
31};
32
33const INLINED_FLAG: u8 = 0x80;
34
35mod private {
36    #[allow(clippy::missing_safety_doc)]
37    pub unsafe trait InlinedLayout {
38        const LEN: usize;
39        type Data: Copy;
40        const UNINIT: Self::Data;
41    }
42}
43
44const _3_WORDS_LEN: usize = 3 * size_of::<usize>() - 2;
45const _4_WORDS_LEN: usize = 4 * size_of::<usize>() - 2;
46
47unsafe impl<const ANY_BUFFER: bool, const STATIC: bool> InlinedLayout
48    for ArcLayout<ANY_BUFFER, STATIC>
49{
50    const LEN: usize = _3_WORDS_LEN;
51    type Data = [MaybeUninit<u8>; _3_WORDS_LEN];
52    const UNINIT: Self::Data = [MaybeUninit::uninit(); _3_WORDS_LEN];
53}
54
55unsafe impl InlinedLayout for BoxedSliceLayout {
56    const LEN: usize = _3_WORDS_LEN;
57    type Data = [MaybeUninit<u8>; _3_WORDS_LEN];
58    const UNINIT: Self::Data = [MaybeUninit::uninit(); _3_WORDS_LEN];
59}
60
61unsafe impl InlinedLayout for VecLayout {
62    const LEN: usize = _4_WORDS_LEN;
63    type Data = [MaybeUninit<u8>; _4_WORDS_LEN];
64    const UNINIT: Self::Data = [MaybeUninit::uninit(); _4_WORDS_LEN];
65}
66
67#[cfg(feature = "raw-buffer")]
68unsafe impl InlinedLayout for crate::layout::RawLayout {
69    const LEN: usize = _4_WORDS_LEN;
70    type Data = [MaybeUninit<u8>; _4_WORDS_LEN];
71    const UNINIT: Self::Data = [MaybeUninit::uninit(); _4_WORDS_LEN];
72}
73
74/// An inlined storage that can contains a slice up to `size_of::<ArcBytes<L>>() - 2` bytes.
75///
76/// # Examples
77///
78/// ```rust
79/// use arc_slice::inlined::SmallSlice;
80///
81/// let s = SmallSlice::<str>::new("hello world").unwrap();
82/// assert_eq!(s, "hello world");
83#[repr(C)]
84pub struct SmallSlice<S: Slice<Item = u8> + ?Sized, L: Layout = DefaultLayout> {
85    #[cfg(target_endian = "big")]
86    tagged_length: u8,
87    data: <L as InlinedLayout>::Data,
88    offset: u8,
89    #[cfg(target_endian = "little")]
90    tagged_length: u8,
91    _phantom: PhantomData<S>,
92}
93
94impl<S: Slice<Item = u8> + ?Sized, L: Layout> SmallSlice<S, L> {
95    const MAX_LEN: usize = L::LEN;
96
97    /// An empty SmallSlice.
98    pub const EMPTY: Self = Self {
99        data: L::UNINIT,
100        offset: 0,
101        tagged_length: INLINED_FLAG,
102        _phantom: PhantomData,
103    };
104
105    /// Create a new `SmallSlice` if the slice fits in.
106    ///
107    /// # Examples
108    ///
109    /// ```rust
110    /// use arc_slice::inlined::SmallSlice;
111    ///
112    /// assert!(SmallSlice::<[u8]>::new(&[0, 1, 2]).is_some());
113    /// assert!(SmallSlice::<[u8]>::new(&[0; 256]).is_none());
114    /// ```
115    pub fn new(slice: &S) -> Option<Self> {
116        if slice.len() > Self::MAX_LEN {
117            return None;
118        }
119        let mut this = Self {
120            data: L::UNINIT,
121            offset: 0,
122            tagged_length: slice.len() as u8 | INLINED_FLAG,
123            _phantom: PhantomData,
124        };
125        let data = ptr::from_mut(&mut this.data).cast::<u8>();
126        unsafe { ptr::copy_nonoverlapping(slice.as_ptr().as_ptr(), data, slice.len()) }
127        Some(this)
128    }
129
130    #[inline(always)]
131    const fn is_inlined(this: *const Self) -> bool {
132        unsafe { (*addr_of!((*this).tagged_length)) & INLINED_FLAG != 0 }
133    }
134
135    /// Returns the number of items in the slice.
136    ///
137    /// # Examples
138    ///
139    /// ```rust
140    /// use arc_slice::inlined::SmallSlice;
141    ///
142    /// let s = SmallSlice::<[u8]>::new(&[0, 1, 2]).unwrap();
143    /// assert_eq!(s.len(), 3);
144    /// ```
145    pub const fn len(&self) -> usize {
146        (self.tagged_length & !INLINED_FLAG) as usize
147    }
148
149    /// Returns `true` if the slice contains no items.
150    ///
151    /// # Examples
152    ///
153    /// ```rust
154    /// use arc_slice::inlined::SmallSlice;
155    ///
156    /// let s = SmallSlice::<[u8]>::new(&[0, 1, 2]).unwrap();
157    /// assert!(!s.is_empty());
158    ///
159    /// let s = SmallSlice::<[u8]>::new(&[]).unwrap();
160    /// assert!(s.is_empty());
161    /// ```
162    pub const fn is_empty(&self) -> bool {
163        self.len() == 0
164    }
165
166    /// Returns a raw pointer to the slice's first item.
167    ///
168    /// See [`slice::as_ptr`].
169    pub const fn as_ptr(&self) -> *const u8 {
170        let data = ptr::from_ref(&self.data).cast::<u8>();
171        unsafe { data.add(self.offset as usize) }
172    }
173
174    /// Advances the start of the slice by `offset` items.
175    ///
176    /// # Panics
177    ///
178    /// Panics if `offset > self.len()`.
179    ///
180    /// # Examples
181    ///
182    /// ```rust
183    /// use arc_slice::inlined::SmallSlice;
184    ///
185    /// let mut s = SmallSlice::<[u8]>::new(b"hello world").unwrap();
186    /// s.advance(6);
187    /// assert_eq!(s, b"world");
188    /// ```
189    pub fn advance(&mut self, offset: usize)
190    where
191        S: Subsliceable,
192    {
193        if offset > self.len() {
194            panic_out_of_range()
195        }
196        unsafe { self.check_advance(offset) };
197        self.offset += offset as u8;
198        self.tagged_length -= offset as u8;
199    }
200
201    /// Truncate the slice to the first `len` items.
202    ///
203    /// If `len` is greater than the slice length, this has no effect.
204    ///
205    /// ```rust
206    /// use arc_slice::inlined::SmallSlice;
207    ///
208    /// let mut s = SmallSlice::<[u8]>::new(b"hello world").unwrap();
209    /// s.truncate(5);
210    /// assert_eq!(s, b"hello");
211    /// ```
212    pub fn truncate(&mut self, len: usize)
213    where
214        S: Subsliceable,
215    {
216        if len < self.len() {
217            unsafe { self.check_truncate(len) };
218            self.tagged_length = len as u8 | INLINED_FLAG;
219        }
220    }
221
222    /// Extracts a subslice of a `SmallSlice` with a given range.
223    ///
224    /// # Examples
225    ///
226    /// ```rust
227    /// use arc_slice::inlined::SmallSlice;
228    ///
229    /// let s = SmallSlice::<[u8]>::new(b"hello world").unwrap();
230    /// let s2 = s.subslice(..5);
231    /// assert_eq!(s2, b"hello");
232    /// ```
233    pub fn subslice(&self, range: impl RangeBounds<usize>) -> Self
234    where
235        S: Subsliceable,
236    {
237        let (offset, len) = range_offset_len(self.deref(), range);
238        Self {
239            offset: self.offset + offset as u8,
240            tagged_length: len as u8 | INLINED_FLAG,
241            ..*self
242        }
243    }
244}
245
246impl<S: Slice<Item = u8> + ?Sized, L: Layout> Clone for SmallSlice<S, L> {
247    fn clone(&self) -> Self {
248        *self
249    }
250}
251
252impl<S: Slice<Item = u8> + ?Sized, L: Layout> Copy for SmallSlice<S, L> {}
253
254impl<S: Slice<Item = u8> + ?Sized, L: Layout> Deref for SmallSlice<S, L> {
255    type Target = S;
256
257    fn deref(&self) -> &Self::Target {
258        unsafe { S::from_slice_unchecked(slice::from_raw_parts(self.as_ptr(), self.len())) }
259    }
260}
261
262impl<S: Slice<Item = u8> + ?Sized, L: Layout> AsRef<S> for SmallSlice<S, L> {
263    fn as_ref(&self) -> &S {
264        self
265    }
266}
267
268impl<S: Hash + Slice<Item = u8> + ?Sized, L: Layout> Hash for SmallSlice<S, L> {
269    fn hash<H>(&self, state: &mut H)
270    where
271        H: Hasher,
272    {
273        self.deref().hash(state);
274    }
275}
276
277impl<S: Slice<Item = u8> + ?Sized, L: Layout> Borrow<S> for SmallSlice<S, L> {
278    fn borrow(&self) -> &S {
279        self
280    }
281}
282
283impl<S: Emptyable<Item = u8> + ?Sized, L: Layout> Default for SmallSlice<S, L> {
284    fn default() -> Self {
285        Self::EMPTY
286    }
287}
288
289impl<S: fmt::Debug + Slice<Item = u8> + ?Sized, L: Layout> fmt::Debug for SmallSlice<S, L> {
290    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
291        debug_slice(self.deref(), f)
292    }
293}
294
295impl<S: fmt::Display + Slice<Item = u8> + ?Sized, L: Layout> fmt::Display for SmallSlice<S, L> {
296    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
297        self.deref().fmt(f)
298    }
299}
300
301impl<S: Slice<Item = u8> + ?Sized, L: Layout> fmt::LowerHex for SmallSlice<S, L> {
302    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
303        lower_hex(self.to_slice(), f)
304    }
305}
306
307impl<S: Slice<Item = u8> + ?Sized, L: Layout> fmt::UpperHex for SmallSlice<S, L> {
308    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
309        upper_hex(self.to_slice(), f)
310    }
311}
312
313impl<S: PartialEq + Slice<Item = u8> + ?Sized, L: Layout> PartialEq for SmallSlice<S, L> {
314    fn eq(&self, other: &SmallSlice<S, L>) -> bool {
315        **self == **other
316    }
317}
318
319impl<S: PartialEq + Slice<Item = u8> + ?Sized, L: Layout> Eq for SmallSlice<S, L> {}
320
321impl<S: PartialOrd + Slice<Item = u8> + ?Sized, L: Layout> PartialOrd for SmallSlice<S, L> {
322    fn partial_cmp(&self, other: &SmallSlice<S, L>) -> Option<cmp::Ordering> {
323        self.deref().partial_cmp(other.deref())
324    }
325}
326
327impl<S: Ord + Slice<Item = u8> + ?Sized, L: Layout> Ord for SmallSlice<S, L> {
328    fn cmp(&self, other: &SmallSlice<S, L>) -> cmp::Ordering {
329        self.deref().cmp(other.deref())
330    }
331}
332
333impl<S: PartialEq + Slice<Item = u8> + ?Sized, L: Layout> PartialEq<S> for SmallSlice<S, L> {
334    fn eq(&self, other: &S) -> bool {
335        self.deref() == other
336    }
337}
338
339impl<'a, S: PartialEq + Slice<Item = u8> + ?Sized, L: Layout> PartialEq<&'a S>
340    for SmallSlice<S, L>
341{
342    fn eq(&self, other: &&'a S) -> bool {
343        self.deref() == *other
344    }
345}
346
347impl<L: Layout, const N: usize> PartialEq<[u8; N]> for SmallSlice<[u8], L> {
348    fn eq(&self, other: &[u8; N]) -> bool {
349        *other == **self
350    }
351}
352
353impl<'a, L: Layout, const N: usize> PartialEq<&'a [u8; N]> for SmallSlice<[u8], L> {
354    fn eq(&self, other: &&'a [u8; N]) -> bool {
355        **other == **self
356    }
357}
358
359impl<L: Layout, const N: usize> PartialEq<SmallSlice<[u8], L>> for [u8; N] {
360    fn eq(&self, other: &SmallSlice<[u8], L>) -> bool {
361        **other == *self
362    }
363}
364
365impl<L: Layout> PartialEq<SmallSlice<[u8], L>> for [u8] {
366    fn eq(&self, other: &SmallSlice<[u8], L>) -> bool {
367        **other == *self
368    }
369}
370
371impl<L: Layout> PartialEq<SmallSlice<str, L>> for str {
372    fn eq(&self, other: &SmallSlice<str, L>) -> bool {
373        **other == *self
374    }
375}
376
377impl<L: Layout> PartialEq<Vec<u8>> for SmallSlice<[u8], L> {
378    fn eq(&self, other: &Vec<u8>) -> bool {
379        **self == **other
380    }
381}
382
383impl<L: Layout> PartialEq<String> for SmallSlice<str, L> {
384    fn eq(&self, other: &String) -> bool {
385        **self == **other
386    }
387}
388
389impl<L: Layout> PartialEq<SmallSlice<[u8], L>> for Vec<u8> {
390    fn eq(&self, other: &SmallSlice<[u8], L>) -> bool {
391        **self == **other
392    }
393}
394
395impl<L: Layout> PartialEq<SmallSlice<str, L>> for String {
396    fn eq(&self, other: &SmallSlice<str, L>) -> bool {
397        **self == **other
398    }
399}
400
401/// A wrapper enabling [small string optimization] into [`ArcSlice`].
402///
403/// It can store up to `size_of::<ArcBytes<L>>() - 2` bytes inline, without allocating.
404/// However, the niche optimization of `ArcSlice` is lost, which means that
405/// `size_of::<Option<SmallArcBytes<L>>>() == size_of::<SmallArcBytes<L>>() + size_of::<usize>()`.
406///
407/// [small string optimization]: https://cppdepend.com/blog/understanding-small-string-optimization-sso-in-stdstring/
408pub struct SmallArcSlice<S: Slice<Item = u8> + ?Sized, L: Layout = DefaultLayout>(Inner<S, L>);
409
410#[repr(C)]
411union Inner<S: Slice<Item = u8> + ?Sized, L: Layout> {
412    small: SmallSlice<S, L>,
413    arc: ManuallyDrop<ArcSlice<S, L>>,
414}
415
416impl<S: Slice<Item = u8> + ?Sized, L: Layout> SmallArcSlice<S, L> {
417    /// Creates a new empty `SmallArcSlice`.
418    ///
419    /// # Examples
420    ///
421    /// ```rust
422    /// use arc_slice::inlined::SmallArcSlice;
423    ///
424    /// let s = SmallArcSlice::<[u8]>::new();
425    /// assert_eq!(s, []);
426    /// ```
427    pub const fn new() -> Self {
428        Self(Inner {
429            small: SmallSlice::EMPTY,
430        })
431    }
432
433    /// Creates a new `SmallArcSlice` by copying the given slice.
434    ///
435    /// The slice will be stored inlined if it can fit into a `SmallSlice`.
436    ///
437    /// # Panics
438    ///
439    /// Panics if the new capacity exceeds `isize::MAX - size_of::<usize>()` bytes.
440    ///
441    /// # Examples
442    ///
443    /// ```rust
444    /// use arc_slice::inlined::SmallArcSlice;
445    ///
446    /// let s = SmallArcSlice::<[u8]>::from_slice(b"hello world");
447    /// assert_eq!(s, b"hello world");
448    /// ```
449    #[cfg(feature = "oom-handling")]
450    pub fn from_slice(slice: &S) -> Self {
451        SmallSlice::new(slice).map_or_else(|| ArcSlice::from_slice(slice).into(), Into::into)
452    }
453
454    /// Tries creating a new `SmallArcSlice` by copying the given slice, returning an error if the
455    /// allocation fails.
456    ///
457    /// The slice will be stored inlined if it can fit into a `SmallSlice`.
458    ///
459    /// # Examples
460    ///
461    /// ```rust
462    /// use arc_slice::inlined::SmallArcSlice;
463    ///
464    /// # fn main() -> Result<(), arc_slice::error::AllocError> {
465    /// let s = SmallArcSlice::<[u8]>::try_from_slice(b"hello world")?;
466    /// assert_eq!(s, b"hello world");
467    /// # Ok(())
468    /// # }
469    /// ```
470    pub fn try_from_slice(slice: &S) -> Result<Self, AllocError> {
471        SmallSlice::new(slice).map_or_else(
472            || Ok(ArcSlice::try_from_slice(slice)?.into()),
473            |s| Ok(s.into()),
474        )
475    }
476
477    /// Returns either a reference to the inlined [`SmallSlice`] storage, or to the [`ArcSlice`]
478    /// one.
479    ///
480    /// # Examples
481    ///
482    /// ```rust
483    /// use arc_slice::inlined::SmallArcSlice;
484    /// use either::Either;
485    ///
486    /// let s = SmallArcSlice::<[u8]>::new();
487    /// assert!(matches!(s.as_either(), Either::Left(_)));
488    ///
489    /// let s = SmallArcSlice::<[u8]>::from_array([0; 256]);
490    /// assert!(matches!(s.as_either(), Either::Right(_)));
491    /// ```
492    #[inline(always)]
493    pub fn as_either(&self) -> Either<&SmallSlice<S, L>, &ArcSlice<S, L>> {
494        if unsafe { SmallSlice::is_inlined(addr_of!(self.0.small)) } {
495            Either::Left(unsafe { &self.0.small })
496        } else {
497            Either::Right(unsafe { &*ptr::from_ref(&self.0.arc).cast() })
498        }
499    }
500
501    /// Returns either a mutable reference to the inlined [`SmallSlice`] storage, or to the
502    /// [`ArcSlice`] one.
503    ///
504    /// # Examples
505    ///
506    /// ```rust
507    /// use arc_slice::inlined::SmallArcSlice;
508    /// use either::Either;
509    ///
510    /// let mut s = SmallArcSlice::<[u8]>::new();
511    /// assert!(matches!(s.as_either_mut(), Either::Left(_)));
512    ///
513    /// let mut s = SmallArcSlice::<[u8]>::from_array([0; 256]);
514    /// assert!(matches!(s.as_either_mut(), Either::Right(_)));
515    /// ```
516    #[inline(always)]
517    pub fn as_either_mut(&mut self) -> Either<&mut SmallSlice<S, L>, &mut ArcSlice<S, L>> {
518        if unsafe { SmallSlice::is_inlined(addr_of!(self.0.small)) } {
519            Either::Left(unsafe { &mut self.0.small })
520        } else {
521            Either::Right(unsafe { &mut self.0.arc })
522        }
523    }
524
525    /// Returns either the inlined [`SmallSlice`] storage, or the [`ArcSlice`] one.
526    #[inline(always)]
527    pub fn into_either(self) -> Either<SmallSlice<S, L>, ArcSlice<S, L>> {
528        let mut this = ManuallyDrop::new(self);
529        if unsafe { SmallSlice::is_inlined(addr_of!(this.0.small)) } {
530            Either::Left(unsafe { this.0.small })
531        } else {
532            Either::Right(unsafe { ManuallyDrop::take(&mut this.0.arc) })
533        }
534    }
535
536    /// Returns the number of items in the slice.
537    ///
538    /// # Examples
539    ///
540    /// ```rust
541    /// use arc_slice::inlined::SmallArcSlice;
542    ///
543    /// let s = SmallArcSlice::<[u8]>::from(&[0, 1, 2]);
544    /// assert_eq!(s.len(), 3);
545    /// ```
546    pub fn len(&self) -> usize {
547        match self.as_either() {
548            Either::Left(bytes) => bytes.len(),
549            Either::Right(bytes) => bytes.len(),
550        }
551    }
552
553    /// Returns `true` if the slice contains no items.
554    ///
555    /// # Examples
556    ///
557    /// ```rust
558    /// use arc_slice::inlined::SmallArcSlice;
559    ///
560    /// let s = SmallArcSlice::<[u8]>::from(&[0, 1, 2]);
561    /// assert!(!s.is_empty());
562    ///
563    /// let s = SmallArcSlice::<[u8]>::from(&[]);
564    /// assert!(s.is_empty());
565    /// ```
566    pub fn is_empty(&self) -> bool {
567        self.len() == 0
568    }
569
570    /// Returns a raw pointer to the slice's first item.
571    ///
572    /// See [`slice::as_ptr`].
573    pub fn as_ptr(&self) -> *const u8 {
574        match self.as_either() {
575            Either::Left(bytes) => bytes.as_ptr(),
576            Either::Right(bytes) => bytes.start.as_ptr(),
577        }
578    }
579
580    /// Tries cloning the `SmallArcSlice`, returning an error if an allocation fails.
581    ///
582    /// The operation may allocate. See [`CloneNoAllocLayout`](crate::layout::CloneNoAllocLayout)
583    /// documentation for cases where it does not.
584    ///
585    /// # Examples
586    ///
587    /// ```rust
588    /// use arc_slice::inlined::SmallArcSlice;
589    ///
590    /// # fn main() -> Result<(), arc_slice::error::AllocError> {
591    /// let s = SmallArcSlice::<[u8]>::try_from_slice(b"hello world")?;
592    /// let s2 = s.try_clone()?;
593    /// assert_eq!(s2, b"hello world");
594    /// # Ok(())
595    /// # }
596    /// ```
597    pub fn try_clone(&self) -> Result<Self, AllocError> {
598        Ok(match self.as_either() {
599            Either::Left(bytes) => Self(Inner { small: *bytes }),
600            Either::Right(bytes) => Self(Inner {
601                arc: ManuallyDrop::new(bytes.try_clone()?),
602            }),
603        })
604    }
605
606    /// Tries extracting a subslice of an `SmallArcSlice` with a given range, returning an error
607    /// if an allocation fails.
608    ///
609    /// The operation may allocate. See [`CloneNoAllocLayout`](crate::layout::CloneNoAllocLayout)
610    /// documentation for cases where it does not.
611    ///
612    /// # Examples
613    ///
614    /// ```rust
615    /// use arc_slice::inlined::SmallArcSlice;
616    ///
617    /// # fn main() -> Result<(), arc_slice::error::AllocError> {
618    /// let s = SmallArcSlice::<[u8]>::try_from_slice(b"hello world")?;
619    /// let s2 = s.try_subslice(..5)?;
620    /// assert_eq!(s2, b"hello");
621    /// # Ok(())
622    /// # }
623    /// ```
624    pub fn try_subslice(&self, range: impl RangeBounds<usize>) -> Result<Self, AllocError>
625    where
626        S: Subsliceable,
627    {
628        match self.as_either() {
629            Either::Left(bytes) => Ok(bytes.subslice(range).into()),
630            Either::Right(bytes) => Ok(bytes.try_subslice(range)?.into()),
631        }
632    }
633
634    #[doc(hidden)]
635    pub fn _advance(&mut self, cnt: usize)
636    where
637        S: Subsliceable,
638    {
639        match self.as_either_mut() {
640            Either::Left(s) => s.advance(cnt),
641            Either::Right(s) => s.advance(cnt),
642        }
643    }
644}
645
646impl<L: Layout> SmallArcSlice<[u8], L> {
647    /// Creates a new `SmallArcSlice` by moving the given array.
648    ///
649    /// # Panics
650    ///
651    /// Panics if the new capacity exceeds `isize::MAX - size_of::<usize>()` bytes.
652    ///
653    /// # Examples
654    ///
655    /// ```rust
656    /// use arc_slice::inlined::SmallArcSlice;
657    ///
658    /// let s = SmallArcSlice::<[u8]>::from_array([0, 1, 2]);
659    /// assert_eq!(s, [0, 1, 2]);
660    /// ```
661    #[cfg(feature = "oom-handling")]
662    pub fn from_array<const N: usize>(array: [u8; N]) -> Self {
663        SmallSlice::new(array.as_slice())
664            .map_or_else(|| ArcSlice::from_array(array).into(), Into::into)
665    }
666
667    /// Tries creating a new `SmallArcSlice` by moving the given array, returning it if an
668    /// allocation fails.
669    ///
670    /// # Examples
671    ///
672    /// ```rust
673    /// use arc_slice::inlined::SmallArcSlice;
674    ///
675    /// let s = SmallArcSlice::<[u8]>::try_from_array([0, 1, 2]).unwrap();
676    /// assert_eq!(s, [0, 1, 2]);
677    /// ```
678    pub fn try_from_array<const N: usize>(array: [u8; N]) -> Result<Self, [u8; N]> {
679        SmallSlice::new(array.as_slice()).map_or_else(
680            || Ok(ArcSlice::try_from_array(array)?.into()),
681            |a| Ok(a.into()),
682        )
683    }
684}
685
686impl<
687        S: Slice<Item = u8> + ?Sized,
688        #[cfg(feature = "oom-handling")] L: Layout,
689        #[cfg(not(feature = "oom-handling"))] L: CloneNoAllocLayout,
690    > SmallArcSlice<S, L>
691{
692    /// Extracts a subslice of an `SmallArcSlice` with a given range.
693    ///
694    /// # Examples
695    ///
696    /// ```rust
697    /// use arc_slice::inlined::SmallArcSlice;
698    ///
699    /// let s = SmallArcSlice::<[u8]>::from_slice(b"hello world");
700    /// let s2 = s.subslice(..5);
701    /// assert_eq!(s2, b"hello");
702    /// ```
703    pub fn subslice(&self, range: impl RangeBounds<usize>) -> Self
704    where
705        S: Subsliceable,
706    {
707        match self.as_either() {
708            Either::Left(bytes) => bytes.subslice(range).into(),
709            Either::Right(bytes) => bytes.subslice(range).into(),
710        }
711    }
712}
713
714impl<L: StaticLayout> SmallArcSlice<[u8], L> {
715    /// Creates a new `SmallArcSlice` from a static slice.
716    ///
717    /// The operation never allocates.
718    ///
719    /// # Examples
720    ///
721    /// ```rust
722    /// use arc_slice::{inlined::SmallArcSlice, layout::ArcLayout};
723    ///
724    /// static HELLO_WORLD: SmallArcSlice<[u8], ArcLayout<true, true>> =
725    ///     SmallArcSlice::<[u8], ArcLayout<true, true>>::from_static(b"hello world");
726    /// ```
727    pub const fn from_static(slice: &'static [u8]) -> SmallArcSlice<[u8], L> {
728        Self(Inner {
729            arc: ManuallyDrop::new(ArcSlice::<[u8], L>::from_static(slice)),
730        })
731    }
732}
733
734impl<L: StaticLayout> SmallArcSlice<str, L> {
735    /// Creates a new `SmallArcSlice` from a static slice.
736    ///
737    /// The operation never allocates.
738    ///
739    /// # Examples
740    ///
741    /// ```rust
742    /// use arc_slice::{inlined::SmallArcSlice, layout::ArcLayout};
743    ///
744    /// static HELLO_WORLD: SmallArcSlice<[u8], ArcLayout<true, true>> =
745    ///     SmallArcSlice::<[u8], ArcLayout<true, true>>::from_static(b"hello world");
746    /// ```
747    pub const fn from_static(slice: &'static str) -> SmallArcSlice<str, L> {
748        Self(Inner {
749            arc: ManuallyDrop::new(ArcSlice::<str, L>::from_static(slice)),
750        })
751    }
752}
753
754impl<S: Slice<Item = u8> + ?Sized, L: Layout> Drop for SmallArcSlice<S, L> {
755    fn drop(&mut self) {
756        if let Either::Right(bytes) = self.as_either_mut() {
757            unsafe { ptr::drop_in_place(bytes) }
758        }
759    }
760}
761
762impl<
763        S: Slice<Item = u8> + ?Sized,
764        #[cfg(feature = "oom-handling")] L: Layout,
765        #[cfg(not(feature = "oom-handling"))] L: CloneNoAllocLayout,
766    > Clone for SmallArcSlice<S, L>
767{
768    fn clone(&self) -> Self {
769        match self.as_either() {
770            Either::Left(bytes) => Self(Inner { small: *bytes }),
771            Either::Right(bytes) => Self(Inner {
772                arc: ManuallyDrop::new(bytes.clone()),
773            }),
774        }
775    }
776}
777
778impl<S: Slice<Item = u8> + ?Sized, L: Layout> Deref for SmallArcSlice<S, L> {
779    type Target = S;
780
781    fn deref(&self) -> &Self::Target {
782        match self.as_either() {
783            Either::Left(bytes) => bytes,
784            Either::Right(bytes) => bytes,
785        }
786    }
787}
788
789impl<S: Slice<Item = u8> + ?Sized, L: Layout> AsRef<S> for SmallArcSlice<S, L> {
790    fn as_ref(&self) -> &S {
791        self
792    }
793}
794
795impl<S: Hash + Slice<Item = u8> + ?Sized, L: Layout> Hash for SmallArcSlice<S, L> {
796    fn hash<H>(&self, state: &mut H)
797    where
798        H: Hasher,
799    {
800        self.deref().hash(state);
801    }
802}
803
804impl<S: Slice<Item = u8> + ?Sized, L: Layout> Borrow<S> for SmallArcSlice<S, L> {
805    fn borrow(&self) -> &S {
806        self
807    }
808}
809
810impl<S: Emptyable<Item = u8> + ?Sized, L: Layout> Default for SmallArcSlice<S, L> {
811    fn default() -> Self {
812        Self::from(SmallSlice::default())
813    }
814}
815
816impl<S: fmt::Debug + Slice<Item = u8> + ?Sized, L: Layout> fmt::Debug for SmallArcSlice<S, L> {
817    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
818        debug_slice(self.deref(), f)
819    }
820}
821
822impl<S: fmt::Display + Slice<Item = u8> + ?Sized, L: Layout> fmt::Display for SmallArcSlice<S, L> {
823    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
824        self.deref().fmt(f)
825    }
826}
827
828impl<S: Slice<Item = u8> + ?Sized, L: Layout> fmt::LowerHex for SmallArcSlice<S, L> {
829    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
830        lower_hex(self.to_slice(), f)
831    }
832}
833
834impl<S: Slice<Item = u8> + ?Sized, L: Layout> fmt::UpperHex for SmallArcSlice<S, L> {
835    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
836        upper_hex(self.to_slice(), f)
837    }
838}
839
840impl<S: PartialEq + Slice<Item = u8> + ?Sized, L: Layout> PartialEq for SmallArcSlice<S, L> {
841    fn eq(&self, other: &SmallArcSlice<S, L>) -> bool {
842        **self == **other
843    }
844}
845
846impl<S: PartialEq + Slice<Item = u8> + ?Sized, L: Layout> Eq for SmallArcSlice<S, L> {}
847
848impl<S: PartialOrd + Slice<Item = u8> + ?Sized, L: Layout> PartialOrd for SmallArcSlice<S, L> {
849    fn partial_cmp(&self, other: &SmallArcSlice<S, L>) -> Option<cmp::Ordering> {
850        self.deref().partial_cmp(other.deref())
851    }
852}
853
854impl<S: Ord + Slice<Item = u8> + ?Sized, L: Layout> Ord for SmallArcSlice<S, L> {
855    fn cmp(&self, other: &SmallArcSlice<S, L>) -> cmp::Ordering {
856        self.deref().cmp(other.deref())
857    }
858}
859
860impl<S: PartialEq + Slice<Item = u8> + ?Sized, L: Layout> PartialEq<S> for SmallArcSlice<S, L> {
861    fn eq(&self, other: &S) -> bool {
862        self.deref() == other
863    }
864}
865
866impl<'a, S: PartialEq + Slice<Item = u8> + ?Sized, L: Layout> PartialEq<&'a S>
867    for SmallArcSlice<S, L>
868{
869    fn eq(&self, other: &&'a S) -> bool {
870        self.deref() == *other
871    }
872}
873
874impl<L: Layout, const N: usize> PartialEq<[u8; N]> for SmallArcSlice<[u8], L> {
875    fn eq(&self, other: &[u8; N]) -> bool {
876        *other == **self
877    }
878}
879
880impl<'a, L: Layout, const N: usize> PartialEq<&'a [u8; N]> for SmallArcSlice<[u8], L> {
881    fn eq(&self, other: &&'a [u8; N]) -> bool {
882        **other == **self
883    }
884}
885
886impl<L: Layout, const N: usize> PartialEq<SmallArcSlice<[u8], L>> for [u8; N] {
887    fn eq(&self, other: &SmallArcSlice<[u8], L>) -> bool {
888        **other == *self
889    }
890}
891
892impl<L: Layout> PartialEq<SmallArcSlice<[u8], L>> for [u8] {
893    fn eq(&self, other: &SmallArcSlice<[u8], L>) -> bool {
894        **other == *self
895    }
896}
897
898impl<L: Layout> PartialEq<SmallArcSlice<str, L>> for str {
899    fn eq(&self, other: &SmallArcSlice<str, L>) -> bool {
900        **other == *self
901    }
902}
903
904impl<L: Layout> PartialEq<Vec<u8>> for SmallArcSlice<[u8], L> {
905    fn eq(&self, other: &Vec<u8>) -> bool {
906        **self == **other
907    }
908}
909
910impl<L: Layout> PartialEq<String> for SmallArcSlice<str, L> {
911    fn eq(&self, other: &String) -> bool {
912        **self == **other
913    }
914}
915
916impl<L: Layout> PartialEq<SmallArcSlice<[u8], L>> for Vec<u8> {
917    fn eq(&self, other: &SmallArcSlice<[u8], L>) -> bool {
918        **self == **other
919    }
920}
921
922impl<L: Layout> PartialEq<SmallArcSlice<str, L>> for String {
923    fn eq(&self, other: &SmallArcSlice<str, L>) -> bool {
924        **self == **other
925    }
926}
927
928#[cfg(feature = "oom-handling")]
929impl<S: Slice<Item = u8> + ?Sized, L: AnyBufferLayout> From<&S> for SmallArcSlice<S, L> {
930    fn from(value: &S) -> Self {
931        Self::from_slice(value)
932    }
933}
934
935#[cfg(feature = "oom-handling")]
936impl<L: AnyBufferLayout, const N: usize> From<&[u8; N]> for SmallArcSlice<[u8], L> {
937    fn from(value: &[u8; N]) -> Self {
938        Self::from_slice(value)
939    }
940}
941
942#[cfg(feature = "oom-handling")]
943impl<L: AnyBufferLayout, const N: usize> From<[u8; N]> for SmallArcSlice<[u8], L> {
944    fn from(value: [u8; N]) -> Self {
945        Self::from_array(value)
946    }
947}
948
949#[cfg(feature = "oom-handling")]
950impl<S: Slice<Item = u8> + ?Sized, L: AnyBufferLayout> From<alloc::boxed::Box<S>>
951    for SmallArcSlice<S, L>
952{
953    fn from(value: alloc::boxed::Box<S>) -> Self {
954        ArcSlice::from(value).into()
955    }
956}
957
958#[cfg(feature = "oom-handling")]
959impl<L: AnyBufferLayout> From<Vec<u8>> for SmallArcSlice<[u8], L> {
960    fn from(value: Vec<u8>) -> Self {
961        ArcSlice::from(value).into()
962    }
963}
964
965#[cfg(feature = "oom-handling")]
966impl<L: AnyBufferLayout> From<String> for SmallArcSlice<str, L> {
967    fn from(value: String) -> Self {
968        ArcSlice::from(value).into()
969    }
970}
971
972impl<S: Slice<Item = u8> + ?Sized, L: Layout> From<SmallSlice<S, L>> for SmallArcSlice<S, L> {
973    fn from(value: SmallSlice<S, L>) -> Self {
974        Self(Inner { small: value })
975    }
976}
977
978impl<S: Slice<Item = u8> + ?Sized, L: Layout> From<ArcSlice<S, L>> for SmallArcSlice<S, L> {
979    fn from(value: ArcSlice<S, L>) -> Self {
980        Self(Inner {
981            arc: ManuallyDrop::new(value),
982        })
983    }
984}
985
986#[cfg(feature = "oom-handling")]
987impl<L: Layout> core::str::FromStr for SmallArcSlice<str, L> {
988    type Err = core::convert::Infallible;
989
990    fn from_str(s: &str) -> Result<Self, Self::Err> {
991        Ok(Self::from_slice(s))
992    }
993}
994
995/// An alias for `SmallArcSlice<[u8], L>`.
996pub type SmallArcBytes<L = DefaultLayout> = SmallArcSlice<[u8], L>;
997/// An alias for `SmallArcSlice<str, L>`.
998pub type SmallArcStr<L = DefaultLayout> = SmallArcSlice<str, L>;