shared_bytes 0.1.0-beta.4

Owned string and byte slices.
Documentation
mod iter;

pub use self::iter::{IntoIter, Iter};

#[cfg(test)]
mod tests;

use crate::{owned_slice::OwnedSlice, util::range, IndexOutOfBounds, RangeOfSubset, SharedStr};
use std::{
    borrow::{Borrow, Cow},
    fmt::{self, Debug},
    ops::{Deref, Range, RangeBounds},
    sync::Arc,
};

#[derive(Clone)]
pub struct SharedBytes(pub(crate) Flavour);

#[derive(Clone)]
pub(crate) enum Flavour {
    Static(&'static [u8]),
    ArcVecSlice(OwnedSlice<Arc<Vec<u8>>, [u8]>),
    ArcStringSlice(OwnedSlice<Arc<String>, [u8]>),
}

impl SharedBytes {
    #[inline]
    pub const fn new() -> Self {
        Self(Flavour::Static(b""))
    }

    #[inline]
    pub const fn from_static(x: &'static [u8]) -> Self {
        Self(Flavour::Static(x))
    }

    #[inline]
    pub fn from_vec(x: Vec<u8>) -> Self {
        Self::from_arc_vec(Arc::new(x))
    }

    #[inline]
    pub fn from_arc_vec(x: Arc<Vec<u8>>) -> Self {
        Self(Flavour::ArcVecSlice(OwnedSlice::new(x).unwrap()))
    }

    #[inline]
    pub fn from_arc_string(x: Arc<String>) -> Self {
        Self(Flavour::ArcStringSlice(OwnedSlice::new(x).unwrap()))
    }

    pub fn into_vec(self) -> Vec<u8> {
        self.into_static_cow().into_owned()
    }

    fn into_static_cow(self) -> Cow<'static, [u8]> {
        match self.0 {
            Flavour::Static(x) => Cow::Borrowed(x),
            Flavour::ArcVecSlice(x) => Cow::Owned(x.into_unwrapped(Into::into, ToOwned::to_owned)),
            Flavour::ArcStringSlice(x) => {
                Cow::Owned(x.into_unwrapped(Into::into, ToOwned::to_owned))
            }
        }
    }

    #[inline]
    pub fn as_slice(&self) -> &[u8] {
        match &self.0 {
            Flavour::Static(x) => x,
            Flavour::ArcVecSlice(x) => x,
            Flavour::ArcStringSlice(x) => x,
        }
    }

