#[derive(Copy)]
pub struct UncheckedIndex<S>(S);
impl<S: Copy> Clone for UncheckedIndex<S> {
fn clone(&self) -> Self { *self }
}
pub unsafe fn unchecked_index<T>(v: T) -> UncheckedIndex<T>
{
UncheckedIndex(v)
}
pub unsafe fn get_unchecked<T: ?Sized, I>(v: &T, index: I) -> &T::Output
where T: GetUnchecked<I>
{
#[cfg(debug_assertions)]
v.assert_indexable_with(&index);
v.get_unchecked(index)
}
pub unsafe fn get_unchecked_mut<T: ?Sized, I>(v: &mut T, index: I) -> &mut T::Output
where T: GetUncheckedMut<I>
{
#[cfg(debug_assertions)]
v.assert_indexable_with(&index);
v.get_unchecked_mut(index)
}
use std::ops::{Deref, DerefMut, Index, IndexMut};
impl<T> Deref for UncheckedIndex<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T> DerefMut for UncheckedIndex<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}
impl<T, I> Index<I> for UncheckedIndex<T>
where T: GetUnchecked<I>
{
type Output = T::Output;
#[inline]
fn index(&self, index: I) -> &Self::Output {
unsafe {
get_unchecked(&self.0, index)
}
}
}
impl<T, I> IndexMut<I> for UncheckedIndex<T>
where T: GetUncheckedMut<I>
{
#[inline]
fn index_mut(&mut self, index: I) -> &mut Self::Output {
unsafe {
get_unchecked_mut(&mut self.0, index)
}
}
}
pub trait CheckIndex<I> {
fn assert_indexable_with(&self, index: &I);
}
impl<'a, T: ?Sized, I> CheckIndex<I> for &'a T where T: CheckIndex<I> {
fn assert_indexable_with(&self, index: &I) {
(**self).assert_indexable_with(index)
}
}
impl<'a, T: ?Sized, I> CheckIndex<I> for &'a mut T where T: CheckIndex<I> {
fn assert_indexable_with(&self, index: &I) {
(**self).assert_indexable_with(index)
}
}
impl<T> CheckIndex<usize> for [T] {
fn assert_indexable_with(&self, &index: &usize) {
assert!(index < self.len(),
"assertion index < len failed: index out of bounds: \
index = {}, len = {}",
index, self.len())
}
}
pub trait GetUnchecked<I>: CheckIndex<I> {
type Output: ?Sized;
unsafe fn get_unchecked(&self, index: I) -> &Self::Output;
}
pub trait GetUncheckedMut<I>: GetUnchecked<I> {
unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut Self::Output;
}
impl<T> GetUnchecked<usize> for [T] {
type Output = T;
unsafe fn get_unchecked(&self, index: usize) -> &Self::Output {
(*self).get_unchecked(index)
}
}
impl<T> GetUncheckedMut<usize> for [T] {
unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut Self::Output {
(*self).get_unchecked_mut(index)
}
}
impl<'a, T: ?Sized, I> GetUnchecked<I> for &'a T
where T: GetUnchecked<I>
{
type Output = T::Output;
unsafe fn get_unchecked(&self, index: I) -> &Self::Output {
(**self).get_unchecked(index)
}
}
impl<'a, T: ?Sized, I> GetUnchecked<I> for &'a mut T
where T: GetUnchecked<I>
{
type Output = T::Output;
unsafe fn get_unchecked(&self, index: I) -> &Self::Output {
(**self).get_unchecked(index)
}
}
impl<'a, T: ?Sized, I> GetUncheckedMut<I> for &'a mut T
where T: GetUncheckedMut<I>
{
unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut Self::Output {
(**self).get_unchecked_mut(index)
}
}
macro_rules! impl_slice_range {
($index_type:ty, $self_:ident, $index: ident, $assertion:expr) => {
impl<T> CheckIndex<$index_type> for [T] {
fn assert_indexable_with($self_: &Self, $index: &$index_type) {
$assertion
}
}
impl<T> GetUnchecked<$index_type> for [T] {
type Output = [T];
unsafe fn get_unchecked(&self, index: $index_type) -> &Self::Output {
(*self).get_unchecked(index)
}
}
impl<T> GetUncheckedMut<$index_type> for [T] {
unsafe fn get_unchecked_mut(&mut self, index: $index_type) -> &mut Self::Output {
(*self).get_unchecked_mut(index)
}
}
}
}
use std::ops::{Range, RangeTo, RangeFrom, RangeFull};
impl_slice_range!(Range<usize>, self, index, {
assert!(index.start <= index.end,
"assertion start <= end failed: start = {}, end = {}, len = {}",
index.start, index.end, self.len());
assert!(index.end <= self.len(),
"assertion end <= len failed: end = {}, len = {}",
index.end, self.len());
});
impl_slice_range!(RangeTo<usize>, self, index, {
assert!(index.end <= self.len(),
"assertion end <= len failed: end = {}, len = {}",
index.end, self.len());
});
impl_slice_range!(RangeFrom<usize>, self, index, {
assert!(index.start <= self.len(),
"assertion start <= len failed: start = {}, len = {}",
index.start, self.len());
});
impl_slice_range!(RangeFull, self, _index, { });
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let mut data = [0; 8];
unsafe {
let mut data = unchecked_index(&mut data);
for i in 0..data.len() {
data[i] = i;
}
}
assert_eq!(data, [0, 1, 2, 3, 4, 5, 6, 7]);
}
#[cfg(debug_assertions)]
#[test]
#[should_panic]
fn debug_oob_check_write() {
let mut data = [0; 8];
unsafe {
let mut data = unchecked_index(&mut data[..7]);
data[7] = 1;
}
}
#[cfg(debug_assertions)]
#[test]
#[should_panic]
fn debug_oob_check_read() {
let mut data = [0; 8];
unsafe {
let data = unchecked_index(&mut data[..7]);
println!("{}", data[17]);
}
}
#[cfg(not(debug_assertions))]
#[test]
fn non_debug_oob() {
let mut data = [0; 8];
unsafe {
let mut data = unchecked_index(&mut data[..7]);
data[7] = 1;
}
assert_eq!(data, [0, 0, 0, 0, 0, 0, 0, 1]);
}
#[cfg(debug_assertions)]
#[test]
#[should_panic]
fn debug_oob_check_read_slice_1() {
let mut data = [0; 8];
unsafe {
let data = unchecked_index(&mut data[..7]);
println!("{:?}", &data[5..10]);
}
}
#[cfg(debug_assertions)]
#[test]
#[should_panic]
fn debug_oob_check_read_slice_2() {
let mut data = [0; 8];
unsafe {
let data = unchecked_index(&mut data[..7]);
println!("{:?}", &data[7..6]);
}
}
#[cfg(debug_assertions)]
#[test]
#[should_panic]
fn debug_oob_check_read_slice_3() {
let mut data = [0; 8];
unsafe {
let data = unchecked_index(&mut data[..7]);
println!("{:?}", &data[8..]);
}
}
#[cfg(debug_assertions)]
#[test]
#[should_panic]
fn debug_oob_check_read_slice_4() {
let mut data = [0; 8];
unsafe {
let data = unchecked_index(&mut data[..7]);
println!("{:?}", &data[..9]);
}
}
#[cfg(not(debug_assertions))]
#[test]
fn non_debug_oob_slice() {
let mut data = [0; 8];
unsafe {
let mut data = unchecked_index(&mut data[..7]);
data[7..8][0] = 1;
}
assert_eq!(data, [0, 0, 0, 0, 0, 0, 0, 1]);
}
}