Non Empty Vector

In this exercise, you will implement a non-empty vector type. This type is a vector that is compile-time guaranteed to have at least one element. It can be useful when you want to ensure that a vector is never empty and avoid the overhead of checking for emptiness.

For example, a function can return a NonEmptyVec<T> instead of a Vec<T> to guarantee to its caller that the vector has at least one element. Or, a function can receive a NonEmptyVec<T> as an argument to force the caller to guarantee that the vector has at least one element.

To Do

  1. Implement the following methods for NonEmptyVec:

    • new: creates a new NonEmptyVec with a single element.
    • push: pushes an element to the end of the NonEmptyVec.
    • get: returns the element at the given index, if it exists.
    • first (last): returns the first (last) element of the NonEmptyVec. Unlike Vec::first, this method should not return an Option!
    • first_mut (last_mut): returns a mutable reference to the first (last) element of the NonEmptyVec.
    • pop: removes the last element from the NonEmptyVec and returns it, along with the remaining elements. Unlike Vec::pop, this method should not return an Option (pop should succeed even if there is a single element).

    Think carefully about the signature of these methods. For each input and output argument, consider whether it should be owned, borrowed, or mutably borrowed.

  2. Fill in the missing parts in the unit tests below (We didn't write the full tests for you to avoid spoiling the signatures).

    You can test your implementation by running cargo test.

#![allow(unused)]
fn main() {
pub struct NonEmptyVec<T> {
    head: T,
    tail: Vec<T>,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_new() {
        let x: NonEmptyVec<i32> = NonEmptyVec::new(5);
        todo!("assert that x.first() returns 5, and that x.last() also returns 5.");
    }

    #[test]
    fn test_push() {
        let mut x: NonEmptyVec<i32> = NonEmptyVec::new(5);
        x.push(10);
        todo!("assert that x.first() returns 5, and that x.last() returns 10.");
    }

    #[test]
    fn test_get() {
        let mut x: NonEmptyVec<i32> = NonEmptyVec::new(5);
        x.push(10);
        x.push(15);
        todo!("check the result of `x.get` for indices 0, 1, 2 and 3");
    }

    #[test]
    fn test_first_mut() {
        let mut x: NonEmptyVec<i32> = NonEmptyVec::new(5);
        todo!("use `x.first_mut()` to modify the first item, and then assert that `x.first()` returns the modified value.");
    }

    #[test]
    fn test_last_mut() {
        let mut x: NonEmptyVec<i32> = NonEmptyVec::new(5);
        x.push(10);
        todo!("use `x.last_mut()` to modify the last item, and then assert that `x.last()` returns the modified value.");
    }

    #[test]
    fn test_pop() {
        let mut x: NonEmptyVec<i32> = NonEmptyVec::new(5);
        x.push(10);
        x.push(15);
        todo!("call `x.pop()`, and verify that the popped item is 15, and the remaining values are 5 and 10.");
    }

    #[test]
    fn test_pop_single_item() {
        let x: NonEmptyVec<i32> = NonEmptyVec::new(5);
        todo!("call `x.pop()`, and verify that the popped item is 5, and that there are no remaining values.");
    }
}
}