On Mon Sep 28, 2026 at 5:42 PM JST, Eliot Courtney wrote:
> Add `Vec::try_push_init` for fallible initializers (`impl Init<T, E>`)
> and a new sum error type `PushInitError<I, E>` that it returns. If
> allocation fails, it hands back the original initializer. A From impl

nit: missing `` around "From".

> for `Error` lets callers decay the `PushInitError<I, E>` to a regular
> Error if they want.
>
> Signed-off-by: Eliot Courtney <[email protected]>
> ---
>  rust/kernel/alloc/kvec.rs        | 55 
> ++++++++++++++++++++++++++++++++++++++--
>  rust/kernel/alloc/kvec/errors.rs | 30 ++++++++++++++++++++++
>  2 files changed, 83 insertions(+), 2 deletions(-)
>
> diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs
> index c7546b9da4fa..a2b72a7779d9 100644
> --- a/rust/kernel/alloc/kvec.rs
> +++ b/rust/kernel/alloc/kvec.rs
> @@ -52,10 +52,18 @@
>      }, //
>  };
>  
> -use pin_init::Zeroable;
> +use pin_init::{
> +    Init,
> +    Zeroable, //
> +};
>  
>  mod errors;
> -pub use self::errors::{InsertError, PushError, RemoveError};
> +pub use self::errors::{
> +    InsertError,
> +    PushError,
> +    PushInitError,
> +    RemoveError, //
> +};
>  
>  /// Create a [`KVec`] containing the arguments.
>  ///
> @@ -359,6 +367,49 @@ pub fn push(&mut self, v: T, flags: Flags) -> Result<(), 
> AllocError> {
>          Ok(())
>      }
>  
> +    /// Appends an element to the back of the [`Vec`] instance by 
> initializing it in place.
> +    ///
> +    /// Unlike [`Vec::push`], the initializer may be fallible. If the 
> allocation fails, the
> +    /// original initializer `init` is handed back in 
> [`PushInitError::AllocError`]. If the
> +    /// initializer itself fails, its error is returned in 
> [`PushInitError::InitError`].
> +    ///
> +    /// # Examples
> +    ///
> +    /// ```
> +    /// struct Element {
> +    ///     buf: KVec<u8>,

It becomes a tad confusing when the element of a `KVec` is itself a
`KVec`... Can we just use primitive types inside `Element`?

> +    /// }
> +    ///
> +    /// impl Element {
> +    ///     fn new() -> impl Init<Self, Error> {
> +    ///         try_init!(Element {
> +    ///             buf: KVec::with_capacity(16, GFP_KERNEL)?,
> +    ///         }? Error)
> +    ///     }
> +    /// }
> +    ///
> +    /// let mut v: KVec<Element> = KVec::new();
> +    /// v.try_push_init(Element::new(), GFP_KERNEL)?;
> +    /// assert!(v[0].buf.is_empty());
> +    /// # Ok::<(), Error>(())
> +    /// ```
> +    pub fn try_push_init<I, E>(&mut self, init: I, flags: Flags) -> 
> Result<(), PushInitError<I, E>>
> +    where
> +        I: Init<T, E>,
> +    {
> +        if self.reserve(1, flags).is_err() {
> +            return Err(PushInitError::AllocError(init));
> +        }
> +        // SAFETY: The call to `reserve` was successful, so there is at 
> least one spare slot.
> +        unsafe { 
> init.__init(self.spare_capacity_mut().as_mut_ptr().cast::<T>()) }

I guess it comes down to the same but I'd feel safer if we could
explicitly index the first element using `get_unchecked_mut(0)`:

    unsafe { 
init.__init(self.spare_capacity_mut().get_unchecked_mut(0).as_mut_ptr()) }

(removing a cast is also nice I guess)

Reply via email to