Skip to content

Commit 28d018a

Browse files
committed
use NonNull in place of *const
1 parent a410c67 commit 28d018a

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
}
@@ -548,7 +549,9 @@ impl<T, const N: usize> SmallVec<T, N> {
548549
let mut vec = ManuallyDrop::new(vec);
549550
let len = vec.len();
550551
let cap = vec.capacity();
551-
let ptr = vec.as_mut_ptr();
552+
// SAFETY: vec.capacity is not `0` (checked above), so the pointer
553+
// can not dangle and thus specifically cannot be null.
554+
let ptr = unsafe { NonNull::new_unchecked(vec.as_mut_ptr()) };
552555

553556
Self {
554557
len: TaggedLen::new(len, true, Self::is_zst()),
@@ -752,11 +755,10 @@ impl<T, const N: usize> SmallVec<T, N> {
752755
debug_assert!(self.spilled());
753756
let len = self.len();
754757
let (ptr, cap) = self.raw.heap;
755-
let ptr = ptr as *mut T;
756758
if len == cap {
757759
self.reserve(1);
758760
}
759-
ptr.add(len).write(value);
761+
ptr.as_ptr().add(len).write(value);
760762
self.set_len(len + 1)
761763
}
762764

@@ -826,9 +828,9 @@ impl<T, const N: usize> SmallVec<T, N> {
826828

827829
// SAFETY: len <= new_capacity <= Self::inline_size()
828830
// so the copy is within bounds of the inline member
829-
copy_nonoverlapping(ptr, self.raw.as_mut_ptr_inline(), len);
831+
copy_nonoverlapping(ptr.as_ptr(), self.raw.as_mut_ptr_inline(), len);
830832
drop(DropDealloc {
831-
ptr: NonNull::new_unchecked(ptr as *mut u8),
833+
ptr: NonNull::new_unchecked(ptr.as_ptr() as *mut u8),
832834
size_bytes: old_cap * size_of::<T>(),
833835
align: align_of::<T>(),
834836
});
@@ -904,10 +906,10 @@ impl<T, const N: usize> SmallVec<T, N> {
904906
unsafe {
905907
let (ptr, capacity) = self.raw.heap;
906908
self.raw = RawSmallVec::new_inline(MaybeUninit::uninit());
907-
copy_nonoverlapping(ptr, self.raw.as_mut_ptr_inline(), len);
909+
copy_nonoverlapping(ptr.as_ptr(), self.raw.as_mut_ptr_inline(), len);
908910
self.set_inline();
909911
alloc::alloc::dealloc(
910-
ptr as *mut T as *mut u8,
912+
ptr.as_ptr() as *mut u8,
911913
Layout::from_size_align_unchecked(capacity * size_of::<T>(), align_of::<T>()),
912914
);
913915
}
@@ -1083,10 +1085,16 @@ impl<T, const N: usize> SmallVec<T, N> {
10831085
vec
10841086
} else {
10851087
let this = ManuallyDrop::new(self);
1086-
// SAFETY: ptr was created with the global allocator
1088+
// SAFETY:
1089+
// - `ptr` was created with the global allocator
1090+
// - `ptr` was created with the appropriate alignment for `T`
1091+
// - the allocation pointed to by ptr is exactly cap * sizeof(T)
1092+
// - `len` is less than or equal to `cap`
1093+
// - the first `len` entries are proper `T`-values
1094+
// - the allocation is not larger than `isize::MAX`
10871095
unsafe {
10881096
let (ptr, cap) = this.raw.heap;
1089-
Vec::from_raw_parts(ptr as *mut T, len, cap)
1097+
Vec::from_raw_parts(ptr.as_ptr(), len, cap)
10901098
}
10911099
}
10921100
}
@@ -1260,6 +1268,14 @@ impl<T, const N: usize> SmallVec<T, N> {
12601268
#[inline]
12611269
pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> SmallVec<T, N> {
12621270
assert!(!Self::is_zst());
1271+
1272+
// SAFETY: We require caller to provide same ptr as we alloc
1273+
// and we never alloc null pointer.
1274+
let ptr = unsafe {
1275+
debug_assert!(!ptr.is_null(), "Called `from_raw_parts` with null pointer.");
1276+
NonNull::new_unchecked(ptr)
1277+
};
1278+
12631279
SmallVec {
12641280
len: TaggedLen::new(length, true, Self::is_zst()),
12651281
raw: RawSmallVec::new_heap(ptr, capacity),
@@ -1298,7 +1314,7 @@ impl<T, const N: usize> SmallVec<T, N> {
12981314
}
12991315
let len = self.len();
13001316
let (ptr, capacity) = self.raw.heap;
1301-
let ptr = ptr as *mut T;
1317+
let ptr = ptr.as_ptr();
13021318
// SAFETY: ptr is valid for `capacity - len` writes
13031319
let count = extend_batch(ptr, capacity - len, len, &mut iter);
13041320
self.set_len(len + count);

0 commit comments

Comments
 (0)