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,
start: usize,
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 {
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();
}
}