shifted_vec 0.1.2

A growable datastructure with positive and negative indexing built on top of `std::vec::Vec` calculating the offset automatically.
Documentation
//! 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)
        );
    }
}