Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

add `[pin_]init_scope` to execute code before creating an initializer

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 functions `[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>
[ Fix typo in commit message: s/functinos/functions/. - Danilo ]
Signed-off-by: Danilo Krummrich <dakr@kernel.org>

authored by

Benno Lossin and committed by
Danilo Krummrich
fc2b38de e6901808

+87
+87
rust/pin-init/src/lib.rs
··· 1392 1392 unsafe { pin_init_from_closure(init) } 1393 1393 } 1394 1394 1395 + /// Construct an initializer in a closure and run it. 1396 + /// 1397 + /// Returns an initializer that first runs the closure and then the initializer returned by it. 1398 + /// 1399 + /// See also [`init_scope`]. 1400 + /// 1401 + /// # Examples 1402 + /// 1403 + /// ``` 1404 + /// # use pin_init::*; 1405 + /// # #[pin_data] 1406 + /// # struct Foo { a: u64, b: isize } 1407 + /// # struct Bar { a: u32, b: isize } 1408 + /// # fn lookup_bar() -> Result<Bar, Error> { todo!() } 1409 + /// # struct Error; 1410 + /// fn init_foo() -> impl PinInit<Foo, Error> { 1411 + /// pin_init_scope(|| { 1412 + /// let bar = lookup_bar()?; 1413 + /// Ok(try_pin_init!(Foo { a: bar.a.into(), b: bar.b }? Error)) 1414 + /// }) 1415 + /// } 1416 + /// ``` 1417 + /// 1418 + /// This initializer will first execute `lookup_bar()`, match on it, if it returned an error, the 1419 + /// initializer itself will fail with that error. If it returned `Ok`, then it will run the 1420 + /// initializer returned by the [`try_pin_init!`] invocation. 1421 + pub fn pin_init_scope<T, E, F, I>(make_init: F) -> impl PinInit<T, E> 1422 + where 1423 + F: FnOnce() -> Result<I, E>, 1424 + I: PinInit<T, E>, 1425 + { 1426 + // SAFETY: 1427 + // - If `make_init` returns `Err`, `Err` is returned and `slot` is completely uninitialized, 1428 + // - If `make_init` returns `Ok`, safety requirement are fulfilled by `init.__pinned_init`. 1429 + // - The safety requirements of `init.__pinned_init` are fulfilled, since it's being called 1430 + // from an initializer. 1431 + unsafe { 1432 + pin_init_from_closure(move |slot: *mut T| -> Result<(), E> { 1433 + let init = make_init()?; 1434 + init.__pinned_init(slot) 1435 + }) 1436 + } 1437 + } 1438 + 1439 + /// Construct an initializer in a closure and run it. 1440 + /// 1441 + /// Returns an initializer that first runs the closure and then the initializer returned by it. 1442 + /// 1443 + /// See also [`pin_init_scope`]. 1444 + /// 1445 + /// # Examples 1446 + /// 1447 + /// ``` 1448 + /// # use pin_init::*; 1449 + /// # struct Foo { a: u64, b: isize } 1450 + /// # struct Bar { a: u32, b: isize } 1451 + /// # fn lookup_bar() -> Result<Bar, Error> { todo!() } 1452 + /// # struct Error; 1453 + /// fn init_foo() -> impl Init<Foo, Error> { 1454 + /// init_scope(|| { 1455 + /// let bar = lookup_bar()?; 1456 + /// Ok(try_init!(Foo { a: bar.a.into(), b: bar.b }? Error)) 1457 + /// }) 1458 + /// } 1459 + /// ``` 1460 + /// 1461 + /// This initializer will first execute `lookup_bar()`, match on it, if it returned an error, the 1462 + /// initializer itself will fail with that error. If it returned `Ok`, then it will run the 1463 + /// initializer returned by the [`try_init!`] invocation. 1464 + pub fn init_scope<T, E, F, I>(make_init: F) -> impl Init<T, E> 1465 + where 1466 + F: FnOnce() -> Result<I, E>, 1467 + I: Init<T, E>, 1468 + { 1469 + // SAFETY: 1470 + // - If `make_init` returns `Err`, `Err` is returned and `slot` is completely uninitialized, 1471 + // - If `make_init` returns `Ok`, safety requirement are fulfilled by `init.__init`. 1472 + // - The safety requirements of `init.__init` are fulfilled, since it's being called from an 1473 + // initializer. 1474 + unsafe { 1475 + init_from_closure(move |slot: *mut T| -> Result<(), E> { 1476 + let init = make_init()?; 1477 + init.__init(slot) 1478 + }) 1479 + } 1480 + } 1481 + 1395 1482 // SAFETY: the `__init` function always returns `Ok(())` and initializes every field of `slot`. 1396 1483 unsafe impl<T> Init<T> for T { 1397 1484 unsafe fn __init(self, slot: *mut T) -> Result<(), Infallible> {