/// [`drain`]: #method.drain
#[stable(feature = "rust1", since = "1.0.0")]
pub fn truncate(&mut self, len: usize) {
- if mem::needs_drop::<T>() {
- let current_len = self.len;
- unsafe {
- let mut ptr = self.as_mut_ptr().add(self.len);
- // Set the final length at the end, keeping in mind that
- // dropping an element might panic. Works around a missed
- // optimization, as seen in the following issue:
- // https://github.com/rust-lang/rust/issues/51802
- let mut local_len = SetLenOnDrop::new(&mut self.len);
-
- // drop any extra elements
- for _ in len..current_len {
- local_len.decrement_len(1);
- ptr = ptr.offset(-1);
- ptr::drop_in_place(ptr);
- }
+ // This is safe because:
+ //
+ // * the slice passed to `drop_in_place` is valid; the `len > self.len`
+ // case avoids creating an invalid slice, and
+ // * the `len` of the vector is shrunk before calling `drop_in_place`,
+ // such that no value will be dropped twice in case `drop_in_place`
+ // were to panic once (if it panics twice, the program aborts).
+ unsafe {
+ if len > self.len {
+ return;
}
- } else if len <= self.len {
+ let s = self.get_unchecked_mut(len..) as *mut _;
self.len = len;
+ ptr::drop_in_place(s);
}
}
fn increment_len(&mut self, increment: usize) {
self.local_len += increment;
}
-
- #[inline]
- fn decrement_len(&mut self, decrement: usize) {
- self.local_len -= decrement;
- }
}
impl Drop for SetLenOnDrop<'_> {