use std::ops::Range;
pub trait SliceChecked {
fn slice_checked(&self, range: Range<usize>) -> Option<&Self>;
}
impl<T> SliceChecked for [T] {
fn slice_checked(&self, range: Range<usize>) -> Option<&Self> {
if range.end <= self.len() {
Some(&self[range])
} else {
None
}
}
}
pub trait SubsliceOffset {
fn subslice_offset(&self, inner: &Self) -> Option<usize>;
}
pub trait SubsliceRange {
fn subslice_in_range(&self, inner: &Self) -> Option<Range<usize>>;
}
impl<T> SubsliceOffset for [T] {
fn subslice_offset(&self, inner: &Self) -> Option<usize> {
let start = self.as_ptr() as usize;
let inner_start = inner.as_ptr() as usize;
if inner_start < start || inner_start > start.wrapping_add(self.len()) {
None
} else {
inner_start.checked_sub(start)
}
}
}
impl<T> SubsliceRange for [T]
where
[T]: SubsliceOffset,
{
fn subslice_in_range(&self, inner: &Self) -> Option<Range<usize>> {
let offset = self.subslice_offset(inner)?;
let end = offset.checked_add(inner.len())?;
let start = self.as_ptr() as usize;
if end > start + self.len() {
None
} else {
Some(Range { start: offset, end })
}
}
}
#[cfg(test)]
mod tests {
use super::SubsliceOffset;
#[test]
fn subslice_offset() {
let a = &[0u8];
let v: Vec<u8> = vec![0, 1, 2, 3, 4, 5];
let b = &[0u8];
assert_eq!(v.subslice_offset(&v).unwrap(), 0);
assert_eq!(v.subslice_offset(&v[1..2]).unwrap(), 1);
assert_eq!(v.subslice_offset(&v[1..]).unwrap(), 1);
assert_eq!(v.subslice_offset(&v[2..]).unwrap(), 2);
assert_eq!(v.subslice_offset(&v[3..]).unwrap(), 3);
assert_eq!(v.subslice_offset(&v[5..]).unwrap(), 5);
assert!(v.subslice_offset(a).is_none());
assert!(v.subslice_offset(b).is_none());
}
}