Commit 1fa51679 authored by Benno Lossin's avatar Benno Lossin
Browse files

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: default avatarAlexandre Courbot <acourbot@nvidia.com>
Reviewed-by: default avatarGary Guo <gary@garyguo.net>
Reviewed-by: default avatarAlice Ryhl <aliceryhl@google.com>
Tested-by: default avatarDanilo Krummrich <dakr@kernel.org>
Reviewed-by: default avatarDanilo Krummrich <dakr@kernel.org>
Signed-off-by: default avatarBenno Lossin <lossin@kernel.org>
parent 619db96d
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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
+29 −0
Original line number Diff line number Diff line
@@ -1263,6 +1263,21 @@ fn assert_zeroable<T: $crate::Zeroable>(_: *mut T) {}
        // 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 @@ fn assert_zeroable<T: $crate::Zeroable>(_: *mut T) {}
            );
        }
    };
    (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),