Mailing List Archive

[PATCH v3 06/13] rust: init/sync: add `InPlaceInit` trait to pin-initialize smart pointers
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()) })
+ }
+
+ #[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() })
+ }
+}
+
+impl<T> InPlaceInit<T> for UniqueArc<T> {
+ #[inline]
+ fn pin_init<E>(init: impl PinInit<T, E>) -> error::Result<Pin<Self>>
+ where
+ Error: From<E>,
+ {
+ let mut this = UniqueArc::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()) })
+ }
+
+ #[inline]
+ fn init<E>(init: impl Init<T, E>) -> error::Result<Self>
+ where
+ Error: From<E>,
+ {
+ let mut this = UniqueArc::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() })
+ }
+}
diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs
index 16ec174637b2..77a3833cc265 100644
--- a/rust/kernel/sync/arc.rs
+++ b/rust/kernel/sync/arc.rs
@@ -17,7 +17,8 @@

use crate::{
bindings,
- error::Result,
+ error::{Error, Result},
+ init::{InPlaceInit, Init, PinInit},
types::{ForeignOwnable, Opaque},
};
use alloc::boxed::Box;
@@ -163,6 +164,28 @@ impl<T> Arc<T> {
// `Arc` object.
Ok(unsafe { Self::from_inner(Box::leak(inner).into()) })
}
+
+ /// Use the given initializer to in-place initialize a `T`.
+ ///
+ /// If `T: !Unpin` it will not be able to move afterwards.
+ #[inline]
+ pub fn pin_init<E>(init: impl PinInit<T, E>) -> Result<Self>
+ where
+ Error: From<E>,
+ {
+ UniqueArc::pin_init(init).map(|u| u.into())
+ }
+
+ /// Use the given initializer to in-place initialize a `T`.
+ ///
+ /// This is equivalent to [`pin_init`], since an [`Arc`] is always pinned.
+ #[inline]
+ pub fn init<E>(init: impl Init<T, E>) -> Result<Self>
+ where
+ Error: From<E>,
+ {
+ UniqueArc::init(init).map(|u| u.into())
+ }
}

impl<T: ?Sized> Arc<T> {
--
2.39.2
Re: [PATCH v3 06/13] rust: init/sync: add `InPlaceInit` trait to pin-initialize smart pointers [ In reply to ]
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() })
> + }
> +}
Re: [PATCH v3 06/13] rust: init/sync: add `InPlaceInit` trait to pin-initialize smart pointers [ In reply to ]
y86-dev@protonmail.com writes:

> 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>
> ---

Reviewed-by: Andreas Hindborg <a.hindborg@samsung.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()) })
> + }
> +
> + #[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() })
> + }
> +}
> +
> +impl<T> InPlaceInit<T> for UniqueArc<T> {
> + #[inline]
> + fn pin_init<E>(init: impl PinInit<T, E>) -> error::Result<Pin<Self>>
> + where
> + Error: From<E>,
> + {
> + let mut this = UniqueArc::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()) })
> + }
> +
> + #[inline]
> + fn init<E>(init: impl Init<T, E>) -> error::Result<Self>
> + where
> + Error: From<E>,
> + {
> + let mut this = UniqueArc::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() })
> + }
> +}
> diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs
> index 16ec174637b2..77a3833cc265 100644
> --- a/rust/kernel/sync/arc.rs
> +++ b/rust/kernel/sync/arc.rs
> @@ -17,7 +17,8 @@
>
> use crate::{
> bindings,
> - error::Result,
> + error::{Error, Result},
> + init::{InPlaceInit, Init, PinInit},
> types::{ForeignOwnable, Opaque},
> };
> use alloc::boxed::Box;
> @@ -163,6 +164,28 @@ impl<T> Arc<T> {
> // `Arc` object.
> Ok(unsafe { Self::from_inner(Box::leak(inner).into()) })
> }
> +
> + /// Use the given initializer to in-place initialize a `T`.
> + ///
> + /// If `T: !Unpin` it will not be able to move afterwards.
> + #[inline]
> + pub fn pin_init<E>(init: impl PinInit<T, E>) -> Result<Self>
> + where
> + Error: From<E>,
> + {
> + UniqueArc::pin_init(init).map(|u| u.into())
> + }
> +
> + /// Use the given initializer to in-place initialize a `T`.
> + ///
> + /// This is equivalent to [`pin_init`], since an [`Arc`] is always pinned.
> + #[inline]
> + pub fn init<E>(init: impl Init<T, E>) -> Result<Self>
> + where
> + Error: From<E>,
> + {
> + UniqueArc::init(init).map(|u| u.into())
> + }
> }
>
> impl<T: ?Sized> Arc<T> {
Re: [PATCH v3 06/13] rust: init/sync: add `InPlaceInit` trait to pin-initialize smart pointers [ In reply to ]
On 3/30/23 00:33, 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>
> ---
>
> +/// 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>;
> +}

