diff options
Diffstat (limited to 'rust/pin-init')
| -rw-r--r-- | rust/pin-init/README.md | 2 | ||||
| -rw-r--r-- | rust/pin-init/src/lib.rs | 87 | ||||
| -rw-r--r-- | rust/pin-init/src/macros.rs | 2 |
3 files changed, 90 insertions, 1 deletions
diff --git a/rust/pin-init/README.md b/rust/pin-init/README.md index 723e275445d4..74bbb4e0a2f7 100644 --- a/rust/pin-init/README.md +++ b/rust/pin-init/README.md @@ -9,7 +9,7 @@ > [!NOTE] > > This crate was originally named [`pinned-init`], but the migration to -> `pin-init` is not yet complete. The `legcay` branch contains the current +> `pin-init` is not yet complete. The `legacy` branch contains the current > version of the `pinned-init` crate & the `main` branch already incorporates > the rename to `pin-init`. > 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 @@ where 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> { diff --git a/rust/pin-init/src/macros.rs b/rust/pin-init/src/macros.rs index d6acf2cd291e..682c61a587a0 100644 --- a/rust/pin-init/src/macros.rs +++ b/rust/pin-init/src/macros.rs @@ -506,6 +506,8 @@ pub use ::paste::paste; /// Creates a `unsafe impl<...> PinnedDrop for $type` block. /// /// See [`PinnedDrop`] for more information. +/// +/// [`PinnedDrop`]: crate::PinnedDrop #[doc(hidden)] #[macro_export] macro_rules! __pinned_drop { |
