rust: Implement the smart pointer InPlaceInit
for Arc
For pinned and unpinned initialization of structs, a trait named `InPlaceInit` exists for uniform access. `Arc` did not implement `InPlaceInit` yet, although the functions already existed. The main reason for that, was that the trait itself returned a `Pin<Self>`. The `Arc` implementation of the kernel is already implicitly pinned. To enable `Arc` to implement `InPlaceInit` and to have uniform access, for in-place and pinned in-place initialization, an associated type is introduced for `InPlaceInit`. The new implementation of `InPlaceInit` for `Arc` sets `Arc` as the associated type. Older implementations use an explicit `Pin<T>` as the associated type. The implemented methods for `Arc` are mostly moved from a direct implementation on `Arc`. There should be no user impact. The implementation for `ListArc` is omitted, because it is not merged yet. Link: https://github.com/Rust-for-Linux/linux/issues/1079 Signed-off-by: Alex Mantel <alexmantel93@mailbox.org> Reviewed-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Benno Lossin <benno.lossin@proton.me> Link: https://lore.kernel.org/r/20240727042442.682109-1-alexmantel93@mailbox.org [ Removed "Rusts" (Benno). - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
This commit is contained in:
parent
47ac09b91b
commit
08f983a55c
@ -213,6 +213,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
alloc::{box_ext::BoxExt, AllocError, Flags},
|
alloc::{box_ext::BoxExt, AllocError, Flags},
|
||||||
error::{self, Error},
|
error::{self, Error},
|
||||||
|
sync::Arc,
|
||||||
sync::UniqueArc,
|
sync::UniqueArc,
|
||||||
types::{Opaque, ScopeGuard},
|
types::{Opaque, ScopeGuard},
|
||||||
};
|
};
|
||||||
@ -1107,11 +1108,17 @@ unsafe impl<T, E> PinInit<T, E> for T {
|
|||||||
|
|
||||||
/// Smart pointer that can initialize memory in-place.
|
/// Smart pointer that can initialize memory in-place.
|
||||||
pub trait InPlaceInit<T>: Sized {
|
pub trait InPlaceInit<T>: Sized {
|
||||||
|
/// Pinned version of `Self`.
|
||||||
|
///
|
||||||
|
/// If a type already implicitly pins its pointee, `Pin<Self>` is unnecessary. In this case use
|
||||||
|
/// `Self`, otherwise just use `Pin<Self>`.
|
||||||
|
type PinnedSelf;
|
||||||
|
|
||||||
/// Use the given pin-initializer to pin-initialize a `T` inside of a new smart pointer of this
|
/// Use the given pin-initializer to pin-initialize a `T` inside of a new smart pointer of this
|
||||||
/// type.
|
/// type.
|
||||||
///
|
///
|
||||||
/// If `T: !Unpin` it will not be able to move afterwards.
|
/// If `T: !Unpin` it will not be able to move afterwards.
|
||||||
fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Pin<Self>, E>
|
fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Self::PinnedSelf, E>
|
||||||
where
|
where
|
||||||
E: From<AllocError>;
|
E: From<AllocError>;
|
||||||
|
|
||||||
@ -1119,7 +1126,7 @@ pub trait InPlaceInit<T>: Sized {
|
|||||||
/// type.
|
/// type.
|
||||||
///
|
///
|
||||||
/// If `T: !Unpin` it will not be able to move afterwards.
|
/// If `T: !Unpin` it will not be able to move afterwards.
|
||||||
fn pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> error::Result<Pin<Self>>
|
fn pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> error::Result<Self::PinnedSelf>
|
||||||
where
|
where
|
||||||
Error: From<E>,
|
Error: From<E>,
|
||||||
{
|
{
|
||||||
@ -1148,9 +1155,31 @@ pub trait InPlaceInit<T>: Sized {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> InPlaceInit<T> for Box<T> {
|
impl<T> InPlaceInit<T> for Arc<T> {
|
||||||
|
type PinnedSelf = Self;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Pin<Self>, E>
|
fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Self::PinnedSelf, E>
|
||||||
|
where
|
||||||
|
E: From<AllocError>,
|
||||||
|
{
|
||||||
|
UniqueArc::try_pin_init(init, flags).map(|u| u.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
|
||||||
|
where
|
||||||
|
E: From<AllocError>,
|
||||||
|
{
|
||||||
|
UniqueArc::try_init(init, flags).map(|u| u.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> InPlaceInit<T> for Box<T> {
|
||||||
|
type PinnedSelf = Pin<Self>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Self::PinnedSelf, E>
|
||||||
where
|
where
|
||||||
E: From<AllocError>,
|
E: From<AllocError>,
|
||||||
{
|
{
|
||||||
@ -1179,8 +1208,10 @@ impl<T> InPlaceInit<T> for Box<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T> InPlaceInit<T> for UniqueArc<T> {
|
impl<T> InPlaceInit<T> for UniqueArc<T> {
|
||||||
|
type PinnedSelf = Pin<Self>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Pin<Self>, E>
|
fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Self::PinnedSelf, E>
|
||||||
where
|
where
|
||||||
E: From<AllocError>,
|
E: From<AllocError>,
|
||||||
{
|
{
|
||||||
|
@ -12,12 +12,13 @@
|
|||||||
//! 2. It does not support weak references, which allows it to be half the size.
|
//! 2. It does not support weak references, which allows it to be half the size.
|
||||||
//! 3. It saturates the reference count instead of aborting when it goes over a threshold.
|
//! 3. It saturates the reference count instead of aborting when it goes over a threshold.
|
||||||
//! 4. It does not provide a `get_mut` method, so the ref counted object is pinned.
|
//! 4. It does not provide a `get_mut` method, so the ref counted object is pinned.
|
||||||
|
//! 5. The object in [`Arc`] is pinned implicitly.
|
||||||
//!
|
//!
|
||||||
//! [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html
|
//! [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
alloc::{box_ext::BoxExt, AllocError, Flags},
|
alloc::{box_ext::BoxExt, AllocError, Flags},
|
||||||
error::{self, Error},
|
bindings,
|
||||||
init::{self, InPlaceInit, Init, PinInit},
|
init::{self, InPlaceInit, Init, PinInit},
|
||||||
try_init,
|
try_init,
|
||||||
types::{ForeignOwnable, Opaque},
|
types::{ForeignOwnable, Opaque},
|
||||||
@ -209,28 +210,6 @@ impl<T> Arc<T> {
|
|||||||
// `Arc` object.
|
// `Arc` object.
|
||||||
Ok(unsafe { Self::from_inner(Box::leak(inner).into()) })
|
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>, flags: Flags) -> error::Result<Self>
|
|
||||||
where
|
|
||||||
Error: From<E>,
|
|
||||||
{
|
|
||||||
UniqueArc::pin_init(init, flags).map(|u| u.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Use the given initializer to in-place initialize a `T`.
|
|
||||||
///
|
|
||||||
/// This is equivalent to [`Arc<T>::pin_init`], since an [`Arc`] is always pinned.
|
|
||||||
#[inline]
|
|
||||||
pub fn init<E>(init: impl Init<T, E>, flags: Flags) -> error::Result<Self>
|
|
||||||
where
|
|
||||||
Error: From<E>,
|
|
||||||
{
|
|
||||||
UniqueArc::init(init, flags).map(|u| u.into())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ?Sized> Arc<T> {
|
impl<T: ?Sized> Arc<T> {
|
||||||
|
Loading…
Reference in New Issue
Block a user