Messages in this thread Patch in this message | | | Date | Thu, 30 Mar 2023 11:58:08 +0100 | From | Gary Guo <> | Subject | Re: [PATCH v3 06/13] rust: init/sync: add `InPlaceInit` trait to pin-initialize smart pointers |
| |
On Wed, 29 Mar 2023 22:33:18 +0000 y86-dev@protonmail.com wrote:
> From: Benno Lossin <y86-dev@protonmail.com> > > The `InPlaceInit` trait that provides two functions, for initializing > using `PinInit<T, E>` and `Init<T>`. It is implemented by `Arc<T>`, > `UniqueArc<T>` and `Box<T>`. > > Signed-off-by: Benno Lossin <y86-dev@protonmail.com> > --- > rust/kernel/init.rs | 97 +++++++++++++++++++++++++++++++++++------ > rust/kernel/sync/arc.rs | 25 ++++++++++- > 2 files changed, 108 insertions(+), 14 deletions(-) > > diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs > index 85e8d5f41b60..3d89c7e3bdb5 100644 > --- a/rust/kernel/init.rs > +++ b/rust/kernel/init.rs > @@ -114,10 +114,13 @@ > //! [`impl Init<T, E>`]: Init > //! [`Opaque`]: kernel::types::Opaque > //! [`pin_data`]: ::macros::pin_data > -//! [`UniqueArc<T>`]: kernel::sync::UniqueArc > > +use crate::{ > + error::{self, Error}, > + sync::UniqueArc, > +}; > use alloc::boxed::Box; > -use core::{cell::Cell, convert::Infallible, marker::PhantomData, mem::MaybeUninit, ptr}; > +use core::{cell::Cell, convert::Infallible, marker::PhantomData, mem::MaybeUninit, pin::Pin, ptr}; > > #[doc(hidden)] > pub mod __internal; > @@ -309,7 +312,6 @@ pub mod macros; > /// > /// [`try_pin_init!`]: kernel::try_pin_init > /// [`NonNull<Self>`]: core::ptr::NonNull > -/// [`Error`]: kernel::error::Error > // For a detailed example of how this macro works, see the module documentation of the hidden > // module `__internal` inside of `init/__internal.rs`. > #[macro_export] > @@ -366,8 +368,6 @@ macro_rules! pin_init { > /// } > /// } > /// ``` > -/// > -/// [`Error`]: kernel::error::Error > // For a detailed example of how this macro works, see the module documentation of the hidden > // module `__internal` inside of `init/__internal.rs`. > #[macro_export] > @@ -589,8 +589,6 @@ macro_rules! try_pin_init { > /// > /// This initializer is for initializing data in-place that might later be moved. If you want to > /// pin-initialize, use [`pin_init!`]. > -/// > -/// [`Error`]: kernel::error::Error > // For a detailed example of how this macro works, see the module documentation of the hidden > // module `__internal` inside of `init/__internal.rs`. > #[macro_export] > @@ -641,8 +639,6 @@ macro_rules! init { > /// } > /// } > /// ``` > -/// > -/// [`Error`]: kernel::error::Error > // For a detailed example of how this macro works, see the module documentation of the hidden > // module `__internal` inside of `init/__internal.rs`. > #[macro_export] > @@ -848,7 +844,8 @@ macro_rules! try_init { > /// A pinned initializer for `T`. > /// > /// To use this initializer, you will need a suitable memory location that can hold a `T`. This can > -/// be [`Box<T>`], [`Arc<T>`], [`UniqueArc<T>`]. > +/// be [`Box<T>`], [`Arc<T>`], [`UniqueArc<T>`]. Use the [`InPlaceInit::pin_init`] function of a > +/// smart pointer like [`Arc<T>`] on this. > /// > /// Also see the [module description](self). > /// > @@ -867,7 +864,6 @@ macro_rules! try_init { > /// > /// [`Arc<T>`]: crate::sync::Arc > /// [`Arc::pin_init`]: crate::sync::Arc::pin_init > -/// [`UniqueArc<T>`]: kernel::sync::UniqueArc > #[must_use = "An initializer must be used in order to create its value."] > pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized { > /// Initializes `slot`. > @@ -884,7 +880,8 @@ pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized { > /// An initializer for `T`. > /// > /// To use this initializer, you will need a suitable memory location that can hold a `T`. This can > -/// be [`Box<T>`], [`Arc<T>`], [`UniqueArc<T>`]. Because [`PinInit<T, E>`] is a super trait, you can > +/// be [`Box<T>`], [`Arc<T>`], [`UniqueArc<T>`]. Use the [`InPlaceInit::init`] function of a smart > +/// pointer like [`Arc<T>`] on this. Because [`PinInit<T, E>`] is a super trait, you can > /// use every function that takes it as well. > /// > /// Also see the [module description](self). > @@ -909,7 +906,6 @@ pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized { > /// move the pointee after initialization. > /// > /// [`Arc<T>`]: crate::sync::Arc > -/// [`UniqueArc<T>`]: kernel::sync::UniqueArc > #[must_use = "An initializer must be used in order to create its value."] > pub unsafe trait Init<T: ?Sized, E = Infallible>: PinInit<T, E> { > /// Initializes `slot`. > @@ -1014,3 +1010,78 @@ unsafe impl<T> Init<T> for T { > Ok(()) > } > } > + > +/// Smart pointer that can initialize memory in-place. > +pub trait InPlaceInit<T>: Sized { > + /// Use the given initializer to in-place initialize a `T`. > + /// > + /// If `T: !Unpin` it will not be able to move afterwards. > + fn pin_init<E>(init: impl PinInit<T, E>) -> error::Result<Pin<Self>> > + where > + Error: From<E>; > + > + /// Use the given initializer to in-place initialize a `T`. > + fn init<E>(init: impl Init<T, E>) -> error::Result<Self> > + where > + Error: From<E>; > +} > + > +impl<T> InPlaceInit<T> for Box<T> { > + #[inline] > + fn pin_init<E>(init: impl PinInit<T, E>) -> error::Result<Pin<Self>> > + where > + Error: From<E>, > + { > + let mut this = Box::try_new_uninit()?; > + let slot = this.as_mut_ptr(); > + // SAFETY: When init errors/panics, slot will get deallocated but not dropped, > + // slot is valid and will not be moved because of the `Pin::new_unchecked` > + unsafe { init.__pinned_init(slot)? }; > + // SAFETY: All fields have been initialized. > + Ok(unsafe { Pin::new_unchecked(this.assume_init()) })
This can be either `Box::into_pin` or just `into()`.
> + } > + > + #[inline] > + fn init<E>(init: impl Init<T, E>) -> error::Result<Self> > + where > + Error: From<E>, > + { > + let mut this = Box::try_new_uninit()?; > + let slot = this.as_mut_ptr(); > + // SAFETY: When init errors/panics, slot will get deallocated but not dropped, > + // slot is valid > + unsafe { init.__init(slot)? }; > + // SAFETY: All fields have been initialized. > + Ok(unsafe { this.assume_init() }) > + } > +}
| |