Skip to content

Commit 233df73

Browse files
authored
Merge pull request #98 from bluss/use-drop-in-place
Use drop_in_place for truncate and clear (and drop)
2 parents e80446c + ac61ce7 commit 233df73

File tree

2 files changed

+83
-3
lines changed

2 files changed

+83
-3
lines changed

src/lib.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -462,12 +462,18 @@ impl<A: Array> ArrayVec<A> {
462462
/// assert_eq!(&array[..], &[1, 2, 3]);
463463
/// ```
464464
pub fn truncate(&mut self, len: usize) {
465-
while self.len() > len { self.pop(); }
465+
unsafe {
466+
if len < self.len() {
467+
let tail: *mut [_] = &mut self[len..];
468+
self.set_len(len);
469+
ptr::drop_in_place(tail);
470+
}
471+
}
466472
}
467473

468474
/// Remove all elements in the vector.
469475
pub fn clear(&mut self) {
470-
while let Some(_) = self.pop() { }
476+
self.truncate(0)
471477
}
472478

473479
/// Retains only the elements specified by the predicate.
@@ -540,7 +546,7 @@ impl<A: Array> ArrayVec<A> {
540546
// Memory safety
541547
//
542548
// When the Drain is first created, it shortens the length of
543-
// the source vector to make sure no uninitalized or moved-from elements
549+
// the source vector to make sure no uninitialized or moved-from elements
544550
// are accessible at all if the Drain's destructor never gets to run.
545551
//
546552
// Drain will ptr::read out the values to remove.

tests/tests.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,80 @@ fn test_drop() {
126126
}
127127
}
128128

129+
#[test]
130+
fn test_drop_panics() {
131+
use std::cell::Cell;
132+
use std::panic::catch_unwind;
133+
use std::panic::AssertUnwindSafe;
134+
135+
let flag = &Cell::new(0);
136+
137+
struct Bump<'a>(&'a Cell<i32>);
138+
139+
// Panic in the first drop
140+
impl<'a> Drop for Bump<'a> {
141+
fn drop(&mut self) {
142+
let n = self.0.get();
143+
self.0.set(n + 1);
144+
if n == 0 {
145+
panic!("Panic in Bump's drop");
146+
}
147+
}
148+
}
149+
// check if rust is new enough
150+
flag.set(0);
151+
{
152+
let array = vec![Bump(flag), Bump(flag)];
153+
let res = catch_unwind(AssertUnwindSafe(|| {
154+
drop(array);
155+
}));
156+
assert!(res.is_err());
157+
}
158+
159+
if flag.get() != 2 {
160+
println!("test_drop_panics: skip, this version of Rust doesn't continue in drop_in_place");
161+
return;
162+
}
163+
164+
flag.set(0);
165+
{
166+
let mut array = ArrayVec::<[Bump; 128]>::new();
167+
array.push(Bump(flag));
168+
array.push(Bump(flag));
169+
array.push(Bump(flag));
170+
171+
let res = catch_unwind(AssertUnwindSafe(|| {
172+
drop(array);
173+
}));
174+
assert!(res.is_err());
175+
}
176+
// Check that all the elements drop, even if the first drop panics.
177+
assert_eq!(flag.get(), 3);
178+
179+
180+
flag.set(0);
181+
{
182+
let mut array = ArrayVec::<[Bump; 16]>::new();
183+
array.push(Bump(flag));
184+
array.push(Bump(flag));
185+
array.push(Bump(flag));
186+
array.push(Bump(flag));
187+
array.push(Bump(flag));
188+
189+
let i = 2;
190+
let tail_len = array.len() - i;
191+
192+
let res = catch_unwind(AssertUnwindSafe(|| {
193+
array.truncate(i);
194+
}));
195+
assert!(res.is_err());
196+
// Check that all the tail elements drop, even if the first drop panics.
197+
assert_eq!(flag.get(), tail_len as i32);
198+
}
199+
200+
201+
}
202+
129203
#[test]
130204
fn test_extend() {
131205
let mut range = 0..10;

0 commit comments

Comments
 (0)