From: Benno Lossin Date: Fri, 5 Sep 2025 14:05:31 +0000 (+0200) Subject: rust: pin-init: add code blocks to `[try_][pin_]init!` macros X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=1fa516794fdd27b96cee77f8b12ac916b8b6a9a7;p=users%2Fhch%2Fmisc.git rust: pin-init: add code blocks to `[try_][pin_]init!` macros 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 Reviewed-by: Gary Guo Reviewed-by: Alice Ryhl Tested-by: Danilo Krummrich Reviewed-by: Danilo Krummrich Signed-off-by: Benno Lossin --- diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index 2d0d9fd12524..dd553212836e 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -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`] /// pointer named `this` inside of the initializer. /// - Using struct update syntax one can place `..Zeroable::init_zeroed()` at the very end of the diff --git a/rust/pin-init/src/macros.rs b/rust/pin-init/src/macros.rs index 668dcee9b7af..c3462080b7b6 100644 --- a/rust/pin-init/src/macros.rs +++ b/rust/pin-init/src/macros.rs @@ -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),