Skip to content

Commit 54bc182

Browse files
committed
Make from_elem panic-safe
Fixes #101
1 parent 21b02fa commit 54bc182

File tree

1 file changed

+32
-7
lines changed

1 file changed

+32
-7
lines changed

lib.rs

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -944,19 +944,17 @@ impl<A: Array> SmallVec<A> where A::Item: Clone {
944944
if n > A::size() {
945945
vec![elem; n].into()
946946
} else {
947+
let mut v = SmallVec::<A>::new();
947948
unsafe {
948-
let mut arr: A = ::std::mem::uninitialized();
949-
let ptr = arr.ptr_mut();
949+
let (ptr, len_ptr, _) = v.triple_mut();
950+
let mut local_len = SetLenOnDrop::new(len_ptr);
950951

951952
for i in 0..n as isize {
952953
::std::ptr::write(ptr.offset(i), elem.clone());
953-
}
954-
955-
SmallVec {
956-
capacity: n,
957-
data: SmallVecData::from_inline(arr),
954+
local_len.increment_len(1);
958955
}
959956
}
957+
v
960958
}
961959
}
962960
}
@@ -1344,6 +1342,33 @@ pub unsafe trait Array {
13441342
fn ptr_mut(&mut self) -> *mut Self::Item;
13451343
}
13461344

1345+
/// Set the length of the vec when the `SetLenOnDrop` value goes out of scope.
1346+
///
1347+
/// Copied from https://github.com/rust-lang/rust/pull/36355
1348+
struct SetLenOnDrop<'a> {
1349+
len: &'a mut usize,
1350+
local_len: usize,
1351+
}
1352+
1353+
impl<'a> SetLenOnDrop<'a> {
1354+
#[inline]
1355+
fn new(len: &'a mut usize) -> Self {
1356+
SetLenOnDrop { local_len: *len, len: len }
1357+
}
1358+
1359+
#[inline]
1360+
fn increment_len(&mut self, increment: usize) {
1361+
self.local_len += increment;
1362+
}
1363+
}
1364+
1365+
impl<'a> Drop for SetLenOnDrop<'a> {
1366+
#[inline]
1367+
fn drop(&mut self) {
1368+
*self.len = self.local_len;
1369+
}
1370+
}
1371+
13471372
macro_rules! impl_array(
13481373
($($size:expr),+) => {
13491374
$(

0 commit comments

Comments
 (0)