diff --git a/src/lib.rs b/src/lib.rs index 50903c5..75860dd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -462,12 +462,18 @@ impl ArrayVec { /// assert_eq!(&array[..], &[1, 2, 3]); /// ``` pub fn truncate(&mut self, len: usize) { - while self.len() > len { self.pop(); } + unsafe { + if len < self.len() { + let tail: *mut [_] = &mut self[len..]; + self.set_len(len); + ptr::drop_in_place(tail); + } + } } /// Remove all elements in the vector. pub fn clear(&mut self) { - while let Some(_) = self.pop() { } + self.truncate(0) } /// Retains only the elements specified by the predicate. @@ -540,7 +546,7 @@ impl ArrayVec { // Memory safety // // When the Drain is first created, it shortens the length of - // the source vector to make sure no uninitalized or moved-from elements + // the source vector to make sure no uninitialized or moved-from elements // are accessible at all if the Drain's destructor never gets to run. // // Drain will ptr::read out the values to remove. diff --git a/tests/tests.rs b/tests/tests.rs index eaca12c..bb7fe8a 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -126,6 +126,80 @@ fn test_drop() { } } +#[test] +fn test_drop_panics() { + use std::cell::Cell; + use std::panic::catch_unwind; + use std::panic::AssertUnwindSafe; + + let flag = &Cell::new(0); + + struct Bump<'a>(&'a Cell); + + // Panic in the first drop + impl<'a> Drop for Bump<'a> { + fn drop(&mut self) { + let n = self.0.get(); + self.0.set(n + 1); + if n == 0 { + panic!("Panic in Bump's drop"); + } + } + } + // check if rust is new enough + flag.set(0); + { + let array = vec![Bump(flag), Bump(flag)]; + let res = catch_unwind(AssertUnwindSafe(|| { + drop(array); + })); + assert!(res.is_err()); + } + + if flag.get() != 2 { + println!("test_drop_panics: skip, this version of Rust doesn't continue in drop_in_place"); + return; + } + + flag.set(0); + { + let mut array = ArrayVec::<[Bump; 128]>::new(); + array.push(Bump(flag)); + array.push(Bump(flag)); + array.push(Bump(flag)); + + let res = catch_unwind(AssertUnwindSafe(|| { + drop(array); + })); + assert!(res.is_err()); + } + // Check that all the elements drop, even if the first drop panics. + assert_eq!(flag.get(), 3); + + + flag.set(0); + { + let mut array = ArrayVec::<[Bump; 16]>::new(); + array.push(Bump(flag)); + array.push(Bump(flag)); + array.push(Bump(flag)); + array.push(Bump(flag)); + array.push(Bump(flag)); + + let i = 2; + let tail_len = array.len() - i; + + let res = catch_unwind(AssertUnwindSafe(|| { + array.truncate(i); + })); + assert!(res.is_err()); + // Check that all the tail elements drop, even if the first drop panics. + assert_eq!(flag.get(), tail_len as i32); + } + + +} + #[test] fn test_extend() { let mut range = 0..10;