* [PATCH] add `[pin_]init_scope` to execute code before creating an initializer
@ 2025-10-16 21:05 Benno Lossin
2025-10-17 13:08 ` Alice Ryhl
2025-10-21 17:43 ` Danilo Krummrich
0 siblings, 2 replies; 3+ messages in thread
From: Benno Lossin @ 2025-10-16 21:05 UTC (permalink / raw)
To: Benno Lossin, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Fiona Behrens, Christian Schrefl
Cc: rust-for-linux, linux-kernel
In more complex cases, initializers need to run arbitrary code before
assigning initializers to fields. While this is possible using the
underscore codeblock feature (`_: {}`), values returned by such
functions cannot be used from later field initializers.
The two new functinos `[pin_]init_scope` allow users to first run some
fallible code and then return an initializer which the function turns
into a single initializer. This permits using the same value multiple
times by different fields.
Reviewed-by: Gary Guo <gary@garyguo.net>
Reviewed-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Benno Lossin <lossin@kernel.org>
---
rust/pin-init/src/lib.rs | 87 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 87 insertions(+)
diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs
index dd553212836e..8dc9dd5ac6fd 100644
--- a/rust/pin-init/src/lib.rs
+++ b/rust/pin-init/src/lib.rs
@@ -1392,6 +1392,93 @@ pub fn pin_init_array_from_fn<I, const N: usize, T, E>(
unsafe { pin_init_from_closure(init) }
}
+/// Construct an initializer in a closure and run it.
+///
+/// Returns an initializer that first runs the closure and then the initializer returned by it.
+///
+/// See also [`init_scope`].
+///
+/// # Examples
+///
+/// ```
+/// # use pin_init::*;
+/// # #[pin_data]
+/// # struct Foo { a: u64, b: isize }
+/// # struct Bar { a: u32, b: isize }
+/// # fn lookup_bar() -> Result<Bar, Error> { todo!() }
+/// # struct Error;
+/// fn init_foo() -> impl PinInit<Foo, Error> {
+/// pin_init_scope(|| {
+/// let bar = lookup_bar()?;
+/// Ok(try_pin_init!(Foo { a: bar.a.into(), b: bar.b }? Error))
+/// })
+/// }
+/// ```
+///
+/// This initializer will first execute `lookup_bar()`, match on it, if it returned an error, the
+/// initializer itself will fail with that error. If it returned `Ok`, then it will run the
+/// initializer returned by the [`try_pin_init!`] invocation.
+pub fn pin_init_scope<T, E, F, I>(make_init: F) -> impl PinInit<T, E>
+where
+ F: FnOnce() -> Result<I, E>,
+ I: PinInit<T, E>,
+{
+ // SAFETY:
+ // - If `make_init` returns `Err`, `Err` is returned and `slot` is completely uninitialized,
+ // - If `make_init` returns `Ok`, safety requirement are fulfilled by `init.__pinned_init`.
+ // - The safety requirements of `init.__pinned_init` are fulfilled, since it's being called
+ // from an initializer.
+ unsafe {
+ pin_init_from_closure(move |slot: *mut T| -> Result<(), E> {
+ let init = make_init()?;
+ init.__pinned_init(slot)
+ })
+ }
+}
+
+/// Construct an initializer in a closure and run it.
+///
+/// Returns an initializer that first runs the closure and then the initializer returned by it.
+///
+/// See also [`pin_init_scope`].
+///
+/// # Examples
+///
+/// ```
+/// # use pin_init::*;
+/// # struct Foo { a: u64, b: isize }
+/// # struct Bar { a: u32, b: isize }
+/// # fn lookup_bar() -> Result<Bar, Error> { todo!() }
+/// # struct Error;
+/// fn init_foo() -> impl Init<Foo, Error> {
+/// init_scope(|| {
+/// let bar = lookup_bar()?;
+/// Ok(try_init!(Foo { a: bar.a.into(), b: bar.b }? Error))
+/// })
+/// }
+/// ```
+///
+/// This initializer will first execute `lookup_bar()`, match on it, if it returned an error, the
+/// initializer itself will fail with that error. If it returned `Ok`, then it will run the
+/// initializer returned by the [`try_init!`] invocation.
+pub fn init_scope<T, E, F, I>(make_init: F) -> impl Init<T, E>
+where
+ F: FnOnce() -> Result<I, E>,
+ I: Init<T, E>,
+{
+ // SAFETY:
+ // - If `make_init` returns `Err`, `Err` is returned and `slot` is completely uninitialized,
+ // - If `make_init` returns `Ok`, safety requirement are fulfilled by `init.__init`.
+ // - The safety requirements of `init.__init` are fulfilled, since it's being called from an
+ // initializer.
+ unsafe {
+ init_from_closure(move |slot: *mut T| -> Result<(), E> {
+ let init = make_init()?;
+ init.__init(slot)
+ })
+ }
+}
+
// SAFETY: the `__init` function always returns `Ok(())` and initializes every field of `slot`.
unsafe impl<T> Init<T> for T {
unsafe fn __init(self, slot: *mut T) -> Result<(), Infallible> {
base-commit: 3a8660878839faadb4f1a6dd72c3179c1df56787
--
2.51.0
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [PATCH] add `[pin_]init_scope` to execute code before creating an initializer
2025-10-16 21:05 [PATCH] add `[pin_]init_scope` to execute code before creating an initializer Benno Lossin
@ 2025-10-17 13:08 ` Alice Ryhl
2025-10-21 17:43 ` Danilo Krummrich
1 sibling, 0 replies; 3+ messages in thread
From: Alice Ryhl @ 2025-10-17 13:08 UTC (permalink / raw)
To: Benno Lossin
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Trevor Gross,
Danilo Krummrich, Fiona Behrens, Christian Schrefl,
rust-for-linux, linux-kernel
On Thu, Oct 16, 2025 at 11:05:39PM +0200, Benno Lossin wrote:
> In more complex cases, initializers need to run arbitrary code before
> assigning initializers to fields. While this is possible using the
> underscore codeblock feature (`_: {}`), values returned by such
> functions cannot be used from later field initializers.
>
> The two new functinos `[pin_]init_scope` allow users to first run some
> fallible code and then return an initializer which the function turns
> into a single initializer. This permits using the same value multiple
> times by different fields.
>
> Reviewed-by: Gary Guo <gary@garyguo.net>
> Reviewed-by: Danilo Krummrich <dakr@kernel.org>
> Signed-off-by: Benno Lossin <lossin@kernel.org>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH] add `[pin_]init_scope` to execute code before creating an initializer
2025-10-16 21:05 [PATCH] add `[pin_]init_scope` to execute code before creating an initializer Benno Lossin
2025-10-17 13:08 ` Alice Ryhl
@ 2025-10-21 17:43 ` Danilo Krummrich
1 sibling, 0 replies; 3+ messages in thread
From: Danilo Krummrich @ 2025-10-21 17:43 UTC (permalink / raw)
To: Benno Lossin
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Fiona Behrens, Christian Schrefl, rust-for-linux, linux-kernel
On Thu Oct 16, 2025 at 11:05 PM CEST, Benno Lossin wrote:
> In more complex cases, initializers need to run arbitrary code before
> assigning initializers to fields. While this is possible using the
> underscore codeblock feature (`_: {}`), values returned by such
> functions cannot be used from later field initializers.
>
> The two new functinos `[pin_]init_scope` allow users to first run some
> fallible code and then return an initializer which the function turns
> into a single initializer. This permits using the same value multiple
> times by different fields.
>
> Reviewed-by: Gary Guo <gary@garyguo.net>
> Reviewed-by: Danilo Krummrich <dakr@kernel.org>
> Signed-off-by: Benno Lossin <lossin@kernel.org>
Applied to driver-core-testing, thanks!
[ Fix typo in commit message: s/functinos/functions/. - Danilo ]
Benno, thanks a lot for providing this patch as prerequisite for [1]; your quick
support with pin-init whenever something comes up is much appreciated!
[1] https://lore.kernel.org/all/20251016125544.15559-1-dakr@kernel.org/
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2025-10-21 17:43 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-16 21:05 [PATCH] add `[pin_]init_scope` to execute code before creating an initializer Benno Lossin
2025-10-17 13:08 ` Alice Ryhl
2025-10-21 17:43 ` Danilo Krummrich
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).