use num_traits::AsPrimitive;
use std::ops::{Add, Range, RangeFrom, RangeFull, RangeTo};
mod is_slice;
pub use is_slice::CouldBeSliceOf;
#[cfg(test)]
mod test;
#[derive(Debug, PartialEq)]
pub enum Error {
OutOfBounds,
NegativeSlice,
NotInSource,
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::OutOfBounds => write!(f, "the slice would be out of bounds of the source slice"),
Error::NegativeSlice => write!(f, "the start of the new slice would be after its end"),
Error::NotInSource => write!(f, "the slice is not part of the source slice"),
}
}
}
impl std::error::Error for Error {}
pub trait ResizeSlice<'a, 'source: 'a, T, R, E> {
fn resize(&'a self, source: &'source [T], by: R) -> &'source [T];
fn try_resize(&'a self, source: &'source [T], by: R) -> Result<&'source [T], E>;
}
impl<'a, 'source: 'a, T> ResizeSlice<'a, 'source, T, RangeFull, Error> for &'a [T] {
#[inline(always)]
fn resize(&'a self, source: &'source [T], _by: RangeFull) -> &'source [T] {
source
}
fn try_resize(&'a self, source: &'source [T], _by: RangeFull) -> Result<&'source [T], Error> {
if self.is_slice_of(source) {
Ok(source)
} else {
Err(Error::NotInSource)
}
}
}
impl<'a, 'source: 'a, T, I> ResizeSlice<'a, 'source, T, RangeFrom<I>, Error> for &'a [T]
where
I: AsPrimitive<usize> + Copy + Add<Output = I> + PartialOrd,
usize: AsPrimitive<I>,
{
fn resize(&'a self, source: &'source [T], by: RangeFrom<I>) -> &'source [T] {
let self_start =
(self.as_ptr() as usize - source.as_ptr() as usize) / std::mem::size_of::<T>();
let new_start = self_start.as_() + by.start;
&source[new_start.as_()..]
}
fn try_resize(&'a self, source: &'source [T], by: RangeFrom<I>) -> Result<&'source [T], Error> {
if !self.is_slice_of(source) {
return Err(Error::NotInSource);
}
let self_start =
(self.as_ptr() as usize - source.as_ptr() as usize) / std::mem::size_of::<T>();
let new_start = self_start.as_() + by.start;
if new_start < 0usize.as_() || new_start > source.len().as_() {
return Err(Error::OutOfBounds);
}
Ok(&source[new_start.as_()..])
}
}
impl<'a, 'source: 'a, T, I> ResizeSlice<'a, 'source, T, RangeTo<I>, Error> for &'source [T]
where
I: AsPrimitive<usize> + Copy + Add<Output = I> + PartialOrd,
usize: AsPrimitive<I>,
{
fn resize(&'a self, source: &'source [T], by: RangeTo<I>) -> &'source [T] {
let self_start =
(self.as_ptr() as usize - source.as_ptr() as usize) / std::mem::size_of::<T>();
let self_end = self_start + self.len();
let new_end = self_end.as_() + by.end;
&source[..new_end.as_()]
}
fn try_resize(&'a self, source: &'source [T], by: RangeTo<I>) -> Result<&'source [T], Error> {
if !self.is_slice_of(source) {
return Err(Error::NotInSource);
}
let self_start =
(self.as_ptr() as usize - source.as_ptr() as usize) / std::mem::size_of::<T>();
let self_end = self_start + self.len();
let new_end = self_end.as_() + by.end;
if new_end < 0usize.as_() || new_end > source.len().as_() {
return Err(Error::OutOfBounds);
}
Ok(&source[..new_end.as_()])
}
}
impl<'a, 'source: 'a, T, I> ResizeSlice<'a, 'source, T, Range<I>, Error> for &'a [T]
where
I: AsPrimitive<usize> + Copy + Add<Output = I> + PartialOrd,
usize: AsPrimitive<I>,
{
fn resize(&'a self, source: &'source [T], by: Range<I>) -> &'source [T] {
let self_start =
(self.as_ptr() as usize - source.as_ptr() as usize) / std::mem::size_of::<T>();
let self_end = self_start + self.len();
let new_start = self_start.as_() + by.start;
let new_end = self_end.as_() + by.end;
&source[new_start.as_()..new_end.as_()]
}
fn try_resize(&'a self, source: &'source [T], by: Range<I>) -> Result<&'source [T], Error> {
let self_start =
(self.as_ptr() as usize - source.as_ptr() as usize) / std::mem::size_of::<T>();
let self_end = self_start + self.len();
let new_start = self_start.as_() + by.start;
let new_end = self_end.as_() + by.end;
if new_end < new_start {
return Err(Error::NegativeSlice);
} else if new_start < 0usize.as_() || new_end > source.len().as_() {
return Err(Error::OutOfBounds);
}
Ok(&source[new_start.as_()..new_end.as_()])
}
}