]> www.infradead.org Git - users/hch/misc.git/commitdiff
rust: pin-init: add code blocks to `[try_][pin_]init!` macros
authorBenno Lossin <lossin@kernel.org>
Fri, 5 Sep 2025 14:05:31 +0000 (16:05 +0200)
committerBenno Lossin <lossin@kernel.org>
Thu, 11 Sep 2025 21:26:44 +0000 (23:26 +0200)
Allow writing `_: { /* any number of statements */ }` in initializers to
run arbitrary code during initialization.

    try_init!(MyStruct {
        _: {
            if check_something() {
                return Err(MyError);
            }
        },
        foo: Foo::new(val),
        _: {
            println!("successfully initialized `MyStruct`");
        },
    })

Tested-by: Alexandre Courbot <acourbot@nvidia.com>
Reviewed-by: Gary Guo <gary@garyguo.net>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Tested-by: Danilo Krummrich <dakr@kernel.org>
Reviewed-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Benno Lossin <lossin@kernel.org>
rust/pin-init/src/lib.rs
rust/pin-init/src/macros.rs

index 2d0d9fd125245dc20a1ca6539122a84559ba5b2a..dd553212836e0d26b61310ae28060114bf0a0673 100644 (file)
@@ -740,6 +740,8 @@ macro_rules! stack_try_pin_init {
 /// As already mentioned in the examples above, inside of `pin_init!` a `struct` initializer with
 /// the following modifications is expected:
 /// - Fields that you want to initialize in-place have to use `<-` instead of `:`.
+/// - You can use `_: { /* run any user-code here */ },` anywhere where you can place fields in
+///   order to run arbitrary code.
 /// - In front of the initializer you can write `&this in` to have access to a [`NonNull<Self>`]
 ///   pointer named `this` inside of the initializer.
 /// - Using struct update syntax one can place `..Zeroable::init_zeroed()` at the very end of the
index 668dcee9b7afeea145d77b56578f4b4fc70ceb3b..c3462080b7b6f7beea72bb013d0545b0411f3374 100644 (file)
@@ -1263,6 +1263,21 @@ macro_rules! __init_internal {
         // have been initialized. Therefore we can now dismiss the guards by forgetting them.
         $(::core::mem::forget($guards);)*
     };
+    (init_slot($($use_data:ident)?):
+        @data($data:ident),
+        @slot($slot:ident),
+        @guards($($guards:ident,)*),
+        // arbitrary code block
+        @munch_fields(_: { $($code:tt)* }, $($rest:tt)*),
+    ) => {
+        { $($code)* }
+        $crate::__init_internal!(init_slot($($use_data)?):
+            @data($data),
+            @slot($slot),
+            @guards($($guards,)*),
+            @munch_fields($($rest)*),
+        );
+    };
     (init_slot($use_data:ident): // `use_data` is present, so we use the `data` to init fields.
         @data($data:ident),
         @slot($slot:ident),
@@ -1358,6 +1373,20 @@ macro_rules! __init_internal {
             );
         }
     };
+    (make_initializer:
+        @slot($slot:ident),
+        @type_name($t:path),
+        @munch_fields(_: { $($code:tt)* }, $($rest:tt)*),
+        @acc($($acc:tt)*),
+    ) => {
+        // code blocks are ignored for the initializer check
+        $crate::__init_internal!(make_initializer:
+            @slot($slot),
+            @type_name($t),
+            @munch_fields($($rest)*),
+            @acc($($acc)*),
+        );
+    };
     (make_initializer:
         @slot($slot:ident),
         @type_name($t:path),