// SPDX-License-Identifier: Apache-2.0 OR MIT //! API to safely and fallibly initialize pinned `struct`s using in-place constructors. //! //! It also allows in-place initialization of big `struct`s that would otherwise produce a stack //! overflow. //! //! Most `struct`s from the [`sync`] module need to be pinned, because they contain self-referential //! `struct`s from C. [Pinning][pinning] is Rust's way of ensuring data does not move. //! //! # Overview //! //! To initialize a `struct` with an in-place constructor you will need two things: //! - an in-place constructor, //! - a memory location that can hold your `struct`. //! //! To get an in-place constructor there are generally two options: //! - a custom function/macro returning an in-place constructor provided by someone else, //! - using the unsafe function [`pin_init_from_closure()`] to manually create an initializer. //! //! Aside from pinned initialization, this API also supports in-place construction without pinning, //! the macros/types/functions are generally named like the pinned variants without the `pin` //! prefix. //! //! [`sync`]: kernel::sync //! [pinning]: https://doc.rust-lang.org/std/pin/index.html //! [structurally pinned fields]: //! https://doc.rust-lang.org/std/pin/index.html#pinning-is-structural-for-field //! [`Arc`]: crate::sync::Arc //! [`impl PinInit`]: PinInit //! [`impl PinInit`]: PinInit //! [`impl Init`]: Init //! [`Opaque`]: kernel::types::Opaque //! [`pin_data`]: ::macros::pin_data //! [`UniqueArc`]: kernel::sync::UniqueArc //! [`Box`]: alloc::boxed::Box use core::{convert::Infallible, marker::PhantomData, mem::MaybeUninit}; #[doc(hidden)] pub mod __internal; /// A pin-initializer for the type `T`. /// /// To use this initializer, you will need a suitable memory location that can hold a `T`. This can /// be [`Box`], [`Arc`], [`UniqueArc`]. /// /// Also see the [module description](self). /// /// # Safety /// /// When implementing this type you will need to take great care. Also there are probably very few /// cases where a manual implementation is necessary. Use [`pin_init_from_closure`] where possible. /// /// The [`PinInit::__pinned_init`] function /// - returns `Ok(())` if it initialized every field of `slot`, /// - returns `Err(err)` if it encountered an error and then cleaned `slot`, this means: /// - `slot` can be deallocated without UB occurring, /// - `slot` does not need to be dropped, /// - `slot` is not partially initialized. /// - while constructing the `T` at `slot` it upholds the pinning invariants of `T`. /// /// [`Arc`]: crate::sync::Arc /// [`Arc::pin_init`]: crate::sync::Arc::pin_init /// [`UniqueArc`]: kernel::sync::UniqueArc /// [`Box`]: alloc::boxed::Box #[must_use = "An initializer must be used in order to create its value."] pub unsafe trait PinInit: Sized { /// Initializes `slot`. /// /// # Safety /// /// - `slot` is a valid pointer to uninitialized memory. /// - the caller does not touch `slot` when `Err` is returned, they are only permitted to /// deallocate. /// - `slot` will not move until it is dropped, i.e. it will be pinned. unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E>; } /// An initializer for `T`. /// /// To use this initializer, you will need a suitable memory location that can hold a `T`. This can /// be [`Box`], [`Arc`], [`UniqueArc`]. Because [`PinInit`] is a super trait, you can /// use every function that takes it as well. /// /// Also see the [module description](self). /// /// # Safety /// /// When implementing this type you will need to take great care. Also there are probably very few /// cases where a manual implementation is necessary. Use [`init_from_closure`] where possible. /// /// The [`Init::__init`] function /// - returns `Ok(())` if it initialized every field of `slot`, /// - returns `Err(err)` if it encountered an error and then cleaned `slot`, this means: /// - `slot` can be deallocated without UB occurring, /// - `slot` does not need to be dropped, /// - `slot` is not partially initialized. /// - while constructing the `T` at `slot` it upholds the pinning invariants of `T`. /// /// The `__pinned_init` function from the supertrait [`PinInit`] needs to execute the exact same /// code as `__init`. /// /// Contrary to its supertype [`PinInit`] the caller is allowed to /// move the pointee after initialization. /// /// [`Arc`]: crate::sync::Arc /// [`UniqueArc`]: kernel::sync::UniqueArc /// [`Box`]: alloc::boxed::Box #[must_use = "An initializer must be used in order to create its value."] pub unsafe trait Init: Sized { /// Initializes `slot`. /// /// # Safety /// /// - `slot` is a valid pointer to uninitialized memory. /// - the caller does not touch `slot` when `Err` is returned, they are only permitted to /// deallocate. unsafe fn __init(self, slot: *mut T) -> Result<(), E>; } // SAFETY: Every in-place initializer can also be used as a pin-initializer. unsafe impl PinInit for I where I: Init, { unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { // SAFETY: `__init` meets the same requirements as `__pinned_init`, except that it does not // require `slot` to not move after init. unsafe { self.__init(slot) } } } /// Creates a new [`PinInit`] from the given closure. /// /// # Safety /// /// The closure: /// - returns `Ok(())` if it initialized every field of `slot`, /// - returns `Err(err)` if it encountered an error and then cleaned `slot`, this means: /// - `slot` can be deallocated without UB occurring, /// - `slot` does not need to be dropped, /// - `slot` is not partially initialized. /// - may assume that the `slot` does not move if `T: !Unpin`, /// - while constructing the `T` at `slot` it upholds the pinning invariants of `T`. #[inline] pub const unsafe fn pin_init_from_closure( f: impl FnOnce(*mut T) -> Result<(), E>, ) -> impl PinInit { __internal::InitClosure(f, PhantomData) } /// Creates a new [`Init`] from the given closure. /// /// # Safety /// /// The closure: /// - returns `Ok(())` if it initialized every field of `slot`, /// - returns `Err(err)` if it encountered an error and then cleaned `slot`, this means: /// - `slot` can be deallocated without UB occurring, /// - `slot` does not need to be dropped, /// - `slot` is not partially initialized. /// - the `slot` may move after initialization. /// - while constructing the `T` at `slot` it upholds the pinning invariants of `T`. #[inline] pub const unsafe fn init_from_closure( f: impl FnOnce(*mut T) -> Result<(), E>, ) -> impl Init { __internal::InitClosure(f, PhantomData) } /// An initializer that leaves the memory uninitialized. /// /// The initializer is a no-op. The `slot` memory is not changed. #[inline] pub fn uninit() -> impl Init, E> { // SAFETY: The memory is allowed to be uninitialized. unsafe { init_from_closure(|_| Ok(())) } } // SAFETY: Every type can be initialized by-value. unsafe impl Init for T { unsafe fn __init(self, slot: *mut T) -> Result<(), Infallible> { unsafe { slot.write(self) }; Ok(()) } }