    pub fn as_static(&self) -> Option<&'static [u8]> {
        match &self.0 {
            Flavour::Static(x) => Some(x),
            _ => None,
        }
    }

    pub fn len(&self) -> usize {
        self.as_slice().len()
    }

    pub fn is_empty(&self) -> bool {
        self.as_slice().is_empty()
    }

    pub fn clear(&mut self) {
        *self = Self::new()
    }

    pub fn truncate(&mut self, at: usize) {
        self.try_slice_mut(..at)
            .unwrap_or_else(|_| panic!("truncate index '{at}' should be <= len '{}'", self.len()))
    }

    #[must_use = "consider fn truncate if you don't need the other half"]
    pub fn split_off(&mut self, at: usize) -> Self {
        self.try_split_off(at)
            .unwrap_or_else(|| panic!("split index '{at}' should be <= len '{}'", self.len()))
    }

    // may be promoted to a pub fn in the future
    fn try_split_off(&mut self, at: usize) -> Option<Self> {
        self.as_slice().get(at)?; // ensure `at` is not out of bounds
        let mut split = self.clone();
        split.slice_mut(at..);
        self.slice_mut(..at);
        Some(split)
    }

    pub fn range_of_subset(&self, subset: &[u8]) -> Range<usize> {
        RangeOfSubset::range_of_subset(self.as_slice(), subset)
    }

    pub fn slice_cloned<R: RangeBounds<usize>>(&self, r: R) -> Self {
        self.non_generic_slice_cloned(self.slice_range_from_bounds(r))
    }

    fn non_generic_slice_cloned(&self, range: Range<usize>) -> Self {
        self.non_generic_try_slice_cloned(range.clone())
            .unwrap_or_else(|_| self.out_of_bounds_panic(range))
    }

    pub fn try_slice_cloned<R: RangeBounds<usize>>(&self, r: R) -> Result<Self, IndexOutOfBounds> {
        self.non_generic_try_slice_cloned(self.slice_range_from_bounds(r))
    }

    fn non_generic_try_slice_cloned(&self, range: Range<usize>) -> Result<Self, IndexOutOfBounds> {
        if self.as_slice().get(range.clone()).is_none() {
            return Err(IndexOutOfBounds::new());
        }
        Ok(self.clone().slice_into(range))
    }

    pub fn slice_into<R: RangeBounds<usize>>(self, r: R) -> Self {
        let range = self.slice_range_from_bounds(r);
        self.non_generic_slice_into(range)
    }

    fn non_generic_slice_into(self, range: Range<usize>) -> Self {
        self.non_generic_try_slice_into(range.clone())
            .unwrap_or_else(|this| this.out_of_bounds_panic(range))
    }

    pub fn try_slice_into<R: RangeBounds<usize>>(self, r: R) -> Result<Self, Self> {
        let range = self.slice_range_from_bounds(r);
        self.non_generic_try_slice_into(range)
    }

    fn non_generic_try_slice_into(mut self, range: Range<usize>) -> Result<Self, Self> {
        match self.internal_try_slice_mut(range) {
            Ok(()) => Ok(self),
            Err(()) => Err(self),
        }
    }

    pub fn slice_mut<R: RangeBounds<usize>>(&mut self, r: R) {
        self.non_generic_slice_mut(self.slice_range_from_bounds(r))
    }

    fn non_generic_slice_mut(&mut self, range: Range<usize>) {
        self.internal_try_slice_mut(range.clone())
            .unwrap_or_else(|()| self.out_of_bounds_panic(range))
    }

    pub fn try_slice_mut<R: RangeBounds<usize>>(&mut self, r: R) -> Result<(), IndexOutOfBounds> {
        self.non_generic_try_slice_mut(self.slice_range_from_bounds(r))
    }

    fn non_generic_try_slice_mut(&mut self, range: Range<usize>) -> Result<(), IndexOutOfBounds> {
        self.internal_try_slice_mut(range)
            .map_err(|()| IndexOutOfBounds::new())
    }

    fn slice_range_from_bounds<R: RangeBounds<usize>>(&self, r: R) -> Range<usize> {
        range::from_slice_bounds(r, || self.len())
    }

    fn out_of_bounds_panic<R: RangeBounds<usize> + Debug, T>(&self, range: R) -> T {
        let length = self.len();
        panic!("slice range {range:?} is out of bounds for length {length}")
    }

    #[must_use = "`internal_try_slice_mut` may fail to mutate `self`"]
    fn internal_try_slice_mut(&mut self, range: Range<usize>) -> Result<(), ()> {
        match &mut self.0 {
            Flavour::Static(old) => match old.get(range) {
                None => Err(()),
                Some(new) => {
                    *old = new;
                    Ok(())
                }
            },
            Flavour::ArcVecSlice(x) => x.try_slice_mut(range),
            Flavour::ArcStringSlice(x) => x.try_slice_mut(range),
        }
    }

    pub fn iter(&self) -> Iter {
        Iter::new(self.as_slice())
    }
}

impl AsRef<[u8]> for SharedBytes {
    #[inline]
    fn as_ref(&self) -> &[u8] {
        self.as_slice()
    }
}

impl Borrow<[u8]> for SharedBytes {
    #[inline]
    fn borrow(&self) -> &[u8] {
        self.as_slice()
    }
}

