#![warn(missing_docs)]
pub trait At<V, T> {
fn at(&self, c: T) -> &V;
fn at_mut(&mut self, c: T) -> &mut V;
}
macro_rules! neg_index {
($len: expr, $i: expr, $it: ty) => {{
let new_index = ($len as $it + $i);
if new_index < 0 {
panic!("Index out of range ({new_index})");
}
new_index as usize
}};
}
macro_rules! at_unsigned {
($e: ty) => {
impl<V> At<V, $e> for Vec<V> {
fn at(&self, c: $e) -> &V {
&self[c as usize]
}
fn at_mut(&mut self, c: $e) -> &mut V {
&mut self[c as usize]
}
}
}
}
macro_rules! at_signed {
($e: ty) => {
impl<V> At<V, $e> for Vec<V> {
fn at(&self, c: $e) -> &V {
if c < 0 {
&self[neg_index!(self.len(), c, $e)]
} else {
&self[c as usize]
}
}
fn at_mut(&mut self, c: $e) -> &mut V {
let l = self.len();
if c < 0 {
&mut self[neg_index!(l, c, $e)]
} else {
&mut self[c as usize]
}
}
}
}
}
at_unsigned!(u8);
at_unsigned!(u16);
at_unsigned!(u32);
at_unsigned!(u64);
at_unsigned!(u128);
at_signed!(i8);
at_signed!(i16);
at_signed!(i32);
at_signed!(i64);
at_signed!(i128);
at_signed!(isize);
#[test]
fn test_negative() {
let v: Vec<i32> = (1..=10).rev().collect();
for i in 1..=10 {
assert_eq!(i, *v.at(-i));
}
}
#[test]
fn test_positive() {
let v: Vec<i32> = (0..10).collect();
for i in 0..10 {
assert_eq!(i, *v.at(i));
}
}
#[test]
#[should_panic(expected = "Index out of range (-1)")]
fn test_negative_panic() {
let v: Vec<i32> = (0..2).collect();
v.at(-3);
}
#[test]
#[should_panic(expected = "index out of bounds: the len is 2 but the index is 3")]
fn test_positive_panic() {
let v: Vec<i32> = (0..2).collect();
v.at(3);
}