Skip to content

Commit edde578

Browse files
committed
Wrap Box in mem::ManuallyDrop instead of Option
We need a way to get a raw pointer to the Box's content within Drop::drop(&mut self) but since we only have a mutable reference to self, the Box needs to be wrapped in something that provides take(). So far we have used Option for that. Instead, use mem::ManuallyDrop which is a zero-cost abstraction and semantically better fits our use case. See #2
1 parent bf72595 commit edde578

File tree

1 file changed

+11
-17
lines changed

1 file changed

+11
-17
lines changed

src/lib.rs

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,36 +31,31 @@ impl std::fmt::Display for AlignedBoxError {
3131
/// `AlignedBox<T>` consists of a `Box<T>` and the `std::alloc::Layout` that has been used to
3232
/// allocate the referenced memory.
3333
pub struct AlignedBox<T: ?Sized> {
34-
// container is not a Box<T> but an Option<Box<T>> for purely technical reasons:
35-
// When drop(&mut self) is called, we need to be able to get the raw pointer from the Box.
36-
// Therefore we need to be able to take ownership of the Box. Option::take() allows that.
37-
// The Option is Some as long as the AlignedBox exist. It is only set to None during drop()
38-
// and into_raw_parts(). In both cases, the AlignedBox is destroyed directly afterwards.
39-
container: std::option::Option<std::boxed::Box<T>>,
34+
container: std::mem::ManuallyDrop<std::boxed::Box<T>>,
4035
layout: std::alloc::Layout,
4136
}
4237

4338
impl<T: ?Sized> std::ops::Deref for AlignedBox<T> {
4439
type Target = T;
4540

4641
fn deref(&self) -> &T {
47-
// self.container is always Some, so we can just unwrap
48-
self.container.as_deref().unwrap()
42+
&self.container
4943
}
5044
}
5145

5246
impl<T: ?Sized> std::ops::DerefMut for AlignedBox<T> {
5347
fn deref_mut(&mut self) -> &mut T {
54-
// self.container is always Some, so we can just unwrap
55-
self.container.as_deref_mut().unwrap()
48+
&mut self.container
5649
}
5750
}
5851

5952
impl<T: ?Sized> Drop for AlignedBox<T> {
6053
fn drop(&mut self) {
61-
// self.container is always Some, so we can just unwrap
62-
let container = self.container.take().unwrap();
54+
// SAFETY:
55+
// * self.container is not used after taking the Box out of it
56+
// * dealloc is called with layout that has been used for allocation earlier
6357
unsafe {
58+
let container = std::mem::ManuallyDrop::take(&mut self.container);
6459
std::alloc::dealloc(std::boxed::Box::into_raw(container) as *mut u8, self.layout);
6560
}
6661
}
@@ -80,10 +75,9 @@ impl<T: Clone + ?Sized> Clone for AlignedBox<T> {
8075

8176
// *b is not a valid instance of T but uninitialized memory. We have to write to it without
8277
// dropping the old (invalid) value. Also the original value must not be dropped.
83-
// self.container is always Some, so we can just unwrap.
8478
// SAFETY: *b points to valid and properly aligned memory and clone() also provides us with
8579
// a valid value.
86-
unsafe { std::ptr::write(&mut *b, (*self.container.as_deref().unwrap()).clone()) };
80+
unsafe { std::ptr::write(&mut *b, (**self.container).clone()) };
8781

8882
b
8983
}
@@ -95,8 +89,8 @@ impl<T: ?Sized> AlignedBox<T> {
9589
/// behind the pointer. This can for example be done by reconstructing the `AlignedBox` using
9690
/// `AlignedBox::from_raw_parts`.
9791
pub fn into_raw_parts(mut from: AlignedBox<T>) -> (*mut T, std::alloc::Layout) {
98-
// self.container is always Some, so we can just unwrap
99-
let container = from.container.take().unwrap();
92+
// SAFETY: from.container is not used anymore afterwards
93+
let container = unsafe { std::mem::ManuallyDrop::take(&mut from.container) };
10094
let ptr = std::boxed::Box::into_raw(container);
10195
let layout = from.layout;
10296
std::mem::forget(from); // AlignedBox::drop() must not be called
@@ -114,7 +108,7 @@ impl<T: ?Sized> AlignedBox<T> {
114108
/// behavior is undefined if the given layout does not correspond to the one used for
115109
/// allocation.
116110
pub unsafe fn from_raw_parts(ptr: *mut T, layout: std::alloc::Layout) -> AlignedBox<T> {
117-
let container = Some(std::boxed::Box::from_raw(ptr));
111+
let container = std::mem::ManuallyDrop::new(std::boxed::Box::from_raw(ptr));
118112
AlignedBox::<T> { container, layout }
119113
}
120114
}

0 commit comments

Comments
 (0)