rust: sync: arc: Add UniqueArc<MaybeUninit<T>::assume_init()
authorAsahi Lina <lina@asahilina.net>
Mon, 3 Apr 2023 10:01:12 +0000 (19:01 +0900)
committerMiguel Ojeda <ojeda@kernel.org>
Wed, 12 Apr 2023 16:41:04 +0000 (18:41 +0200)
We can already create `UniqueArc<MaybeUninit<T>>` instances with
`UniqueArc::try_new_uninit()` and write to them with `write()`. Add
the missing unsafe `assume_init()` function to promote it to
`UniqueArc<T>`, so users can do piece-wise initialization of the
contents instead of doing it all at once as long as they keep the
invariants (the same requirements as `MaybeUninit::assume_init()`).

This mirrors the std `Arc::assume_init()` function. In the kernel,
since we have `UniqueArc`, arguably this only belongs there since most
use cases will initialize it immediately after creating it, before
demoting it to `Arc` to share it.

[ Miguel: The "Rust pin-init API for pinned initialization of structs"
  patch series [1] from Benno Lossin contains a very similar patch:

    rust: sync: add `assume_init` to `UniqueArc`

    Adds the `assume_init` function to `UniqueArc<MaybeUninit<T>>` that
    unsafely assumes the value to be initialized and yields a value of type
    `UniqueArc<T>`. This function is used when manually initializing the
    pointee of an `UniqueArc`.

  To make that patch a noop and thus drop it, I adjusted the `SAFETY`
  comment here to be the same as in the current latest version of
  that series (v7).

  I have also brought the `Reviewed-by`s there into here, and reworded
  the `Co-authored-by` into `Co-developed-by`. ]

Link: https://lore.kernel.org/r/20230408122429.1103522-5-y86-dev@protonmail.com
Co-developed-by: Benno Lossin <benno.lossin@proton.me>
Signed-off-by: Benno Lossin <benno.lossin@proton.me>
Signed-off-by: Asahi Lina <lina@asahilina.net>
Reviewed-by: Gary Guo <gary@garyguo.net>
Reviewed-by: Wedson Almeida Filho <walmeida@microsoft.com>
Reviewed-by: Andreas Hindborg <a.hindborg@samsung.com>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Link: https://lore.kernel.org/r/20230224-rust-arc-v2-2-5c97a865b276@asahilina.net
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
rust/kernel/sync/arc.rs

index 4ab9b28..8ce6d6b 100644 (file)
@@ -492,6 +492,17 @@ impl<T> UniqueArc<MaybeUninit<T>> {
     /// Converts a `UniqueArc<MaybeUninit<T>>` into a `UniqueArc<T>` by writing a value into it.
     pub fn write(mut self, value: T) -> UniqueArc<T> {
         self.deref_mut().write(value);
+        // SAFETY: We just wrote the value to be initialized.
+        unsafe { self.assume_init() }
+    }
+
+    /// Unsafely assume that `self` is initialized.
+    ///
+    /// # Safety
+    ///
+    /// The caller guarantees that the value behind this pointer has been initialized. It is
+    /// *immediate* UB to call this when the value is not initialized.
+    pub unsafe fn assume_init(self) -> UniqueArc<T> {
         let inner = ManuallyDrop::new(self).inner.ptr;
         UniqueArc {
             // SAFETY: The new `Arc` is taking over `ptr` from `self.inner` (which won't be