shared_bytes 0.1.0-beta.4

Owned string and byte slices.
Documentation
use super::{
    length::Length,
    no_interior_mutability::NoInteriorMutability,
    slice::{Slice, TryIndexRange},
    slice_owner::SliceOwner,
};
use std::{marker::PhantomData, ops::Range};

pub(super) struct OwnedSliceCore<Owner, S: ?Sized> {
    owner: Owner,

    /// inclusive start
    start: usize,

    /// exclusive end
    end: usize,

    _phantom_slice: PhantomData<fn(&Owner) -> &S>,
}

impl<Owner, S> OwnedSliceCore<Owner, S>
where
    Owner: SliceOwner + NoInteriorMutability,
    Owner::Slice: Slice<S>,
    S: ?Sized,
{
    #[must_use = "new has no side effect"]
    pub fn try_new(owner: Owner, range: Range<usize>) -> Result<Self, Owner> {
        if Self::check_range(&owner, range.clone()).is_err() {
            return Err(owner);
        }
        Ok(Self {
            owner,
            start: range.start,
            end: range.end,
            _phantom_slice: PhantomData::default(),
        })
    }

    pub fn into_owner(self) -> Owner {
        self.owner
    }

    pub fn owner_length(&self) -> usize {
        self.owner.as_slice().length()
    }

    #[must_use = "has no side effect"]
    pub fn slice_range(&self) -> Range<usize> {
        self.start..self.end
    }

    #[must_use = "may fail to mutate `self`"]
    pub fn set_slice_range(&mut self, range: Range<usize>) -> Result<(), ()> {
        Self::check_range(&self.owner, range.clone())?;
        self.start = range.start;
        self.end = range.end;
        Ok(())
    }

    fn check_range(owner: &Owner, range: Range<usize>) -> Result<(), ()> {
        match owner.as_slice().try_index(range) {
            Some(_) => Ok(()),
            None => Err(()),
        }
    }

    #[must_use = "has no side effect"]
    pub fn as_slice(&self) -> &S {
        let slice = self.owner.as_slice();
        let index = self.start..self.end;
        if crate::UNSAFE_OPTIMISATIONS {
            // SAFETY:
            // Self::set_slice_range and Self::try_new already do a bounds check.
            // Self::into_owner exposes Owner but Owner has no interior mutability.
            unsafe { slice.index_unchecked(index) }
        } else {
            slice.index(index)
        }
    }
}

impl<Owner, S> Clone for OwnedSliceCore<Owner, S>
where
    Owner: Clone,
    S: ?Sized,
{
    fn clone(&self) -> Self {
        Self {
            owner: self.owner.clone(),
            start: self.start,
            end: self.end,
            _phantom_slice: self._phantom_slice,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::sync::Arc;

    #[test]
    fn as_slice() {
        let string = "Hello, Alice!";
        let mut owned_slice =
            OwnedSliceCore::<_, str>::try_new(string.to_owned(), 0..string.len()).unwrap();
        assert_eq!(owned_slice.as_slice(), string);
        owned_slice.set_slice_range(1..5).unwrap();
        assert_eq!(owned_slice.as_slice(), "ello");
    }

    #[test]
    fn try_new_invalid_utf_8_bytes_is_error() {
        let owner = vec![128];
        match OwnedSliceCore::<_, str>::try_new(owner.clone(), 0..1) {
            Ok(_) => panic!(),
            Err(moved_owner) => assert_eq!(owner, moved_owner),
        }
    }

    #[test]
    fn qc_bytes_as_slice_does_not_panic() {
        quickcheck::quickcheck(test_as_slice_does_not_panic::<_, [u8]> as fn(Vec<u8>, Range<usize>))
    }

    #[test]
    fn qc_bytes_str_as_slice_does_not_panic() {
        quickcheck::quickcheck(test_as_slice_does_not_panic::<_, str> as fn(Vec<u8>, Range<usize>))
    }

    #[test]
    fn qc_string_bytes_as_slice_does_not_panic() {
        quickcheck::quickcheck(test_as_slice_does_not_panic::<_, [u8]> as fn(String, Range<usize>))
    }

    #[test]
    fn qc_string_as_slice_does_not_panic() {
        quickcheck::quickcheck(test_as_slice_does_not_panic::<_, str> as fn(String, Range<usize>))
    }

    fn test_as_slice_does_not_panic<Owner, S>(owner: Owner, range: Range<usize>)
    where
        Owner: SliceOwner + NoInteriorMutability + Clone,
        Owner::Slice: Slice<S>,
        S: ?Sized,
    {
        inner_test_as_slice_does_not_panic::<_, S>(owner.clone(), range.clone());
        inner_test_as_slice_does_not_panic::<_, S>(Arc::new(owner), range);
    }

    fn inner_test_as_slice_does_not_panic<Owner, S>(owner: Owner, range: Range<usize>)
    where
        Owner: SliceOwner + NoInteriorMutability + Clone,
        Owner::Slice: Slice<S>,
        S: ?Sized,
    {
        let identity_range = 0..owner.as_slice().length();
        let mut owned_slice = match OwnedSliceCore::try_new(owner.clone(), identity_range) {
            Ok(x) => x,
            Err(_) => match OwnedSliceCore::try_new(owner, range.clone()) {
                Ok(x) => x,
                Err(_) => return,
            },
        };
        let _panic_test = owned_slice.as_slice();
        let _panic_test = owned_slice.set_slice_range(range);
        let _panic_test = owned_slice.as_slice();
    }
}