use core::fmt::{self, Debug};
use core::ops::{Index, IndexMut};
pub struct ShiftedVec<T> {
data: Vec<T>,
offset: isize,
}
impl<T> ShiftedVec<T> {
pub fn with_offset(offset: isize) -> ShiftedVec<T> {
Self::with_offset_and_capacity(offset, 10)
}
pub fn with_offset_and_capacity(offset: isize, capacity: usize) -> ShiftedVec<T> {
ShiftedVec {
data: Vec::with_capacity(capacity),
offset: -offset,
}
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn push(&mut self, thing: T) {
self.data.push(thing)
}
pub fn get(&self, i: isize) -> Option<&T> {
let real = i + self.offset;
if real < 0 {
return None;
}
self.data.get(real as usize)
}
pub fn get_mut(&mut self, i: isize) -> Option<&mut T> {
let real = i + self.offset;
if real < 0 {
return None;
}
self.data.get_mut(real as usize)
}
}
impl<'a, T> ShiftedVec<T> {
pub fn iter(&self) -> std::slice::Iter<T> {
self.data.iter()
}
pub fn iter_mut(&mut self) -> std::slice::IterMut<T> {
self.data.iter_mut()
}
pub fn iter_shifted(&self) -> ShiftedIterator<T> {
ShiftedIterator {
index: -self.offset,
backed: self,
}
}
pub fn iter_shifted_mut(&mut self) -> ShiftedIteratorMut<T> {
ShiftedIteratorMut {
index: -self.offset,
backed: self,
}
}
}
impl<T: Debug> Debug for ShiftedVec<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("ShiftedVec")
.field("offset", &self.offset)
.field("data", &self.data)
.finish()
}
}
impl<T> Index<isize> for ShiftedVec<T> {
type Output = T;
fn index(&self, i: isize) -> &Self::Output {
match self.get(i) {
Some(thing) => thing,
None => panic!(format!("out of bounds access {}", i)),
}
}
}
impl<T> IndexMut<isize> for ShiftedVec<T> {
fn index_mut(&mut self, i: isize) -> &mut Self::Output {
match self.get_mut(i) {
Some(thing) => thing,
None => panic!(format!("out of bounds access {}", i)),
}
}
}
pub struct ShiftedIterator<'a, T> {
index: isize,
backed: &'a ShiftedVec<T>,
}
impl<'a, T> Iterator for ShiftedIterator<'a, T> {
type Item = (isize, &'a T);
fn next(&mut self) -> Option<Self::Item> {
let r = self.backed.get(self.index).map(|thing| (self.index, thing));
self.index += 1;
r
}
}
pub struct ShiftedIteratorMut<'a, T> {
index: isize,
backed: &'a mut ShiftedVec<T>,
}
impl<'a, T> Iterator for ShiftedIteratorMut<'a, T> {
type Item = (isize, &'a mut T);
#[allow(mutable_transmutes)]
fn next(&mut self) -> Option<Self::Item> {
let index = self.index;
self.index += 1;
self.backed.get_mut(index).map(|thing: &mut T| {
let ptr: *mut T = thing as *mut T;
let thing2: &'a mut T = unsafe { std::mem::transmute(ptr) };
(index, thing2)
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn normal() {
let mut v = ShiftedVec::with_offset(0);
v.push(0);
v.push(1);
v.push(2);
v.push(3);
assert_eq!(0, v[0]);
assert_eq!(1, v[1]);
assert_eq!(2, v[2]);
assert_eq!(3, v[3]);
}
#[test]
fn positive_shift() {
let mut v = ShiftedVec::with_offset(10);
v.push(0);
v.push(1);
v.push(2);
v.push(3);
assert_eq!(0, v[10]);
assert_eq!(1, v[11]);
assert_eq!(2, v[12]);
assert_eq!(3, v[13]);
}
#[test]
fn negative_shift() {
let mut v = ShiftedVec::with_offset(-10);
v.push(0);
v.push(1);
v.push(2);
v.push(3);
assert_eq!(0, v[-10]);
assert_eq!(1, v[-9]);
assert_eq!(2, v[-8]);
assert_eq!(3, v[-7]);
}
#[test]
fn half_shift() {
let mut v = ShiftedVec::with_offset(-2);
v.push(0);
v.push(1);
v.push(2);
v.push(3);
v.push(4);
assert_eq!(0, v[-2]);
assert_eq!(1, v[-1]);
assert_eq!(2, v[0]);
assert_eq!(3, v[1]);
assert_eq!(4, v[2]);
}
#[test]
fn half_shift_mut() {
let mut v = ShiftedVec::with_offset(-2);
v.push(0);
v.push(1);
v.push(2);
v.push(3);
v.push(4);
v[0] = 5;
assert_eq!(0, v[-2]);
assert_eq!(1, v[-1]);
assert_eq!(5, v[0]);
assert_eq!(3, v[1]);
assert_eq!(4, v[2]);
}
#[test]
fn out_of_bounds() {
let v: ShiftedVec<(usize, usize)> = ShiftedVec::with_offset(-2);
assert_eq!(None, v.get(0));
}
#[test]
fn out_of_bounds_mut() {
let mut v = ShiftedVec::with_offset(-2);
v.push(0usize);
assert_eq!(None, v.get_mut(0));
}
#[test]
#[should_panic]
fn out_of_bounds_panic() {
let v: ShiftedVec<(usize, usize)> = ShiftedVec::with_offset(-2);
v[0];
}
#[test]
#[should_panic]
fn out_of_bounds_panic_mut() {
let mut v = ShiftedVec::with_offset(-2);
v.push(0usize);
v[0] = 13;
}
#[test]
fn display() {
let mut v = ShiftedVec::with_offset(-2);
v.push(0usize);
assert_eq!("0", format!("{}", v[-2]));
}
#[test]
fn debug() {
let mut v = ShiftedVec::with_offset(-2);
v.push(0usize);
assert_eq!("ShiftedVec { offset: 2, data: [0] }", format!("{:?}", v));
}
#[test]
fn debug_pretty() {
let mut v = ShiftedVec::with_offset(-2);
v.push(0usize);
println!("{:#?}", v);
assert_eq!(
"ShiftedVec {\n offset: 2,\n data: [\n 0,\n ],\n}",
format!("{:#?}", v)
);
}
}