#![cfg_attr(not(feature = "std"), no_std)]
#![allow(clippy::let_unit_value)]
use core::{
marker::PhantomData,
ops::{Index, IndexMut, Deref, DerefMut},
};
trait IsValidIndex<const INDEX: usize> {
const RESULT: ();
}
pub struct StaticIndex<const INDEX: usize>;
impl<T, const INDEX: usize, const N: usize> IsValidIndex<INDEX> for [T; N] {
const RESULT: () = assert!(N > INDEX, "Index is out of bounds!");
}
impl<T, const INDEX: usize, const N: usize> Index<StaticIndex<INDEX>> for [T; N] {
type Output = T;
fn index(&self, _: StaticIndex<INDEX>) -> &Self::Output {
let _ = <[T; N] as IsValidIndex<INDEX>>::RESULT;
unsafe { &*(self.as_ptr().add(INDEX) as *const T) }
}
}
impl<T, const INDEX: usize, const N: usize> IndexMut<StaticIndex<INDEX>> for [T; N] {
fn index_mut(&mut self, _: StaticIndex<INDEX>) -> &mut Self::Output {
let _ = <[T; N] as IsValidIndex<INDEX>>::RESULT;
unsafe { &mut *(self.as_mut_ptr().add(INDEX) as *mut T) }
}
}
trait IsValidRangeIndex<const START: usize, const LENGTH: usize> {
const RESULT: ();
}
pub struct StaticRangeIndex<const START: usize, const LENGTH: usize>;
impl<T, const START: usize, const LENGTH: usize, const N: usize> IsValidRangeIndex<START, LENGTH>
for [T; N]
{
const RESULT: () = {
assert!(N > START, "Starting index is out of bounds!");
assert!(N - START >= LENGTH, "Ending index is out of bounds! Check your range index's length.");
};
}
impl<T, const START: usize, const LENGTH: usize, const N: usize>
Index<StaticRangeIndex<START, LENGTH>> for [T; N]
{
type Output = [T; LENGTH];
fn index(&self, _: StaticRangeIndex<START, LENGTH>) -> &Self::Output {
let _ = <[T; N] as IsValidRangeIndex<START, LENGTH>>::RESULT;
unsafe { &*(self.as_ptr().add(START) as *const [T; LENGTH]) }
}
}
impl<T, const START: usize, const LENGTH: usize, const N: usize>
IndexMut<StaticRangeIndex<START, LENGTH>> for [T; N]
{
fn index_mut(&mut self, _: StaticRangeIndex<START, LENGTH>) -> &mut Self::Output {
let _ = <[T; N] as IsValidRangeIndex<START, LENGTH>>::RESULT;
unsafe { &mut *(self.as_mut_ptr().add(START) as *mut [T; LENGTH]) }
}
}
#[repr(transparent)]
pub struct SliceWrapper<'a, I, T>(
T,
PhantomData<&'a ()>,
PhantomData<I>
);
impl<'a, I, T> SliceWrapper<'a, I, T> where T: AsRef<[I]> {
pub fn new(data: T) -> Self {
Self(data, PhantomData, PhantomData)
}
}
impl<'a, I, T> Deref for SliceWrapper<'a, I, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a, I, T> DerefMut for SliceWrapper<'a, I, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<I, S: AsRef<[I]>, const START: usize, const LENGTH: usize> Index<StaticRangeIndex<START, LENGTH>> for SliceWrapper<'_, I, S> {
type Output = [I; LENGTH];
fn index(&self, _: StaticRangeIndex<START, LENGTH>) -> &Self::Output {
let inner: &[I] = self.0.as_ref();
assert!(inner.len() > START, "Starting index {} is out of bounds", START);
assert!(inner.len() - START >= LENGTH, "Not enough items after index {} (requested {}; length: {})", START, LENGTH, inner.len());
unsafe { &*(inner.as_ptr().add(START) as *const [I; LENGTH]) }
}
}
impl<I, S: AsRef<[I]>, const INDEX: usize> Index<StaticIndex<INDEX>> for SliceWrapper<'_, I, S> {
type Output = I;
fn index(&self, _: StaticIndex<INDEX>) -> &Self::Output {
self.0.as_ref().index(INDEX)
}
}
impl<I, S: AsRef<[I]> + AsMut<[I]>, const START: usize, const LENGTH: usize> IndexMut<StaticRangeIndex<START, LENGTH>> for SliceWrapper<'_, I, S> {
fn index_mut(&mut self, _: StaticRangeIndex<START, LENGTH>) -> &mut Self::Output {
let inner: &mut [I] = self.0.as_mut();
assert!(inner.len() > START, "Starting index {} is out of bounds", START);
assert!(inner.len() - START >= LENGTH, "Not enough items after index {} (requested {}; length: {})", START, LENGTH, inner.len());
unsafe { &mut *(inner.as_mut_ptr().add(START) as *mut [I; LENGTH]) }
}
}
impl<I, S: AsRef<[I]> + AsMut<[I]>, const INDEX: usize> IndexMut<StaticIndex<INDEX>> for SliceWrapper<'_, I, S> {
fn index_mut(&mut self, _: StaticIndex<INDEX>) -> &mut Self::Output {
self.0.as_mut().index_mut(INDEX)
}
}
#[cfg(test)]
mod tests {
use super::*;
mod core_functionality {
use super::*;
#[test]
fn test_immutable_static_slice() {
let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
let sub_arr = arr[StaticRangeIndex::<4, 8>];
assert_eq!(sub_arr, arr[4..12]);
}
#[test]
fn test_mutable_static_slice() {
let mut arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
let sub_arr = &mut arr[StaticRangeIndex::<4, 8>];
sub_arr[0] = 1234;
assert_eq!(arr[4], 1234);
}
#[test]
fn test_full_immutable_static_slice() {
let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
let sub_arr = arr[StaticRangeIndex::<0, 12>];
assert_eq!(arr, sub_arr);
}
#[test]
fn test_full_mutable_static_slice() {
let mut arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
let sub_arr = &mut arr[StaticRangeIndex::<0, 12>];
sub_arr[4] = 5;
sub_arr[5] = 4;
assert_eq!(arr[4], 5);
assert_eq!(arr[5], 4);
}
#[test]
fn test_immutable_static_index() {
let arr = [1, 2, 3, 4, 5];
assert_eq!(arr[StaticIndex::<4>], 5);
}
#[test]
fn test_mutable_static_index() {
let mut arr = [1, 2, 3, 4, 5];
arr[StaticIndex::<4>] = 6;
assert_eq!(arr, [1, 2, 3, 4, 6]);
}
}
mod wrapper_functionality {
use super::*;
#[test]
fn test_wrapped_slice_read_single() {
let x = SliceWrapper::new(&[1, 2, 3]);
assert_eq!(x[StaticIndex::<2>], 3);
assert_eq!(x.len(), 3);
}
#[test]
fn test_wrapped_slice_write_single() {
let mut x = [1, 2, 3];
let mut y = SliceWrapper::new(&mut x);
y[StaticIndex::<2>] = 5;
assert_eq!(x[2], 5);
}
#[test]
fn test_wrapped_slice_read_multi() {
let x = SliceWrapper::new(&[1, 2, 3]);
assert_eq!(x[StaticRangeIndex::<0, 2>], [1, 2]);
}
#[test]
fn test_wrapped_slice_write_multi() {
let mut x = [1, 2, 3];
let mut y = SliceWrapper::new(&mut x);
y[StaticRangeIndex::<0, 2>] = [3, 4];
assert_eq!(x, [3, 4, 3]);
}
#[test]
fn test_wrapped_vec_read() {
let x = vec![1, 2, 3];
let x = SliceWrapper::new(x);
assert_eq!(x[StaticRangeIndex::<0, 2>], [1, 2]);
assert_eq!(x.len(), 3);
}
#[test]
fn test_wrapped_vec_write() {
let mut x = vec![1, 2, 3];
let mut y = SliceWrapper::new(&mut x);
y[StaticRangeIndex::<1, 2>] = [4, 5];
assert_eq!(y[StaticRangeIndex::<0, 3>], [1, 4, 5]);
assert_eq!(x[0..3], [1, 4, 5]);
}
}
mod wrapper_safety {
use super::*;
#[test]
#[should_panic]
fn wrapped_slice_oob_read_should_panic() {
let x = SliceWrapper::new(&[1, 2, 3]);
let _ = x[StaticIndex::<3>];
}
#[test]
#[should_panic]
fn wrapped_slice_oob_write_should_panic() {
let mut x = [1, 2, 3];
let mut x = SliceWrapper::new(&mut x);
x[StaticIndex::<3>] = 1337;
}
#[test]
#[should_panic]
fn wrapped_slice_oob_range_read_should_panic() {
let x = SliceWrapper::new(&[1, 2, 3]);
let _ = x[StaticRangeIndex::<0, 5>];
}
#[test]
#[should_panic]
fn wrapped_slice_oob_range_write_should_panic() {
let mut x = [1, 2, 3];
let mut x = SliceWrapper::new(&mut x);
x[StaticRangeIndex::<0, 5>] = [2, 3, 4, 5, 6];
}
#[test]
#[should_panic]
fn wrapped_vec_oob_read_should_panic() {
let x = SliceWrapper::new(vec![1, 2, 3]);
let _ = x[StaticIndex::<3>];
}
#[test]
#[should_panic]
fn wrapped_vec_oob_write_should_panic() {
let mut x = SliceWrapper::new(vec![1, 2, 3]);
x[StaticIndex::<3>] = 1337;
}
#[test]
#[should_panic]
fn wrapped_vec_oob_range_read_should_panic() {
let x = SliceWrapper::new(vec![1, 2, 3]);
let _ = x[StaticRangeIndex::<0, 5>];
}
#[test]
#[should_panic]
fn wrapped_vec_oob_range_write_should_panic() {
let mut x = SliceWrapper::new(vec![1, 2, 3]);
x[StaticRangeIndex::<0, 5>] = [2, 3, 4, 5, 6];
}
}
}