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)
