Skip to content

Commit 43e678e

Browse files
authored
Use NonNull in place of *const (v2) (#334)
* use NonNull in place of *const * use NonNull::cast instead of as where possible
1 parent 6f6637e commit 43e678e

File tree

1 file changed

+33
-17
lines changed

1 file changed

+33
-17
lines changed

src/lib.rs

+33-17
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,13 @@ impl core::fmt::Display for CollectionAllocErr {
109109
/// Either a stack array with `length <= N` or a heap array
110110
/// whose pointer and capacity are stored here.
111111
///
112-
/// We store a `*const T` instead of a `*mut T` so that the type is covariant
112+
/// We store a `NonNull<T>` instead of a `*mut T`, so that
113+
/// niche-optimization can be performed and the type is covariant
113114
/// with respect to `T`.
114115
#[repr(C)]
115116
pub union RawSmallVec<T, const N: usize> {
116117
inline: ManuallyDrop<MaybeUninit<[T; N]>>,
117-
heap: (*const T, usize), // this pointer is never null
118+
heap: (NonNull<T>, usize),
118119
}
119120

120121
#[inline]
@@ -143,7 +144,7 @@ impl<T, const N: usize> RawSmallVec<T, N> {
143144
}
144145
}
145146
#[inline]
146-
const fn new_heap(ptr: *mut T, capacity: usize) -> Self {
147+
const fn new_heap(ptr: NonNull<T>, capacity: usize) -> Self {
147148
Self {
148149
heap: (ptr, capacity),
149150
}
@@ -168,15 +169,15 @@ impl<T, const N: usize> RawSmallVec<T, N> {
168169
/// The vector must be on the heap
169170
#[inline]
170171
const unsafe fn as_ptr_heap(&self) -> *const T {
171-
self.heap.0
172+
self.heap.0.as_ptr()
172173
}
173174

174175
/// # Safety
175176
///
176177
/// The vector must be on the heap
177178
#[inline]
178179
unsafe fn as_mut_ptr_heap(&mut self) -> *mut T {
179-
self.heap.0 as *mut T
180+
self.heap.0.as_ptr()
180181
}
181182

182183
/// # Safety
@@ -216,7 +217,7 @@ impl<T, const N: usize> RawSmallVec<T, N> {
216217
Err(CollectionAllocErr::AllocErr { layout: new_layout })
217218
} else {
218219
copy_nonoverlapping(ptr, new_ptr, len);
219-
*self = Self::new_heap(new_ptr, new_capacity);
220+
*self = Self::new_heap(NonNull::new_unchecked(new_ptr), new_capacity);
220221
Ok(())
221222
}
222223
} else {
@@ -236,7 +237,7 @@ impl<T, const N: usize> RawSmallVec<T, N> {
236237
if new_ptr.is_null() {
237238
Err(CollectionAllocErr::AllocErr { layout: new_layout })
238239
} else {
239-
*self = Self::new_heap(new_ptr, new_capacity);
240+
*self = Self::new_heap(NonNull::new_unchecked(new_ptr), new_capacity);
240241
Ok(())
241242
}
242243
}
@@ -733,7 +734,9 @@ impl<T, const N: usize> SmallVec<T, N> {
733734
let mut vec = ManuallyDrop::new(vec);
734735
let len = vec.len();
735736
let cap = vec.capacity();
736-
let ptr = vec.as_mut_ptr();
737+
// SAFETY: vec.capacity is not `0` (checked above), so the pointer
738+
// can not dangle and thus specifically cannot be null.
739+
let ptr = unsafe { NonNull::new_unchecked(vec.as_mut_ptr()) };
737740

738741
Self {
739742
len: TaggedLen::new(len, true, Self::is_zst()),
@@ -1002,11 +1005,10 @@ impl<T, const N: usize> SmallVec<T, N> {
10021005
debug_assert!(self.spilled());
10031006
let len = self.len();
10041007
let (ptr, cap) = self.raw.heap;
1005-
let ptr = ptr as *mut T;
10061008
if len == cap {
10071009
self.reserve(1);
10081010
}
1009-
ptr.add(len).write(value);
1011+
ptr.as_ptr().add(len).write(value);
10101012
self.set_len(len + 1)
10111013
}
10121014

@@ -1076,9 +1078,9 @@ impl<T, const N: usize> SmallVec<T, N> {
10761078

10771079
// SAFETY: len <= new_capacity <= Self::inline_size()
10781080
// so the copy is within bounds of the inline member
1079-
copy_nonoverlapping(ptr, self.raw.as_mut_ptr_inline(), len);
1081+
copy_nonoverlapping(ptr.as_ptr(), self.raw.as_mut_ptr_inline(), len);
10801082
drop(DropDealloc {
1081-
ptr: NonNull::new_unchecked(ptr as *mut u8),
1083+
ptr: NonNull::new_unchecked(ptr.cast().as_ptr()),
10821084
size_bytes: old_cap * size_of::<T>(),
10831085
align: align_of::<T>(),
10841086
});
@@ -1154,10 +1156,10 @@ impl<T, const N: usize> SmallVec<T, N> {
11541156
unsafe {
11551157
let (ptr, capacity) = self.raw.heap;
11561158
self.raw = RawSmallVec::new_inline(MaybeUninit::uninit());
1157-
copy_nonoverlapping(ptr, self.raw.as_mut_ptr_inline(), len);
1159+
copy_nonoverlapping(ptr.as_ptr(), self.raw.as_mut_ptr_inline(), len);
11581160
self.set_inline();
11591161
alloc::alloc::dealloc(
1160-
ptr as *mut T as *mut u8,
1162+
ptr.cast().as_ptr(),
11611163
Layout::from_size_align_unchecked(capacity * size_of::<T>(), align_of::<T>()),
11621164
);
11631165
}
@@ -1333,10 +1335,16 @@ impl<T, const N: usize> SmallVec<T, N> {
13331335
vec
13341336
} else {
13351337
let this = ManuallyDrop::new(self);
1336-
// SAFETY: ptr was created with the global allocator
1338+
// SAFETY:
1339+
// - `ptr` was created with the global allocator
1340+
// - `ptr` was created with the appropriate alignment for `T`
1341+
// - the allocation pointed to by ptr is exactly cap * sizeof(T)
1342+
// - `len` is less than or equal to `cap`
1343+
// - the first `len` entries are proper `T`-values
1344+
// - the allocation is not larger than `isize::MAX`
13371345
unsafe {
13381346
let (ptr, cap) = this.raw.heap;
1339-
Vec::from_raw_parts(ptr as *mut T, len, cap)
1347+
Vec::from_raw_parts(ptr.as_ptr(), len, cap)
13401348
}
13411349
}
13421350
}
@@ -1510,6 +1518,14 @@ impl<T, const N: usize> SmallVec<T, N> {
15101518
#[inline]
15111519
pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> SmallVec<T, N> {
15121520
assert!(!Self::is_zst());
1521+
1522+
// SAFETY: We require caller to provide same ptr as we alloc
1523+
// and we never alloc null pointer.
1524+
let ptr = unsafe {
1525+
debug_assert!(!ptr.is_null(), "Called `from_raw_parts` with null pointer.");
1526+
NonNull::new_unchecked(ptr)
1527+
};
1528+
15131529
SmallVec {
15141530
len: TaggedLen::new(length, true, Self::is_zst()),
15151531
raw: RawSmallVec::new_heap(ptr, capacity),
@@ -1548,7 +1564,7 @@ impl<T, const N: usize> SmallVec<T, N> {
15481564
}
15491565
let len = self.len();
15501566
let (ptr, capacity) = self.raw.heap;
1551-
let ptr = ptr as *mut T;
1567+
let ptr = ptr.as_ptr();
15521568
// SAFETY: ptr is valid for `capacity - len` writes
15531569
let count = extend_batch(ptr, capacity - len, len, &mut iter);
15541570
self.set_len(len + count);

0 commit comments

Comments
 (0)