Skip to content

Commit

Permalink
rust: kernel: add drop_contents to BoxExt
Browse files Browse the repository at this point in the history
Sometimes (see [1]) it is necessary to drop the value inside of a
`Box<T>`, but retain the allocation. For example to reuse the allocation
in the future.
Introduce a new function `drop_contents` that turns a `Box<T>` into
`Box<MaybeUninit<T>>` by dropping the value.

Signed-off-by: Benno Lossin <[email protected]>
Link: https://lore.kernel.org/rust-for-linux/[email protected]/ [1]
  • Loading branch information
Benno Lossin authored and matthewtgilbride committed Aug 19, 2024
1 parent e26fa54 commit 68ad5e3
Showing 1 changed file with 25 additions and 1 deletion.
26 changes: 25 additions & 1 deletion rust/kernel/alloc/box_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use super::{AllocError, Flags};
use alloc::boxed::Box;
use core::mem::MaybeUninit;
use core::{mem::MaybeUninit, ptr, result::Result};

/// Extensions to [`Box`].
pub trait BoxExt<T>: Sized {
Expand All @@ -17,6 +17,22 @@ pub trait BoxExt<T>: Sized {
///
/// The allocation may fail, in which case an error is returned.
fn new_uninit(flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError>;

/// Drops the contents, but keeps the allocation.
///
/// # Examples
///
/// ```
/// use kernel::alloc::{flags, box_ext::BoxExt};
/// let value = Box::new([0; 32], flags::GFP_KERNEL)?;
/// assert_eq!(*value, [0; 32]);
/// let value = Box::drop_contents(value);
/// // Now we can re-use `value`:
/// let value = Box::write(value, [1; 32]);
/// assert_eq!(*value, [1; 32]);
/// # Ok::<(), Error>(())
/// ```
fn drop_contents(this: Self) -> Box<MaybeUninit<T>>;
}

impl<T> BoxExt<T> for Box<T> {
Expand Down Expand Up @@ -53,4 +69,12 @@ impl<T> BoxExt<T> for Box<T> {
// zero-sized types, we use `NonNull::dangling`.
Ok(unsafe { Box::from_raw(ptr) })
}

fn drop_contents(this: Self) -> Box<MaybeUninit<T>> {
let ptr = Box::into_raw(this);
// SAFETY: `ptr` is valid, because it came from `Box::into_raw`.
unsafe { ptr::drop_in_place(ptr) };
// SAFETY: `ptr` is valid, because it came from `Box::into_raw`.
unsafe { Box::from_raw(ptr.cast()) }
}
}

0 comments on commit 68ad5e3

Please sign in to comment.