Messages in this thread | | | Date | Sat, 24 Jun 2023 15:17:10 +0000 | From | Björn Roy Baron <> | Subject | Re: [PATCH 6/7] rust: init: Add functions to create array initializers |
| |
On Saturday, June 24th, 2023 at 11:25, Benno Lossin <benno.lossin@proton.me> wrote:
> Add two functions `pin_init_array_from_fn` and `init_array_from_fn` that > take a function that generates initializers for `T` from usize, the added > functions then return an initializer for `[T; N]` where every element is > initialized by an element returned from the generator function. > > Suggested-by: Asahi Lina <lina@asahilina.net> > Signed-off-by: Benno Lossin <benno.lossin@proton.me>
Reviewed-by: Björn Roy Baron <bjorn3_gh@protonmail.com>
> --- > rust/kernel/init.rs | 90 +++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 90 insertions(+) > > diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs > index 44bc3e77419a..c9ea4bf71987 100644 > --- a/rust/kernel/init.rs > +++ b/rust/kernel/init.rs > @@ -867,6 +867,96 @@ pub fn uninit<T, E>() -> impl Init<MaybeUninit<T>, E> { > unsafe { init_from_closure(|_| Ok(())) } > } > > +/// Initializes an array by initializing each element via the provided initializer. > +/// > +/// # Examples > +/// > +/// ```rust > +/// let array: Box<[usize; 1000_000_000]>= Box::init(init_array_from_fn(|i| i)).unwrap(); > +/// println!("{array:?}"); > +/// ``` > +pub fn init_array_from_fn<I, const N: usize, T, E>( > + mut make_init: impl FnMut(usize) -> I, > +) -> impl Init<[T; N], E> > +where > + I: Init<T, E>, > +{ > + let init = move |slot: *mut [T; N]| { > + let slot = slot.cast::<T>(); > + for i in 0..N { > + let init = make_init(i); > + // SAFETY: since 0 <= `i` < N, it is still in bounds of `[T; N]`. > + let ptr = unsafe { slot.add(i) }; > + // SAFETY: The pointer is derived from `slot` and thus satisfies the `__init` > + // requirements. > + match unsafe { init.__init(ptr) } { > + Ok(()) => {} > + Err(e) => { > + // We now free every element that has been initialized before: > + for j in 0..i { > + let ptr = unsafe { slot.add(j) }; > + // SAFETY: The value was initialized in a previous iteration of the loop > + // and since we return `Err` below, the caller will consider the memory at > + // `slot` as uninitialized. > + unsafe { ptr::drop_in_place(ptr) }; > + } > + return Err(e); > + } > + } > + } > + Ok(()) > + }; > + // SAFETY: The initializer above initializes every element of the array. On failure it drops > + // any initialized elements and returns `Err`. > + unsafe { init_from_closure(init) } > +} > + > +/// Initializes an array by initializing each element via the provided initializer. > +/// > +/// # Examples > +/// > +/// ```rust > +/// let array: Arc<[Mutex<usize>; 1000_000_000]>= > +/// Arc::pin_init(init_array_from_fn(|i| new_mutex!(i))).unwrap(); > +/// println!("{array:?}"); > +/// ``` > +pub fn pin_init_array_from_fn<I, const N: usize, T, E>( > + mut make_init: impl FnMut(usize) -> I, > +) -> impl PinInit<[T; N], E> > +where > + I: PinInit<T, E>, > +{ > + let init = move |slot: *mut [T; N]| { > + let slot = slot.cast::<T>(); > + for i in 0..N { > + let init = make_init(i); > + // SAFETY: since 0 <= `i` < N, it is still in bounds of `[T; N]`. > + let ptr = unsafe { slot.add(i) }; > + // SAFETY: The pointer is derived from `slot` and thus satisfies the `__pinned_init` > + // requirements. > + match unsafe { init.__pinned_init(ptr) } { > + Ok(()) => {} > + Err(e) => { > + // We now have to free every element that has been initialized before, since we > + // have to abide by the drop guarantee. > + for j in 0..i { > + let ptr = unsafe { slot.add(j) }; > + // SAFETY: The value was initialized in a previous iteration of the loop > + // and since we return `Err` below, the caller will consider the memory at > + // `slot` as uninitialized. > + unsafe { ptr::drop_in_place(ptr) }; > + } > + return Err(e); > + } > + } > + } > + Ok(()) > + }; > + // SAFETY: The initializer above initializes every element of the array. On failure it drops > + // any initialized elements and returns `Err`. > + unsafe { pin_init_from_closure(init) } > +} > + > // SAFETY: Every type can be initialized by-value. > unsafe impl<T, E> Init<T, E> for T { > unsafe fn __init(self, slot: *mut T) -> Result<(), E> { > -- > 2.41.0
| |