//! A growable datastructure with positive and negative indexing built on top of `std::vec::Vec` calculating the offset automatically.
//!
//!
//! ```
//! use shifted_vec::ShiftedVec;
//!
//! let mut v = ShiftedVec::with_offset_and_capacity(-2, 5);
//!
//! // populate the ShiftedVec
//! v.push(0);
//! v.push(1);
//! v.push(2);
//! v.push(3);
//! v.push(4);
//!
//! assert_eq!(5, v.len());
//!
//! assert_eq!(2, v[0]);
//!
//! // mutable access with index
//! v[0] = 5;
//!
//! assert_eq!(5, v[0]);
//! ```
use core::fmt::{self, Debug};
use core::ops::{Index, IndexMut};
/// Wrapping the `std::vec::Vec` that keeps track of the offset that can handle any Type
///
/// ```
/// # use shifted_vec::ShiftedVec;
/// let mut l: ShiftedVec<String> = ShiftedVec::with_offset(-2);
///
/// l.push("first".to_string());
/// l.push("second".to_string());
///
/// for (shifted, element) in l.iter_shifted() {
/// println!("{}: {}", shifted, element);
/// }
/// assert_eq!(2, l.len());
/// ```
pub struct ShiftedVec<T> {
data: Vec<T>,
offset: isize,
}
impl<T> ShiftedVec<T> {
/// Create a `ShiftedVec` backed by a `std::vec::Vec` with capacity 10
///
/// ```
/// # use shifted_vec::ShiftedVec;
/// let l: ShiftedVec<(usize, isize)> = ShiftedVec::with_offset(2);
/// ```
pub fn with_offset(offset: isize) -> ShiftedVec<T> {
Self::with_offset_and_capacity(offset, 10)
}
/// Create a `ShiftedVec`
///
/// ```
/// # use shifted_vec::ShiftedVec;
/// let mut l: ShiftedVec<(usize, isize)> = ShiftedVec::with_offset(2);
/// assert_eq!(0, l.len());
///
/// l.push((42, -42));
/// assert_eq!(1, l.len());
///
/// assert_eq!((42, -42), l[2]);
/// ```
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()
}
/// Append to the current list
///
/// ```
/// # use shifted_vec::ShiftedVec;
/// let l = {
/// let mut l = ShiftedVec::with_offset(2);
/// l.push((42, 42));
/// l
/// };
/// assert_eq!(1, l.len());
/// ```
pub fn push(&mut self, thing: T) {
self.data.push(thing)
}
/// Checked access to elements, see `get_mut`
pub fn get(&self, i: isize) -> Option<&T> {
let real = i + self.offset;
if real < 0 {
return None;
}
self.data.get(real as usize)
}
/// Checked writeable access to elements
///
/// ```
/// # use shifted_vec::ShiftedVec;
/// let mut l = ShiftedVec::with_offset(2);
///
/// l.push(42);
///
/// assert_eq!(None, l.get_mut(0));
/// assert_eq!(None, l.get_mut(1));
/// assert_eq!(Some(&mut 42), l.get_mut(2));
/// assert_eq!(None, l.get_mut(3));
///
/// match l.get_mut(2) {
/// Some(v) => *v = 64,
/// None => unreachable!("we made sure that we do not miss"),
/// }
///
/// assert_eq!(64, l[2]);
/// ```
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> {
/// Get an iterator
///
/// ```
/// # use shifted_vec::ShiftedVec;
/// let mut l = ShiftedVec::with_offset(-2);
/// let first = "first";
///
/// l.push(first);
///
/// let mut it = l.iter();
/// assert_eq!(Some(&first), it.next());
/// assert_eq!(None, it.next());
/// ```
pub fn iter(&self) -> std::slice::Iter<T> {
self.data.iter()
}
/// Get a mutable iterator
///
/// ```
/// # use shifted_vec::ShiftedVec;
/// let mut l = ShiftedVec::with_offset(-2);
/// let first = "first".to_string();
/// let second = "second".to_string();
///
/// l.push(first);
///
/// let mut it = l.iter_mut();
/// if let Some(val) = it.next() {
/// *val = second.clone();
/// }
/// assert_eq!(None, it.next());
///
/// assert_eq!(second, l[-2]);
/// ```
pub fn iter_mut(&mut self) -> std::slice::IterMut<T> {
self.data.iter_mut()
}
/// Get an iterator including the offset
///
/// ```
/// # use shifted_vec::ShiftedVec;
/// let mut l: ShiftedVec<String> = ShiftedVec::with_offset(-2);
///
/// l.push("first".to_string());
/// l.push("second".to_string());
///
/// let mut it = l.iter_shifted();
/// assert_eq!(Some((-2, &"first".to_string())), it.next());
/// assert_eq!(Some((-1, &"second".to_string())), it.next());
/// assert_eq!(None, it.next());
/// ```
pub fn iter_shifted(&self) -> ShiftedIterator<T> {
ShiftedIterator {
index: -self.offset,
backed: self,
}
}
/// Get a mutable iterator including the offset
///
/// ```
/// # use shifted_vec::ShiftedVec;
/// let mut l: ShiftedVec<String> = ShiftedVec::with_offset(-2);
///
/// l.push("first".to_string());
/// l.push("second".to_string());
///
/// for (offset, element) in l.iter_shifted_mut() {
/// println!("{}: {}", offset, element);
/// if offset == -2 {
/// *element = "replaced".to_string();
/// }
/// if offset == -1 {
/// element.push_str(" modified");
/// }
/// }
///
/// assert_eq!("replaced", l[-2]);
/// assert_eq!("second modified", l[-1]);
/// ```
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)),
}
}
}
/// See [`iter_shifted()`](struct.ShiftedVec.html#method.iter_shifted)
pub struct ShiftedIterator<'a, T> {
index: isize,
backed: &'a ShiftedVec<T>,
}
impl<'a, T> Iterator for ShiftedIterator<'a, T> {
type Item = (isize, &'a T);
// next() is the only required method
fn next(&mut self) -> Option<Self::Item> {
let r = self.backed.get(self.index).map(|thing| (self.index, thing));
self.index += 1;
r
}
}
/// See [`iter_shifted_mut()`](struct.ShiftedVec.html#method.iter_shifted_mut)
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);
// next() is the only required method
#[allow(mutable_transmutes)]
fn next(&mut self) -> Option<Self::Item> {
let index = self.index;
self.index += 1;
//let r: Option<Self::Item> =
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)
);
}
}