On Tue Oct 6, 2026 at 2:52 PM JST, Alexandre Courbot wrote:
> 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`?
SGTM, added the failure case in the example as well.
>
>> + /// }
>> + ///
>> + /// 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)
The file appears split on the convention here (get_unchecked_mut vs
get_mut_ptr + arithmetic + cast), but absolutely do not mind changing
this one here.