impl Debug for SharedBytes {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        Debug::fmt(self.as_slice(), f)
    }
}

impl Default for SharedBytes {
    #[inline]
    fn default() -> Self {
        Self::new()
    }
}

impl Deref for SharedBytes {
    type Target = [u8];

    #[inline]
    fn deref(&self) -> &Self::Target {
        self.as_slice()
    }
}

impl Eq for SharedBytes {}

impl PartialEq for SharedBytes {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        self.as_slice() == other.as_slice()
    }
}

impl<Other: ?Sized> PartialEq<&Other> for SharedBytes
where
    Self: PartialEq<Other>,
{
    #[inline]
    fn eq(&self, other: &&Other) -> bool {
        self == *other
    }
}

impl PartialEq<[u8]> for SharedBytes {
    #[inline]
    fn eq(&self, other: &[u8]) -> bool {
        self.as_slice() == other
    }
}

impl<const N: usize> PartialEq<[u8; N]> for SharedBytes {
    #[inline]
    fn eq(&self, other: &[u8; N]) -> bool {
        self.as_slice() == other.as_slice()
    }
}

impl PartialEq<Vec<u8>> for SharedBytes {
    #[inline]
    fn eq(&self, other: &Vec<u8>) -> bool {
        self.as_slice() == other.as_slice()
    }
}

impl PartialEq<str> for SharedBytes {
    #[inline]
    fn eq(&self, other: &str) -> bool {
        self.as_slice() == other.as_bytes()
    }
}

impl PartialEq<String> for SharedBytes {
    #[inline]
    fn eq(&self, other: &String) -> bool {
        self.as_slice() == other.as_bytes()
    }
}

impl std::hash::Hash for SharedBytes {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.as_slice().hash(state)
    }
}

impl From<&'static [u8]> for SharedBytes {
    #[inline]
    fn from(x: &'static [u8]) -> Self {
        Self::from_static(x)
    }
}

impl From<Vec<u8>> for SharedBytes {
    #[inline]
    fn from(x: Vec<u8>) -> Self {
        Self::from_vec(x)
    }
}

impl From<Arc<Vec<u8>>> for SharedBytes {
    #[inline]
    fn from(x: Arc<Vec<u8>>) -> Self {
        Self::from_arc_vec(x)
    }
}

impl From<SharedStr> for SharedBytes {
    fn from(x: SharedStr) -> Self {
        use crate::shared_str::Flavour::*;
        Self(match x.0 {
            Static(x) => Flavour::Static(x.as_bytes()),
            ArcVecSlice(x) => Flavour::ArcVecSlice(x.try_map_output().unwrap()),
            ArcStringSlice(x) => Flavour::ArcStringSlice(x.try_map_output().unwrap()),
        })
    }
}

impl From<&'static str> for SharedBytes {
    #[inline]
    fn from(x: &'static str) -> Self {
        Self::from_static(x.as_bytes())
    }
}

impl From<String> for SharedBytes {
    #[inline]
    fn from(x: String) -> Self {
        Self::from_vec(x.into_bytes())
    }
}

impl From<Arc<String>> for SharedBytes {
    #[inline]
    fn from(x: Arc<String>) -> Self {
        Self::from_arc_string(x)
    }
}

impl From<SharedBytes> for Vec<u8> {
    fn from(x: SharedBytes) -> Self {
        x.into_vec()
    }
}

impl FromIterator<u8> for SharedBytes {
    #[inline]
    fn from_iter<T: IntoIterator<Item = u8>>(iter: T) -> Self {
        Self::from_vec(iter.into_iter().collect())
    }
}

impl<'a> IntoIterator for &'a SharedBytes {
    type Item = u8;

    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

impl IntoIterator for SharedBytes {
    type Item = u8;

    type IntoIter = IntoIter;

    fn into_iter(self) -> IntoIter {
        IntoIter(self)
    }
}