xref: /linux/rust/kernel/alloc/box_ext.rs (revision 570172569238c66a482ec3eb5d766cc9cf255f69)
108d3f549SWedson Almeida Filho // SPDX-License-Identifier: GPL-2.0
208d3f549SWedson Almeida Filho 
308d3f549SWedson Almeida Filho //! Extensions to [`Box`] for fallible allocations.
408d3f549SWedson Almeida Filho 
52c109285SWedson Almeida Filho use super::{AllocError, Flags};
608d3f549SWedson Almeida Filho use alloc::boxed::Box;
701db99b2SBenno Lossin use core::{mem::MaybeUninit, ptr, result::Result};
808d3f549SWedson Almeida Filho 
908d3f549SWedson Almeida Filho /// Extensions to [`Box`].
1008d3f549SWedson Almeida Filho pub trait BoxExt<T>: Sized {
1108d3f549SWedson Almeida Filho     /// Allocates a new box.
1208d3f549SWedson Almeida Filho     ///
1308d3f549SWedson Almeida Filho     /// The allocation may fail, in which case an error is returned.
new(x: T, flags: Flags) -> Result<Self, AllocError>1408d3f549SWedson Almeida Filho     fn new(x: T, flags: Flags) -> Result<Self, AllocError>;
1508d3f549SWedson Almeida Filho 
1608d3f549SWedson Almeida Filho     /// Allocates a new uninitialised box.
1708d3f549SWedson Almeida Filho     ///
1808d3f549SWedson Almeida Filho     /// The allocation may fail, in which case an error is returned.
new_uninit(flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError>1908d3f549SWedson Almeida Filho     fn new_uninit(flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError>;
2001db99b2SBenno Lossin 
2101db99b2SBenno Lossin     /// Drops the contents, but keeps the allocation.
2201db99b2SBenno Lossin     ///
2301db99b2SBenno Lossin     /// # Examples
2401db99b2SBenno Lossin     ///
2501db99b2SBenno Lossin     /// ```
2601db99b2SBenno Lossin     /// use kernel::alloc::{flags, box_ext::BoxExt};
2701db99b2SBenno Lossin     /// let value = Box::new([0; 32], flags::GFP_KERNEL)?;
2801db99b2SBenno Lossin     /// assert_eq!(*value, [0; 32]);
29*ab309b6eSMiguel Ojeda     /// let mut value = Box::drop_contents(value);
3001db99b2SBenno Lossin     /// // Now we can re-use `value`:
31*ab309b6eSMiguel Ojeda     /// value.write([1; 32]);
32*ab309b6eSMiguel Ojeda     /// // SAFETY: We just wrote to it.
33*ab309b6eSMiguel Ojeda     /// let value = unsafe { value.assume_init() };
3401db99b2SBenno Lossin     /// assert_eq!(*value, [1; 32]);
3501db99b2SBenno Lossin     /// # Ok::<(), Error>(())
3601db99b2SBenno Lossin     /// ```
drop_contents(this: Self) -> Box<MaybeUninit<T>>3701db99b2SBenno Lossin     fn drop_contents(this: Self) -> Box<MaybeUninit<T>>;
3808d3f549SWedson Almeida Filho }
3908d3f549SWedson Almeida Filho 
4008d3f549SWedson Almeida Filho impl<T> BoxExt<T> for Box<T> {
new(x: T, flags: Flags) -> Result<Self, AllocError>4108d3f549SWedson Almeida Filho     fn new(x: T, flags: Flags) -> Result<Self, AllocError> {
420903b9e2SJubilee Young         let mut b = <Self as BoxExt<_>>::new_uninit(flags)?;
430903b9e2SJubilee Young         b.write(x);
440903b9e2SJubilee Young         // SAFETY: We just wrote to it.
450903b9e2SJubilee Young         Ok(unsafe { b.assume_init() })
4608d3f549SWedson Almeida Filho     }
4708d3f549SWedson Almeida Filho 
4808d3f549SWedson Almeida Filho     #[cfg(any(test, testlib))]
new_uninit(_flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError>4908d3f549SWedson Almeida Filho     fn new_uninit(_flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError> {
5008d3f549SWedson Almeida Filho         Ok(Box::new_uninit())
5108d3f549SWedson Almeida Filho     }
5208d3f549SWedson Almeida Filho 
5308d3f549SWedson Almeida Filho     #[cfg(not(any(test, testlib)))]
new_uninit(flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError>5408d3f549SWedson Almeida Filho     fn new_uninit(flags: Flags) -> Result<Box<MaybeUninit<T>>, AllocError> {
5508d3f549SWedson Almeida Filho         let ptr = if core::mem::size_of::<MaybeUninit<T>>() == 0 {
5608d3f549SWedson Almeida Filho             core::ptr::NonNull::<_>::dangling().as_ptr()
5708d3f549SWedson Almeida Filho         } else {
5808d3f549SWedson Almeida Filho             let layout = core::alloc::Layout::new::<MaybeUninit<T>>();
5908d3f549SWedson Almeida Filho 
6008d3f549SWedson Almeida Filho             // SAFETY: Memory is being allocated (first arg is null). The only other source of
6108d3f549SWedson Almeida Filho             // safety issues is sleeping on atomic context, which is addressed by klint. Lastly,
6208d3f549SWedson Almeida Filho             // the type is not a SZT (checked above).
6308d3f549SWedson Almeida Filho             let ptr =
6408d3f549SWedson Almeida Filho                 unsafe { super::allocator::krealloc_aligned(core::ptr::null_mut(), layout, flags) };
6508d3f549SWedson Almeida Filho             if ptr.is_null() {
6608d3f549SWedson Almeida Filho                 return Err(AllocError);
6708d3f549SWedson Almeida Filho             }
6808d3f549SWedson Almeida Filho 
6908d3f549SWedson Almeida Filho             ptr.cast::<MaybeUninit<T>>()
7008d3f549SWedson Almeida Filho         };
7108d3f549SWedson Almeida Filho 
7208d3f549SWedson Almeida Filho         // SAFETY: For non-zero-sized types, we allocate above using the global allocator. For
7308d3f549SWedson Almeida Filho         // zero-sized types, we use `NonNull::dangling`.
7408d3f549SWedson Almeida Filho         Ok(unsafe { Box::from_raw(ptr) })
7508d3f549SWedson Almeida Filho     }
7601db99b2SBenno Lossin 
drop_contents(this: Self) -> Box<MaybeUninit<T>>7701db99b2SBenno Lossin     fn drop_contents(this: Self) -> Box<MaybeUninit<T>> {
7801db99b2SBenno Lossin         let ptr = Box::into_raw(this);
7901db99b2SBenno Lossin         // SAFETY: `ptr` is valid, because it came from `Box::into_raw`.
8001db99b2SBenno Lossin         unsafe { ptr::drop_in_place(ptr) };
8101db99b2SBenno Lossin 
8201db99b2SBenno Lossin         // CAST: `MaybeUninit<T>` is a transparent wrapper of `T`.
8301db99b2SBenno Lossin         let ptr = ptr.cast::<MaybeUninit<T>>();
8401db99b2SBenno Lossin 
8501db99b2SBenno Lossin         // SAFETY: `ptr` is valid for writes, because it came from `Box::into_raw` and it is valid for
8601db99b2SBenno Lossin         // reads, since the pointer came from `Box::into_raw` and the type is `MaybeUninit<T>`.
8701db99b2SBenno Lossin         unsafe { Box::from_raw(ptr) }
8801db99b2SBenno Lossin     }
8908d3f549SWedson Almeida Filho }
90