This definition is potentially rather limiting, because it can only be
used with error types that can be converted into a `kernel::Error`. What
do you think of this alternative?

pub trait InPlaceInit<T>: Sized {
fn pin_init<E>(init: impl PinInit<T, E>) -> Result<Pin<Self>, E>
where
E: From<AllocError>;

fn init<E>(init: impl Init<T, E>) -> Result<Self, E>
where
E: From<AllocError>;
}
Re: [PATCH v3 06/13] rust: init/sync: add `InPlaceInit` trait to pin-initialize smart pointers [ In reply to ]
On 30.03.23 16:37, Alice Ryhl wrote:
> On 3/30/23 00:33, 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>
> > ---
> >
>> +/// 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>;
>> +}
>
> This definition is potentially rather limiting, because it can only be
> used with error types that can be converted into a `kernel::Error`. What
> do you think of this alternative?
>
> pub trait InPlaceInit<T>: Sized {
> fn pin_init<E>(init: impl PinInit<T, E>) -> Result<Pin<Self>, E>
> where
> E: From<AllocError>;
>
> fn init<E>(init: impl Init<T, E>) -> Result<Self, E>
> where
> E: From<AllocError>;
> }

I initially implemented it like this, but it required almost always that
`E` is specified, I will try and see if the situation is any different now,
but I do not think so. In the user-space version of this API (see [1]) I
have four functions, normal variants that return an `AllocError` and `try`
variants that look exactly like what you suggested. In the kernel, we could
make the normal variants as they are now and add the `try` variants as you
described.

[1]: https://docs.rs/pinned-init/0.0.5/pinned_init/trait.InPlaceInit.html

--
Cheers,
Benno
Re: [PATCH v3 06/13] rust: init/sync: add `InPlaceInit` trait to pin-initialize smart pointers [ In reply to ]
On 3/30/23 17:28, Benno Lossin wrote:
> On 30.03.23 16:37, Alice Ryhl wrote:
>> On 3/30/23 00:33, 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>
>>> ---
>>>
>>> +/// 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>;
>>> +}
>>
>> This definition is potentially rather limiting, because it can only be
>> used with error types that can be converted into a `kernel::Error`. What
>> do you think of this alternative?
>>
>> pub trait InPlaceInit<T>: Sized {
>> fn pin_init<E>(init: impl PinInit<T, E>) -> Result<Pin<Self>, E>
>> where
>> E: From<AllocError>;
>>
>> fn init<E>(init: impl Init<T, E>) -> Result<Self, E>
>> where
>> E: From<AllocError>;
>> }
>
> I initially implemented it like this, but it required almost always that
> `E` is specified, I will try and see if the situation is any different now,
> but I do not think so. In the user-space version of this API (see [1]) I
> have four functions, normal variants that return an `AllocError` and `try`
> variants that look exactly like what you suggested. In the kernel, we could
> make the normal variants as they are now and add the `try` variants as you
> described.
>
> [1]: https://docs.rs/pinned-init/0.0.5/pinned_init/trait.InPlaceInit.html
>
> --
> Cheers,
> Benno

Ok, if my alternative causes type inference problems, then let us keep
the version you proposed here. We can add more variants later. (Or if
you want to add more now, that's also fine.)

Reviewed-by: Alice Ryhl <aliceryhl@google.com>