diff --git a/Cargo.toml b/Cargo.toml index 4e48bbc..9d2c68a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,9 @@ default-features = false [dev-dependencies.serde_test] version = "1.0" +[dev-dependencies] +matches = { version = "0.1" } + [features] default = ["std"] std = ["odds/std", "nodrop/std"] diff --git a/src/lib.rs b/src/lib.rs index 4e593ad..4758e11 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -209,33 +209,54 @@ impl ArrayVec { /// Insert `element` in position `index`. /// - /// Shift up all elements after `index`. If any is pushed out, it is returned. + /// Shift up all elements after `index`. /// - /// Return `None` if no element is shifted out. + /// It is an error if the index is greater than the length or if the + /// arrayvec is full. /// - /// `index` must be <= `self.len()` and < `self.capacity()`. Note that any - /// out of bounds index insert results in the element being "shifted out" - /// and returned directly. + /// ***Panics*** on errors. See `try_result` for fallible version. /// /// ``` /// use arrayvec::ArrayVec; /// /// let mut array = ArrayVec::<[_; 2]>::new(); /// - /// assert_eq!(array.insert(0, "x"), None); - /// assert_eq!(array.insert(0, "y"), None); - /// assert_eq!(array.insert(0, "z"), Some("x")); - /// assert_eq!(array.insert(1, "w"), Some("y")); - /// assert_eq!(&array[..], &["z", "w"]); + /// array.insert(0, "x"); + /// array.insert(0, "y"); + /// assert_eq!(&array[..], &["y", "x"]); /// /// ``` - pub fn insert(&mut self, index: usize, element: A::Item) -> Option { - if index > self.len() || index == self.capacity() { - return Some(element); - } - let mut ret = None; + pub fn insert(&mut self, index: usize, element: A::Item) { + self.try_insert(index, element).unwrap() + } + + /// Insert `element` in position `index`. + /// + /// Shift up all elements after `index`. + /// + /// Returns an error if + /// + /// - The vector is at full capacity + /// - The index is out of bounds + /// + /// ``` + /// use arrayvec::ArrayVec; + /// + /// let mut array = ArrayVec::<[_; 2]>::new(); + /// + /// assert!(array.try_insert(0, "x").is_ok()); + /// assert!(array.try_insert(3, "w").is_err()); + /// assert!(array.try_insert(0, "y").is_ok()); + /// assert!(array.try_insert(0, "z").is_err()); + /// assert_eq!(&array[..], &["y", "x"]); + /// + /// ``` + pub fn try_insert(&mut self, index: usize, element: A::Item) -> Result<(), InsertError> { if self.len() == self.capacity() { - ret = self.pop(); + return Err(InsertError::Full(element)); + } + if index > self.len() { + return Err(InsertError::OutOfBounds); } let len = self.len(); @@ -253,7 +274,7 @@ impl ArrayVec { } self.set_len(len + 1); } - ret + Ok(()) } /// Remove the last element in the vector. @@ -308,23 +329,46 @@ impl ArrayVec { /// Remove the element at `index` and shift down the following elements. /// - /// Return `Some(` *element* `)` if the index is in bounds, else `None`. + /// ***Panics*** if the `index` is greater or equal to the length of the + /// vector. /// /// ``` /// use arrayvec::ArrayVec; /// /// let mut array = ArrayVec::from([1, 2, 3]); /// - /// assert_eq!(array.remove(0), Some(1)); + /// let removed_elt = array.remove(0); + /// assert_eq!(removed_elt, 1); + /// assert_eq!(&array[..], &[2, 3]); + /// ``` + pub fn remove(&mut self, index: usize) -> A::Item { + self.try_remove(index).unwrap() + } + + /// Remove the element at `index` and shift down the following elements. + /// + /// Returns an error if: + /// + /// - The index is greater or equal to the length of the vector + /// + /// Else return the element inside `Ok`. + /// + /// ``` + /// use arrayvec::ArrayVec; + /// + /// let mut array = ArrayVec::from([1, 2, 3]); + /// + /// assert!(array.try_remove(0).is_ok()); /// assert_eq!(&array[..], &[2, 3]); /// - /// assert_eq!(array.remove(10), None); + /// assert!(array.try_remove(2).is_err()); + /// assert!(array.try_remove(10).is_err()); /// ``` - pub fn remove(&mut self, index: usize) -> Option { + pub fn try_remove(&mut self, index: usize) -> Result { if index >= self.len() { - None + Err(RemoveError::new()) } else { - self.drain(index..index + 1).next() + self.drain(index..index + 1).next().ok_or_else(|| panic!()) } } @@ -945,3 +989,37 @@ impl fmt::Debug for CapacityError { write!(f, "{}: {}", "CapacityError", CAPERROR) } } + +pub enum InsertError { + Full(T), + OutOfBounds, +} + +impl InsertError { + fn description(&self) -> &'static str { + match *self { + InsertError::Full(_) => "ArrayVec is already at full capacity", + InsertError::OutOfBounds => "index is out of bounds", + } + } +} + +impl fmt::Debug for InsertError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + InsertError::Full(_) => write!(f, "InsertError::Full: ")?, + InsertError::OutOfBounds => write!(f, "InsertError::OutOfBounds: ")?, + } + write!(f, "{}", self.description()) + } +} + +#[derive(Debug)] +pub struct RemoveError { +} + +impl RemoveError { + pub fn new() -> Self { + RemoveError { } + } +} diff --git a/tests/tests.rs b/tests/tests.rs index f2dede2..3a4e5f7 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1,4 +1,5 @@ extern crate arrayvec; +#[macro_use] extern crate matches; use arrayvec::ArrayVec; use arrayvec::ArrayString; @@ -218,20 +219,23 @@ fn test_drop_panic_into_iter() { fn test_insert() { let mut v = ArrayVec::from([]); assert_eq!(v.push(1), Some(1)); - assert_eq!(v.insert(0, 1), Some(1)); + assert_matches!(v.try_insert(0, 1), Err(_)); let mut v = ArrayVec::<[_; 3]>::new(); v.insert(0, 0); v.insert(1, 1); v.insert(2, 2); - v.insert(3, 3); + let ret1 = v.try_insert(3, 3); assert_eq!(&v[..], &[0, 1, 2]); - v.insert(1, 9); - assert_eq!(&v[..], &[0, 9, 1]); + assert_matches!(ret1, Err(_)); + + let ret2 = v.try_insert(1, 9); + assert_eq!(&v[..], &[0, 1, 2]); + assert_matches!(ret2, Err(_)); let mut v = ArrayVec::from([2]); - assert_eq!(v.insert(1, 1), Some(1)); - assert_eq!(v.insert(2, 1), Some(1)); + assert_matches!(v.try_insert(1, 1), Err(_)); + assert_matches!(v.try_insert(2, 1), Err(_)); } #[test] @@ -372,28 +376,32 @@ fn test_string_push() { #[test] fn test_insert_at_length() { let mut v = ArrayVec::<[_; 8]>::new(); - let result1 = v.insert(0, "a"); - let result2 = v.insert(1, "b"); - assert!(result1.is_none() && result2.is_none()); + let result1 = v.try_insert(0, "a"); + let result2 = v.try_insert(1, "b"); + assert!(result1.is_ok() && result2.is_ok()); assert_eq!(&v[..], &["a", "b"]); } #[test] fn test_insert_out_of_bounds() { let mut v = ArrayVec::<[_; 8]>::new(); - let result = v.insert(1, "test"); - assert_eq!(result, Some("test")); + let result = v.try_insert(1, "test"); + assert_matches!(result, Err(_)); assert_eq!(v.len(), 0); - let mut u = ArrayVec::from([1, 2, 3, 4]); - let ret = u.insert(3, 99); - assert_eq!(&u[..], &[1, 2, 3, 99]); - assert_eq!(ret, Some(4)); - let ret = u.insert(4, 77); - assert_eq!(&u[..], &[1, 2, 3, 99]); - assert_eq!(ret, Some(77)); } +/* + * insert that pushes out the last + let mut u = ArrayVec::from([1, 2, 3, 4]); + let ret = u.try_insert(3, 99); + assert_eq!(&u[..], &[1, 2, 3, 99]); + assert_matches!(ret, Err(_)); + let ret = u.try_insert(4, 77); + assert_eq!(&u[..], &[1, 2, 3, 99]); + assert_matches!(ret, Err(_)); +*/ + #[test] fn test_drop_in_insert() { use std::cell::Cell; @@ -416,9 +424,9 @@ fn test_drop_in_insert() { array.push(Bump(flag)); array.insert(0, Bump(flag)); assert_eq!(flag.get(), 0); - let ret = array.insert(1, Bump(flag)); + let ret = array.try_insert(1, Bump(flag)); assert_eq!(flag.get(), 0); - assert!(ret.is_some()); + assert_matches!(ret, Err(_)); drop(ret); assert_eq!(flag.get(), 1); }